fix(whisperkit): streaming translate slows after ~30-40s — task-aware confirmation lag - #230
Merged
Merged
Conversation
…e confirmation lag Streaming decode re-decodes everything after lastConfirmedSegmentEndSeconds every pass, and AudioStreamTranscriber always holds back the newest requiredSegmentsForConfirmation (2) segments. On task=.translate each pass must re-GENERATE English for that whole unconfirmed tail (more tokens, lower confidence, more fallbacks than same-language transcribe), so after ~30-40s of continuous speech the pass cost outgrows the loop's 1s new-audio cadence and partials visibly lag. Make the threshold task-aware (WhisperKitStreamingDecodePolicy .requiredSegmentsForConfirmation(translate:)): translate holds back 1 segment, roughly halving the steady-state re-decode window; transcribe keeps the upstream default of 2. Tests pin the values, the >=1 floor, and that the translate threshold still satisfies the #222 confirmed-end advancement invariant (no 30s truncation regression). Also corrects docs/WHISPERKIT_PILOT.md, which still documented withoutTimestamps: true (the exact config #222 removed) and 'file transcription only'. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Symptom
WhisperKit backend, Russian speech, translate-to-English on: works well at first, gets noticeably sluggish after ~30–40 s of continuous dictation.
Root cause (researched, fork + app both mapped)
The streaming loop (
AudioStreamTranscriber) re-decodes everything afterlastConfirmedSegmentEndSecondson every pass, and confirmation permanently holds back the newestrequiredSegmentsForConfirmation(2) segments — so the re-decoded tail settles at ~2–3 segments (10–25 s of audio). Ontask: .translateevery pass must also re-generate English for that whole tail (more tokens, lower confidence, more decoder fallbacks than same-language transcribe), so once the tail fills out, per-pass cost outgrows the loop's hard-coded ≥1 s new-audio cadence and partials lag — exactly a "fine at first, slow after 30–40 s" curve. The knob was never passed at our call site; both tasks silently ran the upstream default.Fix
WhisperKitStreamingDecodePolicy.requiredSegmentsForConfirmation(translate:)— translate holds back 1 segment (clip point advances a segment sooner → steady-state re-decode window roughly halves), transcribe keeps the upstream default of 2. Passed explicitly inmakeStreamHandle. Tests pin the per-task values, the ≥1 floor (0 would freeze half-heard words with no revision room), and that the translate threshold still satisfies the #222 confirmed-end advancement invariant (no 30 s-truncation regression).Also fixes
docs/WHISPERKIT_PILOT.md, which still documentedwithoutTimestamps: true— the exact configuration #222 removed — plus its stale "file transcription only" limitation.Testing
swift test: 1937 tests green (3 new inWhisperKitStreamingDecodePolicyTests)./build.sh(WhisperKit default): clean, no new warningsFollow-ups (researched, out of scope here)
🤖 Generated with Claude Code