diff --git a/server/src/routes/case_actions.rs b/server/src/routes/case_actions.rs index b95ec98..f104a49 100644 --- a/server/src/routes/case_actions.rs +++ b/server/src/routes/case_actions.rs @@ -124,13 +124,44 @@ pub(crate) async fn build_analysis_input(case_dir: &Path) -> Result = Vec::new(); - let mut last_mtime: SystemTime = SystemTime::UNIX_EPOCH; - for (m4a_path, mtime) in &m4as { - if *mtime > last_mtime { - last_mtime = *mtime; - } + // last_mtime is derived from ALL m4as (including ones that turn out + // to have blank transcripts) — a late blank addendum still counts as + // case activity. Computed up-front so `read_recordings` can focus on + // I/O + validation. + let last_mtime = compute_last_mtime(&m4as); + let recordings = read_recordings(&m4as).await?; + // Silent-only case: `recordings` may be empty here. The analyze worker + // handles that by writing a stub document instead of calling the LLM. + let last_recording_mtime = OffsetDateTime::from(last_mtime) + .format(&Rfc3339) + .map_err(|e| AppError::Internal(format!("format mtime: {e}")))?; + + Ok(AnalysisInput { + last_recording_mtime, + recordings, + }) +} + +/// Max modification time across all m4as. Falls back to UNIX_EPOCH for +/// an empty slice — callers should have already rejected that case. +fn compute_last_mtime(m4as: &[(PathBuf, SystemTime)]) -> SystemTime { + m4as.iter() + .map(|(_, mtime)| *mtime) + .max() + .unwrap_or(SystemTime::UNIX_EPOCH) +} + +/// Read the `.transcript.txt` sidecar for every m4a. Any missing +/// transcript aborts with the legacy 400 "Nicht alle Aufnahmen sind +/// transkribiert" body. Blank transcripts are silently skipped — they +/// represent recordings the transcriber classified as silence and must +/// not be pushed to the LLM. +async fn read_recordings( + m4as: &[(PathBuf, SystemTime)], +) -> Result, AppError> { + let mut recordings: Vec = Vec::new(); + for (m4a_path, _) in m4as { let transcript_path = m4a_path.with_extension("transcript.txt"); let text = tokio::fs::read_to_string(&transcript_path) .await @@ -148,17 +179,7 @@ pub(crate) async fn build_analysis_input(case_dir: &Path) -> Result