Files
doctate/server/src/analyze/mod.rs
T
Brummel 70425939b2 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.
2026-04-20 09:18:30 +02:00

52 lines
1.7 KiB
Rust

use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use tokio::sync::mpsc;
pub mod auto_trigger;
pub mod llm;
pub mod prompt;
pub mod recovery;
pub mod render;
pub mod worker;
/// Single-document-per-case filenames. A re-analysis overwrites the
/// document in place (handler deletes it first; worker writes the fresh one).
pub const DOCUMENT_FILE: &str = "document.md";
pub const ANALYSIS_INPUT_FILE: &str = "analysis_input.json";
/// A single request to analyze a case. Payload is tiny (a path), so the
/// channel is unbounded — persistence lives in `analysis_input.json` on
/// disk, not in the queue. Recovery re-enqueues any inputs the server may
/// have held at crash time.
#[derive(Debug, Clone)]
pub struct AnalyzeJob {
pub case_dir: PathBuf,
}
pub type AnalyzeSender = mpsc::UnboundedSender<AnalyzeJob>;
pub type AnalyzeReceiver = mpsc::UnboundedReceiver<AnalyzeJob>;
pub fn channel() -> (AnalyzeSender, AnalyzeReceiver) {
mpsc::unbounded_channel()
}
/// Persistent input for a single analysis run. Written by the analyze
/// handler, consumed by the analyze worker, removed after a successful
/// document write.
#[derive(Debug, Serialize, Deserialize)]
pub struct AnalysisInput {
/// Latest filesystem mtime (server clock) of any `.m4a` in the case at
/// the moment the analyze button was clicked. Carried through for
/// diagnostics / future "Nachtrag" detection.
pub last_recording_mtime: String,
pub recordings: Vec<RecordingInput>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RecordingInput {
/// Recording timestamp from the watch (filename-derived, ISO-8601).
pub recorded_at: String,
pub text: String,
}