@ -194,8 +194,9 @@ pub async fn run_generation(
state : AppState ,
state : AppState ,
user_id : Uuid ,
user_id : Uuid ,
tx : Arc < watch ::Sender < ProgressEvent > > ,
tx : Arc < watch ::Sender < ProgressEvent > > ,
provider_override : Option < Arc < dyn crate ::services ::llm ::LlmProvider > > ,
) {
) {
let result = run_generation_inner ( job_id , & state , user_id , & tx ). await ;
let result = run_generation_inner ( job_id , & state , user_id , & tx , provider_override ). await ;
match result {
match result {
Ok ( synthesis_id ) = > {
Ok ( synthesis_id ) = > {
@ -224,11 +225,12 @@ pub async fn run_generation(
}
}
/// Inner implementation of the generation pipeline, returning a Result.
/// Inner implementation of the generation pipeline, returning a Result.
async fn run_generation_inner (
pub async fn run_generation_inner (
job_id : Uuid ,
job_id : Uuid ,
state : & AppState ,
state : & AppState ,
user_id : Uuid ,
user_id : Uuid ,
tx : & watch ::Sender < ProgressEvent > ,
tx : & watch ::Sender < ProgressEvent > ,
provider_override : Option < Arc < dyn crate ::services ::llm ::LlmProvider > > ,
) -> Result < Uuid , AppError > {
) -> Result < Uuid , AppError > {
// Batch buffer for article history traces (flushed at logical boundaries)
// Batch buffer for article history traces (flushed at logical boundaries)
let mut pending_traces : Vec < db ::article_history ::ArticleHistoryEntry > = Vec ::new ( ) ;
let mut pending_traces : Vec < db ::article_history ::ArticleHistoryEntry > = Vec ::new ( ) ;
@ -254,10 +256,22 @@ async fn run_generation_inner(
let sources = db ::sources ::list_for_user ( & state . pool , user_id ) . await ? ;
let sources = db ::sources ::list_for_user ( & state . pool , user_id ) . await ? ;
emit_progress ( tx , "provider" , "Configuration du fournisseur IA..." , 12 ) ;
emit_progress ( tx , "provider" , "Configuration du fournisseur IA..." , 12 ) ;
let ( provider_name , api_key ) = resolve_provider_and_key ( state , user_id , & settings ) . await ? ;
let ( provider_name , provider ) = if let Some ( mock_provider ) = provider_override {
let provider = create_provider ( & provider_name , api_key ) ? ;
( "mock" . to_string ( ) , mock_provider )
} else {
let ( pname , api_key ) = resolve_provider_and_key ( state , user_id , & settings ) . await ? ;
let p = create_provider ( & pname , api_key ) ? ;
( pname , p )
} ;
let ( model_research , model_websearch ) = if provider_name = = "mock" {
let research = if settings . ai_model . is_empty ( ) { "mock-model" . to_string ( ) } else { settings . ai_model . clone ( ) } ;
let websearch = if settings . ai_model_websearch . is_empty ( ) { "mock-model" . to_string ( ) } else { settings . ai_model_websearch . clone ( ) } ;
( research , websearch )
} else {
let model_research = if ! settings . ai_model . is_empty ( ) { settings . ai_model . clone ( ) } else { resolve_model ( state , & provider_name ) . await ? } ;
let model_research = if ! settings . ai_model . is_empty ( ) { settings . ai_model . clone ( ) } else { resolve_model ( state , & provider_name ) . await ? } ;
let model_websearch = if ! settings . ai_model_websearch . is_empty ( ) { settings . ai_model_websearch . clone ( ) } else { model_research . clone ( ) } ;
let model_websearch = if ! settings . ai_model_websearch . is_empty ( ) { settings . ai_model_websearch . clone ( ) } else { model_research . clone ( ) } ;
( model_research , model_websearch )
} ;
let user_rate_limiter = get_user_rate_limiter ( state , & settings , user_id ) ;
let user_rate_limiter = get_user_rate_limiter ( state , & settings , user_id ) ;
// Tracking structures
// Tracking structures