diff --git a/backend/src/services/synthesis.rs b/backend/src/services/synthesis.rs index a1d4039..e339964 100644 --- a/backend/src/services/synthesis.rs +++ b/backend/src/services/synthesis.rs @@ -236,7 +236,7 @@ pub async fn run_generation_inner( let mut pending_traces: Vec = Vec::new(); // === INITIALIZATION === - emit_progress(tx, "settings", "Chargement des parametres...", 5); + emit_progress(tx, "sources", "Chargement des parametres...", 5); let settings = db::settings::get_or_create_default(&state.pool, user_id).await?; if settings.article_history_days > 0 { @@ -255,7 +255,7 @@ pub async fn run_generation_inner( emit_progress(tx, "sources", "Chargement des sources...", 10); let sources = db::sources::list_for_user(&state.pool, user_id).await?; - emit_progress(tx, "provider", "Configuration du fournisseur IA...", 12); + emit_progress(tx, "sources", "Configuration du fournisseur IA...", 12); let (provider_name, provider) = if let Some(mock_provider) = provider_override { ("mock".to_string(), mock_provider) } else { @@ -287,7 +287,7 @@ pub async fn run_generation_inner( // === PHASE 1: Personalized Sources === if !sources.is_empty() { - emit_progress(tx, "sources_scrape", "Analyse des sources personnalisees...", 15); + emit_progress(tx, "sources", "Analyse des sources personnalisees...", 15); let last_source = db::article_history::get_last_source_url(&state.pool, user_id).await.unwrap_or(None); let rotated_sources = rotate_sources(sources.clone(), last_source.as_deref()); @@ -302,9 +302,11 @@ pub async fn run_generation_inner( let total_waves = source_chunks.len(); 'wave_loop: for (wave_idx, wave_sources) in source_chunks.iter().enumerate() { - emit_progress(tx, "sources_scrape", - &format!("Extraction des sources (vague {}/{})", wave_idx + 1, total_waves), - 15 + ((wave_idx as u32 * 10) / total_waves.max(1) as u32).min(10) as u8); + let articles_so_far: usize = article_scraped.values().map(|v| v.len()).sum(); + let pct = 5 + ((articles_so_far as u32 * 60) / max_total.max(1) as u32).min(60); + emit_progress(tx, "sources", + &format!("Vague {}/{} : extraction des sources...", wave_idx + 1, total_waves), + pct as u8); // 1a. Extract links from this wave's sources (all in parallel) let mut wave_urls: Vec<(String, String)> = Vec::new(); @@ -407,8 +409,9 @@ pub async fn run_generation_inner( break; } - let pct = 25 + ((processed as u32 * 40) / total_candidates.max(1) as u32).min(40); - emit_progress(tx, "processing", &format!("Articles {}-{}/{}...", processed + 1, processed + batch.len(), total_candidates), pct as u8); + let articles_so_far: usize = article_scraped.values().map(|v| v.len()).sum(); + let pct = 5 + ((articles_so_far as u32 * 60) / max_total.max(1) as u32).min(60); + emit_progress(tx, "sources", &format!("Vague {}/{} : articles {}/{}...", wave_idx + 1, total_waves, processed + 1, total_candidates), pct as u8); // Phase A: Scrape batch in parallel let mut scrape_set = tokio::task::JoinSet::new(); @@ -575,7 +578,7 @@ pub async fn run_generation_inner( if !category_gaps.is_empty() { if settings.use_brave_search { // === BRAVE SEARCH PATH === - emit_progress(tx, "search", "Recherche Brave Search...", 70); + emit_progress(tx, "websearch", "Recherche Brave Search...", 70); let brave_key = resolve_brave_key(state, user_id).await?; let query = format!("{} actualites", settings.theme); @@ -614,7 +617,7 @@ pub async fn run_generation_inner( // Scrape + classify in batches (same as Phase 1) if !brave_urls.is_empty() { - emit_progress(tx, "processing", "Traitement des articles Brave...", 75); + emit_progress(tx, "websearch", "Traitement des articles Brave...", 75); let total_candidates = brave_urls.len(); let batch_size = settings.batch_size.max(1) as usize; let mut processed = 0usize; @@ -630,8 +633,8 @@ pub async fn run_generation_inner( if batch.is_empty() { break; } - let pct = 75 + ((processed as u32 * 15) / total_candidates.max(1) as u32).min(15); - emit_progress(tx, "processing", &format!("Articles Brave {}-{}/{}...", processed + 1, processed + batch.len(), total_candidates), pct as u8); + let pct = 75 + ((processed as u32 * 10) / total_candidates.max(1) as u32).min(10); + emit_progress(tx, "websearch", &format!("Verification des sources {}/{}...", processed + 1, total_candidates), pct as u8); // Scrape batch in parallel let mut scrape_set = tokio::task::JoinSet::new(); @@ -782,7 +785,7 @@ pub async fn run_generation_inner( } } else { // === EXISTING LLM SEARCH PATH === - emit_progress(tx, "search", "Recherche d'actualites complementaires...", 70); + emit_progress(tx, "websearch", "Recherche d'actualites...", 70); 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); @@ -794,7 +797,7 @@ pub async fn run_generation_inner( let llm_duration = llm_start.elapsed().as_millis() as u64; log_llm_call(&state.pool, user_id, job_id, "search", &model_websearch, &sys_prompt, &usr_prompt, &raw_results, llm_duration, None).await; - emit_progress(tx, "parsing", "Analyse des resultats...", 75); + emit_progress(tx, "websearch", "Analyse des resultats...", 75); let parsed = parse_llm_output(&raw_results, &user_categories)?; // Filter and validate Phase 2 articles @@ -827,7 +830,7 @@ pub async fn run_generation_inner( } // Scrape Phase 2 for validation - emit_progress(tx, "scraping", "Verification des sources web...", 80); + emit_progress(tx, "websearch", "Verification des sources...", 80); for (cat_key, item) in phase2_items { let (_body_text, _, final_url, drop_reason) = scrape_single_article(&state.http_client, &item.url, settings.max_age_days as i64).await; diff --git a/frontend/src/i18n/fr.ts b/frontend/src/i18n/fr.ts index acc1090..5ce1a28 100644 --- a/frontend/src/i18n/fr.ts +++ b/frontend/src/i18n/fr.ts @@ -71,9 +71,8 @@ const fr = { 'generate.note': 'Note : La generation peut prendre jusqu\'a 10 minutes.', 'generate.launch': 'Lancer la generation', 'generate.inProgress': 'Generation en cours...', - 'generate.step.search': 'Recherche d\'actualites', - 'generate.step.scraping': 'Verification des sources', - 'generate.step.rewrite': 'Redaction des resumes', + 'generate.step.sources': 'Sources personnalisees', + 'generate.step.websearch': 'Recherche web', 'generate.step.saving': 'Sauvegarde', 'generate.complete': 'Synthese generee avec succes ! Redirection...', 'generate.error': 'Une erreur est survenue lors de la generation.', diff --git a/frontend/src/pages/GenerateSynthesis.tsx b/frontend/src/pages/GenerateSynthesis.tsx index ab235ee..7014815 100644 --- a/frontend/src/pages/GenerateSynthesis.tsx +++ b/frontend/src/pages/GenerateSynthesis.tsx @@ -27,9 +27,8 @@ interface StepInfo { /** Ordered pipeline steps displayed as a checklist during generation. */ const STEPS: StepInfo[] = [ - { key: 'search', label: 'generate.step.search' }, - { key: 'scraping', label: 'generate.step.scraping' }, - { key: 'rewrite', label: 'generate.step.rewrite' }, + { key: 'sources', label: 'generate.step.sources' }, + { key: 'websearch', label: 'generate.step.websearch' }, { key: 'saving', label: 'generate.step.saving' }, ];