From e87e6b79acf406fab460a9117f0c3c65bedf5003 Mon Sep 17 00:00:00 2001 From: itsrubberduck Date: Tue, 26 May 2026 21:24:41 +0200 Subject: [PATCH] Make classroom STT production-ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Last pass fixed the crashes but the UX wasn't trustworthy — you'd hit the mic, something happened, fields silently changed, and there was no clear way to see what Whisper actually heard or which fields it touched. This rebuilds that flow: UI - Dedicated transcription panel below the controls row replaces the single-line "Heard:" hint. Has explicit states: recording (red, pulsing dot, live MM:SS timer), transcribing (spinner), result (editable textarea + summary chip), or error (red body text). - Mic button label shows the elapsed recording time so the pilot knows recording is actually running. - Per-field mic icon appears on every blank that was filled by the current transcription, so it's obvious what came from speech vs. what was typed. - Result panel exposes three explicit actions: Apply to fields (re-runs the mapping after edits), Record again, Dismiss. - Hard auto-stop at 45s (well under the server's 2 MB / ~60s cap). - 503/unreachable responses from the PTT endpoint now flip `sttServerAvailable` so the mic button gracefully hides itself. Matching reliability (shared/utils/sttMatch.ts) - Process fields longest-expected-first so a 6-char callsign claims its substring before a 1-char digit field grabs an overlapping character. - Short candidates (<3 chars) now require a whole-word boundary match, so the digit "5" in callsign "359" no longer auto-fills an unrelated readability field. - Two new test cases cover both false-positive guards. 62 / 62 tests green, vue-tsc clean, dev server starts and serves the classroom page without TDZ / hydration warnings in the log. Co-Authored-By: Claude Opus 4.7 --- app/pages/classroom.vue | 307 ++++++++++++++++++++++++++++------ shared/utils/sttMatch.ts | 31 +++- tests/shared/sttMatch.test.ts | 51 ++++++ 3 files changed, 340 insertions(+), 49 deletions(-) diff --git a/app/pages/classroom.vue b/app/pages/classroom.vue index e0fe602..d81e0c4 100644 --- a/app/pages/classroom.vue +++ b/app/pages/classroom.vue @@ -1086,6 +1086,14 @@ mdi-check mdi-alert + + mdi-microphone + Expected: {{ fieldExpectedValue(segment.key) }} @@ -1130,7 +1138,9 @@ {{ sttTranscribing ? 'mdi-loading' : (sttRecording ? 'mdi-stop-circle' : 'mdi-microphone') }} - {{ sttTranscribing ? 'Transcribing…' : (sttRecording ? 'Stop' : 'Speak readback') }} + + + -
-
- mdi-alert - {{ sttError }} + + +
+
+
+ + {{ sttRecording ? 'mdi-microphone' : (sttTranscribing ? 'mdi-loading' : (sttError ? 'mdi-alert-circle' : 'mdi-microphone-message')) }} + + + + + +
+
+ Filled {{ sttLastFillSummary.filled }} / {{ sttLastFillSummary.total }} field{{ sttLastFillSummary.total === 1 ? '' : 's' }} +
-
- Heard: - {{ sttLastTranscription }} + +
{{ sttError }}
+ +
+ + Speak clearly into your microphone. Click Stop when done. + Sending audio to the speech server…
+ +