Don't show the live "recording"/listening indicator until the model is ready
startLive()'s browser-engine branch flipped liveStatus to "listening" (the red live-dot, "Listening..." hint) the instant the mic was granted, even if the Whisper pipeline was still loading — the user saw an active-looking session while nothing was being transcribed yet. transcribeLiveSegment() already correctly awaits the model-ready gate before posting a segment, so this was purely a misleading-status bug. Adds a "loading-model" LiveStatus between "starting" and "listening"; startLive() now waits on the same browserModelReady() gate the transcribe path uses before claiming "listening", with race-safe cleanup if the load fails while waiting. Server-engine live is unaffected. Adds Decisions.md D-034; updates tests/live.md's manual verification steps.
This commit is contained in:
1 parent
c5d193600a
commit
500cf3b36e
4 files changed
+116
-8
No files matched your search
+28
-2
@@ -889,8 +889,34 @@ export function App() {
|
||||
|
||||
try {
|
||||
const mic = await startMicCapture((chunk) => transcriber.push(chunk));
|
||||
liveRef.current = { mic, transcriber };
|
||||
setLiveStatus("listening");
|
||||
const session = { mic, transcriber };
|
||||
liveRef.current = session;
|
||||
if (loadProgress.ready) {
|
||||
// Pipeline already loaded for the current model/device — nothing to
|
||||
// wait on, go straight to "listening" as before.
|
||||
setLiveStatus("listening");
|
||||
} else {
|
||||
// Model not ready yet (first use, or a model/device switch): don't
|
||||
// claim "Listening" until the pipeline actually is one, otherwise the
|
||||
// live-dot/hint imply an active session while nothing is being
|
||||
// transcribed (D-034). `transcribeLiveSegment` already awaits the
|
||||
// same gate before posting, so no segments are lost either way.
|
||||
setLiveStatus("loading-model");
|
||||
try {
|
||||
await browserModelReady();
|
||||
// The session could have been torn down (Stop, or another start)
|
||||
// while we were waiting — only advance if it's still this one.
|
||||
if (liveRef.current === session) setLiveStatus("listening");
|
||||
} catch {
|
||||
// Load failed; the worker's own "error" handler already calls
|
||||
// setError() for stage:"load" failures, so don't duplicate it here.
|
||||
if (liveRef.current === session) {
|
||||
liveRef.current = null;
|
||||
await mic.stop().catch(() => {});
|
||||
setLiveStatus("idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (micError) {
|
||||
setLiveStatus("idle");
|
||||
const message =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** Live microphone transcription start/stop (M7, Decisions.md D-016). */
|
||||
|
||||
export type LiveStatus = "idle" | "starting" | "listening" | "stopping";
|
||||
export type LiveStatus = "idle" | "starting" | "loading-model" | "listening" | "stopping";
|
||||
|
||||
interface LiveControlsProps {
|
||||
status: LiveStatus;
|
||||
@@ -13,6 +13,7 @@ interface LiveControlsProps {
|
||||
const LABELS: Record<LiveStatus, string> = {
|
||||
idle: "Start live transcription",
|
||||
starting: "Requesting microphone…",
|
||||
"loading-model": "Loading model…",
|
||||
listening: "Stop",
|
||||
stopping: "Finishing…",
|
||||
};
|
||||
@@ -31,7 +32,9 @@ export function LiveControls({
|
||||
type="button"
|
||||
className={`live-button${listening ? " live-button-active" : ""}`}
|
||||
onClick={status === "idle" ? onStart : onStop}
|
||||
disabled={disabled || status === "starting" || status === "stopping"}
|
||||
disabled={
|
||||
disabled || status === "starting" || status === "loading-model" || status === "stopping"
|
||||
}
|
||||
aria-pressed={listening}
|
||||
>
|
||||
{LABELS[status]}
|
||||
@@ -46,6 +49,7 @@ export function LiveControls({
|
||||
whoever triggered it. */}
|
||||
<span className="visually-hidden" role="status">
|
||||
{status === "starting" && "Requesting microphone access"}
|
||||
{status === "loading-model" && "Loading model"}
|
||||
{status === "listening" && "Live transcription started"}
|
||||
{status === "stopping" && "Finishing live transcription"}
|
||||
</span>
|
||||
|
||||
Reference in new issue
Block a user