// Highlight-reel dispatcher — delegerer til synops-highlight CLI. // // Maskinrommet orkestrerer, CLI-verktøyet gjør jobben: // henter transkripsjon, kaller AI for analyse, oppretter klipp-noder. // // Jobbtype: "highlight_extract" // Payload: { "media_node_id": "", "requested_by": "", // "collection_id": "" (valgfri) } // // Ref: docs/proposals/auto_highlight_reel.md // docs/retninger/unix_filosofi.md use uuid::Uuid; use crate::ai_admin; use crate::cli_dispatch; use crate::jobs::JobRow; /// Synops-highlight binary path. fn highlight_bin() -> String { std::env::var("SYNOPS_HIGHLIGHT_BIN") .unwrap_or_else(|_| "synops-highlight".to_string()) } /// Handler for highlight_extract-jobber. /// /// Spawner synops-highlight med --write for å gjøre alt arbeidet: /// transkripsjonshenting, AI-analyse, klipp-node-opprettelse. /// /// Payload forventer: /// - media_node_id: UUID — episodenoden med transkripsjon /// - requested_by: UUID — brukeren som utløste highlight-analysen /// - collection_id: UUID (valgfri) — podcast-samling for belongs_to-edge pub async fn handle_highlight_extract( job: &JobRow, db: &sqlx::PgPool, ) -> Result { let media_node_id: Uuid = job .payload .get("media_node_id") .and_then(|v| v.as_str()) .and_then(|s| s.parse().ok()) .ok_or("Mangler gyldig media_node_id i payload")?; let requested_by: Uuid = job .payload .get("requested_by") .and_then(|v| v.as_str()) .and_then(|s| s.parse().ok()) .ok_or("Mangler gyldig requested_by i payload")?; let collection_id: Option = job .payload .get("collection_id") .and_then(|v| v.as_str()) .and_then(|s| s.parse().ok()); // Bygg kommando let bin = highlight_bin(); let mut cmd = tokio::process::Command::new(&bin); cmd.arg("--media-node-id") .arg(media_node_id.to_string()) .arg("--requested-by") .arg(requested_by.to_string()) .arg("--write"); if let Some(coll_id) = collection_id { cmd.arg("--collection-id").arg(coll_id.to_string()); } // Sett miljøvariabler CLI-verktøyet trenger cli_dispatch::set_database_url(&mut cmd)?; cli_dispatch::forward_env(&mut cmd, "AI_GATEWAY_URL"); cli_dispatch::forward_env(&mut cmd, "LITELLM_MASTER_KEY"); // Modellalias fra ai_job_routing — admin kan endre uten redeploy let model_alias = ai_admin::resolve_routing_or_default(db, "highlight").await; cmd.env("AI_HIGHLIGHT_MODEL", &model_alias); tracing::info!( media_node_id = %media_node_id, requested_by = %requested_by, collection_id = ?collection_id, bin = %bin, "Starter synops-highlight" ); let result = cli_dispatch::run_cli_tool(&bin, &mut cmd).await?; tracing::info!( media_node_id = %media_node_id, clips_created = result["clips_created"].as_u64().unwrap_or(0), highlights_found = result["highlights_found"].as_u64().unwrap_or(0), status = result["status"].as_str().unwrap_or("unknown"), "synops-highlight fullført" ); Ok(result) }