|
|
|
@ -450,7 +450,7 @@ async fn run_generation_inner(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Phase B: Classify/summarize batch in parallel
|
|
|
|
// Phase B: Classify/summarize batch in parallel
|
|
|
|
check_rate_limit(state, &user_rate_limiter, &provider_name)?;
|
|
|
|
check_rate_limit(state, &user_rate_limiter, &provider_name).await?;
|
|
|
|
|
|
|
|
|
|
|
|
let mut classify_set = tokio::task::JoinSet::new();
|
|
|
|
let mut classify_set = tokio::task::JoinSet::new();
|
|
|
|
for (final_url, source_url, body_text, page_title) in &scraped_articles {
|
|
|
|
for (final_url, source_url, body_text, page_title) in &scraped_articles {
|
|
|
|
@ -554,7 +554,7 @@ async fn run_generation_inner(
|
|
|
|
|
|
|
|
|
|
|
|
if !category_gaps.is_empty() {
|
|
|
|
if !category_gaps.is_empty() {
|
|
|
|
emit_progress(tx, "search", "Recherche d'actualites complementaires...", 70);
|
|
|
|
emit_progress(tx, "search", "Recherche d'actualites complementaires...", 70);
|
|
|
|
check_rate_limit(state, &user_rate_limiter, &provider_name)?;
|
|
|
|
check_rate_limit(state, &user_rate_limiter, &provider_name).await?;
|
|
|
|
|
|
|
|
|
|
|
|
let search_schema = crate::services::llm::schema::build_category_schema(&user_categories, settings.max_items_per_category);
|
|
|
|
let search_schema = crate::services::llm::schema::build_category_schema(&user_categories, settings.max_items_per_category);
|
|
|
|
let current_date = Utc::now().format("%A %d %B %Y").to_string();
|
|
|
|
let current_date = Utc::now().format("%A %d %B %Y").to_string();
|
|
|
|
@ -798,22 +798,46 @@ fn get_user_rate_limiter(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Check rate limits using the user's limiter if provided, otherwise the global limiter.
|
|
|
|
/// Check rate limits using the user's limiter if provided, otherwise the global limiter.
|
|
|
|
fn check_rate_limit(
|
|
|
|
/// Check rate limits, waiting if necessary (up to 60 seconds).
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Instead of failing with an error, this function sleeps until the rate
|
|
|
|
|
|
|
|
/// limit window passes. If still rate limited after 60 seconds, returns an error.
|
|
|
|
|
|
|
|
async fn check_rate_limit(
|
|
|
|
state: &AppState,
|
|
|
|
state: &AppState,
|
|
|
|
user_limiter: &Option<crate::services::rate_limiter::RateLimiter>,
|
|
|
|
user_limiter: &Option<crate::services::rate_limiter::RateLimiter>,
|
|
|
|
provider_name: &str,
|
|
|
|
provider_name: &str,
|
|
|
|
) -> Result<(), AppError> {
|
|
|
|
) -> Result<(), AppError> {
|
|
|
|
|
|
|
|
let max_wait = std::time::Duration::from_secs(60);
|
|
|
|
|
|
|
|
let start = std::time::Instant::now();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loop {
|
|
|
|
let allowed = match user_limiter {
|
|
|
|
let allowed = match user_limiter {
|
|
|
|
Some(limiter) => limiter.check(&format!("user_gen_{}", provider_name)),
|
|
|
|
Some(limiter) => limiter.check(&format!("user_gen_{}", provider_name)),
|
|
|
|
None => state.provider_rate_limiter.check(provider_name),
|
|
|
|
None => state.provider_rate_limiter.check(provider_name),
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if !allowed {
|
|
|
|
if allowed {
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate how long to wait
|
|
|
|
|
|
|
|
let wait_time = match user_limiter {
|
|
|
|
|
|
|
|
Some(limiter) => limiter.time_until_available(&format!("user_gen_{}", provider_name)),
|
|
|
|
|
|
|
|
None => state.provider_rate_limiter.time_until_available(provider_name),
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let wait = wait_time.unwrap_or(std::time::Duration::from_secs(1));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if start.elapsed() + wait > max_wait {
|
|
|
|
return Err(AppError::RateLimited(
|
|
|
|
return Err(AppError::RateLimited(
|
|
|
|
"Limite de requetes atteinte. Veuillez reessayer dans quelques instants.".into(),
|
|
|
|
"Limite de requetes atteinte. Veuillez reessayer dans quelques instants.".into(),
|
|
|
|
));
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tracing::info!(wait_ms = wait.as_millis() as u64, "Rate limited, waiting...");
|
|
|
|
|
|
|
|
tokio::time::sleep(wait).await;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|