perf: use Arc for immutable values in pipeline to reduce cloning

Wrap `model_research` (String), `classify_schema` (Value), and
`classification_categories` (Vec<String>) in Arc before the batch
loops so spawned tasks clone a cheap pointer instead of the full
heap data on every iteration. Also removes the redundant intermediate
`mdl`/`class_sys`/`class_user` bindings in both classify loops.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
master
oabrivard 3 months ago
parent 0aa0541958
commit f37e0b42a0

@ -264,7 +264,9 @@ async fn run_generation_inner(
let mut filled_counts: HashMap<String, usize> = HashMap::new(); let mut filled_counts: HashMap<String, usize> = HashMap::new();
let mut seen_urls: std::collections::HashSet<String> = std::collections::HashSet::new(); let mut seen_urls: std::collections::HashSet<String> = std::collections::HashSet::new();
let max_total = (user_categories.len() + 1) * settings.max_items_per_category as usize; let max_total = (user_categories.len() + 1) * settings.max_items_per_category as usize;
let classify_schema = crate::services::llm::schema::build_article_classify_schema(); let classify_schema = Arc::new(crate::services::llm::schema::build_article_classify_schema());
let model_research = Arc::new(model_research);
let classification_categories = Arc::new(classification_categories);
// === PHASE 1: Personalized Sources === // === PHASE 1: Personalized Sources ===
if !sources.is_empty() { if !sources.is_empty() {
@ -289,7 +291,7 @@ async fn run_generation_inner(
let source_title = source.title.clone(); let source_title = source.title.clone();
let use_llm = settings.use_llm_for_source_links; let use_llm = settings.use_llm_for_source_links;
let provider_clone = std::sync::Arc::clone(&provider); let provider_clone = std::sync::Arc::clone(&provider);
let model = model_research.clone(); let model = Arc::clone(&model_research);
let max_l = max_links; let max_l = max_links;
let pool = state.pool.clone(); let pool = state.pool.clone();
let uid = user_id; let uid = user_id;
@ -334,7 +336,7 @@ async fn run_generation_inner(
let source_title = source.title.clone(); let source_title = source.title.clone();
let use_llm = settings.use_llm_for_source_links; let use_llm = settings.use_llm_for_source_links;
let provider_clone = std::sync::Arc::clone(&provider); let provider_clone = std::sync::Arc::clone(&provider);
let model = model_research.clone(); let model = Arc::clone(&model_research);
let max_l = max_links; let max_l = max_links;
let pool = state.pool.clone(); let pool = state.pool.clone();
let uid = user_id; let uid = user_id;
@ -457,9 +459,9 @@ async fn run_generation_inner(
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 {
let provider_clone = std::sync::Arc::clone(&provider); let provider_clone = std::sync::Arc::clone(&provider);
let model = model_research.clone(); let model = Arc::clone(&model_research);
let schema = classify_schema.clone(); let schema = Arc::clone(&classify_schema);
let cats = classification_categories.clone(); let cats = Arc::clone(&classification_categories);
let body_snippet: String = body_text.chars().take(500).collect(); let body_snippet: String = body_text.chars().take(500).collect();
let title = page_title.clone(); let title = page_title.clone();
let url = final_url.clone(); let url = final_url.clone();
@ -468,20 +470,17 @@ async fn run_generation_inner(
let uid = user_id; let uid = user_id;
let jid = job_id; let jid = job_id;
let (class_sys, class_user) = crate::services::prompts::build_article_classify_prompt(&title, &body_snippet, &cats); let (sys, usr) = crate::services::prompts::build_article_classify_prompt(&title, &body_snippet, &cats);
let sys = class_sys.clone();
let usr = class_user.clone();
let mdl = model.clone();
classify_set.spawn(async move { classify_set.spawn(async move {
let llm_start = std::time::Instant::now(); let llm_start = std::time::Instant::now();
let result = provider_clone.call_llm(&mdl, &sys, &usr, &schema).await; let result = provider_clone.call_llm(&model, &sys, &usr, &schema).await;
let duration = llm_start.elapsed().as_millis() as u64; let duration = llm_start.elapsed().as_millis() as u64;
// Log the LLM call // Log the LLM call
if let Ok(ref resp) = result { if let Ok(ref resp) = result {
let resp_str = serde_json::to_string_pretty(resp).unwrap_or_default(); let resp_str = serde_json::to_string_pretty(resp).unwrap_or_default();
crate::db::llm_call_log::insert(&pool, uid, jid, "classify_summarize", &mdl, &sys, &usr, &resp_str, duration as i32, Some(&url)).await.ok(); crate::db::llm_call_log::insert(&pool, uid, jid, "classify_summarize", &model, &sys, &usr, &resp_str, duration as i32, Some(&url)).await.ok();
} }
(url, su, title, result) (url, su, title, result)
@ -626,9 +625,9 @@ async fn run_generation_inner(
let mut classify_set = tokio::task::JoinSet::new(); let mut classify_set = tokio::task::JoinSet::new();
for (final_url, body_text, page_title) in &scraped_articles { for (final_url, body_text, page_title) in &scraped_articles {
let provider_clone = std::sync::Arc::clone(&provider); let provider_clone = std::sync::Arc::clone(&provider);
let model = model_research.clone(); let model = Arc::clone(&model_research);
let schema = classify_schema.clone(); let schema = Arc::clone(&classify_schema);
let cats = classification_categories.clone(); let cats = Arc::clone(&classification_categories);
let body_snippet: String = body_text.chars().take(500).collect(); let body_snippet: String = body_text.chars().take(500).collect();
let title = page_title.clone(); let title = page_title.clone();
let url = final_url.clone(); let url = final_url.clone();
@ -636,19 +635,16 @@ async fn run_generation_inner(
let uid = user_id; let uid = user_id;
let jid = job_id; let jid = job_id;
let (class_sys, class_user) = crate::services::prompts::build_article_classify_prompt(&title, &body_snippet, &cats); let (sys, usr) = crate::services::prompts::build_article_classify_prompt(&title, &body_snippet, &cats);
let sys = class_sys.clone();
let usr = class_user.clone();
let mdl = model.clone();
classify_set.spawn(async move { classify_set.spawn(async move {
let llm_start = std::time::Instant::now(); let llm_start = std::time::Instant::now();
let result = provider_clone.call_llm(&mdl, &sys, &usr, &schema).await; let result = provider_clone.call_llm(&model, &sys, &usr, &schema).await;
let duration = llm_start.elapsed().as_millis() as u64; let duration = llm_start.elapsed().as_millis() as u64;
if let Ok(ref resp) = result { if let Ok(ref resp) = result {
let resp_str = serde_json::to_string_pretty(resp).unwrap_or_default(); let resp_str = serde_json::to_string_pretty(resp).unwrap_or_default();
crate::db::llm_call_log::insert(&pool, uid, jid, "classify_summarize", &mdl, &sys, &usr, &resp_str, duration as i32, Some(&url)).await.ok(); crate::db::llm_call_log::insert(&pool, uid, jid, "classify_summarize", &model, &sys, &usr, &resp_str, duration as i32, Some(&url)).await.ok();
} }
(url, title, result) (url, title, result)

Loading…
Cancel
Save