From 6886c20e266bc3775441db18f0544952ecc76742 Mon Sep 17 00:00:00 2001 From: Brummel Date: Mon, 20 Apr 2026 13:01:11 +0200 Subject: [PATCH] Refactor OnelinerDisplay states Introduce `Generating` state and clarify `Empty` and `Missing` states. The `Pending` state now specifically refers to transcription being in progress. The `Generating` state covers the period after transcription is complete but before the LLM has produced the final oneliner state, or when a new state needs to be generated due to new recordings. The `Missing` state is collapsed into `Empty` as the UI treats them identically when no title is expected. --- server/src/routes/user_web.rs | 53 +++++++++++++++++++++++++--------- server/templates/my_cases.html | 2 +- 2 files changed, 40 insertions(+), 15 deletions(-) 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 {
-
{% match case.oneliner %}{% when OnelinerDisplay::Ready with (t) %} — {{ t }}{% when OnelinerDisplay::Empty %} — kein medizinischer Inhalt{% when OnelinerDisplay::Error %} — Oneliner-Fehler{% when OnelinerDisplay::Pending %} — wird transkribiert …{% when OnelinerDisplay::Missing %} — unbenannt{% endmatch %}
+
{% match case.oneliner %}{% when OnelinerDisplay::Ready with (t) %} — {{ t }}{% when OnelinerDisplay::Empty %} — unbenannt{% when OnelinerDisplay::Error %} — Fehler{% when OnelinerDisplay::Pending %} — transkribiere …{% when OnelinerDisplay::Generating %} — generiere Titel …{% endmatch %}
{{ case.recordings_count }} Aufnahmen{% if case.has_document %} — ausgewertet{% else %} — offen{% endif %}{% if case.analyzing %} wird analysiert{% endif %}
{% if is_admin %}
{{ case.case_id }}
{% endif %}