diff --git a/server/src/routes/user_web.rs b/server/src/routes/user_web.rs index 2182ab0..3048a85 100644 --- a/server/src/routes/user_web.rs +++ b/server/src/routes/user_web.rs @@ -33,18 +33,23 @@ use crate::transcribe::recovery as transcribe_recovery; /// exposes the raw [`OnelinerState`] and lets each client decide how /// to render transit states. enum OnelinerDisplay { + /// LLM produced a usable title. Ready(String), + /// Stable "no title to expect" — either the LLM returned nothing + /// (no medical content in transcript) or every recording failed so + /// nothing can ever generate a title. UI treats both identically; + /// the reason is uninteresting to the doctor in the list view. Empty, + /// LLM call failed with transcripts available. Error, - /// No state file on disk + at least one non-failed recording is - /// still awaiting its transcript. The oneliner will appear once - /// transcription finishes. + /// Transcription still running — a title cannot exist yet. Pending, - /// No state file on disk and no pending transcription. Rare in - /// practice — the worker writes a state at the end of every job — - /// but possible right after a server crash between transcript and - /// oneliner write. - Missing, + /// Transcripts are done (or about to land) but the LLM hasn't + /// written a state yet, OR a previous state is obsolete because new + /// recordings arrived. The worker is generating right now or will + /// generate as soon as the last transcript is in. Covers the + /// reset-just-clicked case and the post-restart recovery window. + Generating, } struct UserCaseView { @@ -527,12 +532,32 @@ async fn compute_case_view( .all(|r| r.transcript.is_some()); let (state, _) = paths::read_oneliner_state(case_path).await; - let oneliner = match state { - Some(OnelinerState::Ready { text, .. }) => OnelinerDisplay::Ready(text), - Some(OnelinerState::Empty { .. }) => OnelinerDisplay::Empty, - Some(OnelinerState::Error { .. }) => OnelinerDisplay::Error, - None if !all_transcribed => OnelinerDisplay::Pending, - None => OnelinerDisplay::Missing, + let oneliner = if non_failed_count == 0 { + // All recordings failed — stable end state, no LLM will ever run. + // Missing state collapses to Empty ("unbenannt"): no title is + // expected, regardless of why. + match state { + Some(OnelinerState::Ready { text, .. }) => OnelinerDisplay::Ready(text), + Some(OnelinerState::Error { .. }) => OnelinerDisplay::Error, + Some(OnelinerState::Empty { .. }) | None => OnelinerDisplay::Empty, + } + } else if all_transcribed { + // Transcripts done — stable state, except for the brief window + // between transcript-write and state-write where the worker is + // still producing its result. + match state { + Some(OnelinerState::Ready { text, .. }) => OnelinerDisplay::Ready(text), + Some(OnelinerState::Empty { .. }) => OnelinerDisplay::Empty, + Some(OnelinerState::Error { .. }) => OnelinerDisplay::Error, + None => OnelinerDisplay::Generating, + } + } else { + // Transcription still pending. Any persisted state is obsolete: + // the worker will regenerate once the last transcript lands. + match state { + None => OnelinerDisplay::Pending, + Some(_) => OnelinerDisplay::Generating, + } }; let has_document = any_document_exists(case_path).await; diff --git a/server/templates/my_cases.html b/server/templates/my_cases.html index 7414b0b..4f5a817 100644 --- a/server/templates/my_cases.html +++ b/server/templates/my_cases.html @@ -86,7 +86,7 @@ try {