feat: Add auto-trigger for LLM analysis
Introduces a new module `auto_trigger` responsible for opportunistically initiating LLM analysis jobs. This mechanism scans case directories for new or updated recordings and transcripts, automatically creating and queuing analysis jobs when appropriate. Key components: - `evaluate_case`: Pure function to determine if a case is ready for analysis based on recording status, transcriptions, document modification times, and existing job/failure markers. - `try_enqueue`: Orchestrates the analysis job creation and queuing process if `evaluate_case` returns `AutoDecision::Enqueue`. - `try_enqueue_all_for_user`: Iterates through all user cases to trigger `try_enqueue` for eligible ones. - `write_failure_marker`/`remove_failure_marker`: Handles persistent recording of analysis failures and their cleanup. This feature aims to reduce manual intervention by automatically analyzing new or changed case data.
This commit is contained in:
@@ -5,7 +5,9 @@ use std::time::Duration;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use super::{ANALYSIS_INPUT_FILE, AnalysisInput, AnalyzeReceiver, DOCUMENT_FILE, llm, prompt};
|
||||
use super::{
|
||||
ANALYSIS_INPUT_FILE, AnalysisInput, AnalyzeReceiver, DOCUMENT_FILE, auto_trigger, llm, prompt,
|
||||
};
|
||||
use crate::config::Config;
|
||||
use crate::events::{self, CaseEventKind, EventSender};
|
||||
use crate::gazetteer::Gazetteer;
|
||||
@@ -69,11 +71,18 @@ async fn process(
|
||||
let stub = b"_Keine verwertbaren Aufnahmen (alle Aufnahmen still)._\n";
|
||||
if let Err(e) = write_atomic(&document_path, stub).await {
|
||||
error!(path = %document_path.display(), error = %e, "writing stub document failed");
|
||||
let _ = auto_trigger::write_failure_marker(
|
||||
case_dir,
|
||||
&input.last_recording_mtime,
|
||||
&format!("stub write: {e}"),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
if let Err(e) = tokio::fs::remove_file(&input_path).await {
|
||||
warn!(path = %input_path.display(), error = %e, "removing analysis input failed");
|
||||
}
|
||||
auto_trigger::remove_failure_marker(case_dir).await;
|
||||
info!(case = %case_dir.display(), "analysis done (stub, no recordings)");
|
||||
events::emit(
|
||||
events_tx,
|
||||
@@ -117,6 +126,12 @@ async fn process(
|
||||
// Do not log the response body — LlmError::Display is already
|
||||
// redacted, but reinforce the rule here for future readers.
|
||||
error!(case = %case_dir.display(), error = %e, "llm call failed");
|
||||
let _ = auto_trigger::write_failure_marker(
|
||||
case_dir,
|
||||
&input.last_recording_mtime,
|
||||
&format!("llm: {e}"),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
};
|
||||
@@ -128,6 +143,12 @@ async fn process(
|
||||
|
||||
if let Err(e) = write_atomic(&document_path, document.as_bytes()).await {
|
||||
error!(path = %document_path.display(), error = %e, "writing document failed");
|
||||
let _ = auto_trigger::write_failure_marker(
|
||||
case_dir,
|
||||
&input.last_recording_mtime,
|
||||
&format!("write document: {e}"),
|
||||
)
|
||||
.await;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -137,6 +158,7 @@ async fn process(
|
||||
if let Err(e) = tokio::fs::remove_file(&input_path).await {
|
||||
warn!(path = %input_path.display(), error = %e, "removing analysis input failed");
|
||||
}
|
||||
auto_trigger::remove_failure_marker(case_dir).await;
|
||||
|
||||
info!(
|
||||
case = %case_dir.display(),
|
||||
|
||||
Reference in New Issue
Block a user