STT forces German on every utterance: -l de hardcoded + language never forwarded, so English voice is translated to German
#9
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptom
English voice captures through the PWA come back wrong. In the worst case whisper.cpp does not transcribe the English audio, it translates it into German — verified live with an English clip returning German text.
Path
PWA voice →
OTTO_PWA_MVOICE_URL(which, despite the name, points at mGPUmanagermrock:8770/v1/stt) → mGPUmanager routesstt→ whisper-server.service (whisper.cpplarge-v3-turbo). mVoice is not in the STT path at all; it only serves TTS. (Full path write-up:m/mVoicedocs/stt-production-path.md, from the #22 investigation.)Root cause — two parts, both required
whisper-server.servicehardcodes-l de. Verified ExecStart on mRock:mGPUmanager only forwards a language when
stt_lang != auto. The PWA always sendsauto. So the per-request language is never set, the service falls back to its hardcoded-l de, and auto-detect is unreachable.stt_languagein the response is therefore a constant, not a detection.Under
-l dewith no per-request prompt, an English clip comes back translated into German rather than transcribed.Verified fix (apollo, #22 investigation)
-l defrom the service and set-l autoexplicitly. Note: whisper.cpp's-ldefault isen, so removing the flag is NOT the same as-l auto— set it explicitly.language=autoto whisper-server instead of suppressing it, and report the realdetected_languagefrom whisper.cpp'sverbose_json.No German regression:
autovsdeoutput is byte-identical on the German reference clip.Acceptance
detected_languagereflects the actual detected language rather than a constant.Provenance
Surfaced by apollo (mvoice/gitster) during
m/mVoice#22 (reported symptom was English punctuation loss; the real defect is this). ExecStart and thestt_lang != autoforwarding both independently re-verified by mvoice/head before filing. Filed here because the code and config live in mGPUmanager, not mVoice. Left unassigned — mGPUmanager owns the priority call.Related:
m/mVoice#22, and the glossary-drift defect filed alongside this one.Fixed, code pushed, live verification below
Branch
mai/curie/mgpumanager-stt-truth-9.Commits: 730fe90 · cbebade
Both root causes fixed
1. The service.
whisper-server.servicenow runs-l auto, set explicitly. Confirmed against this build's own help text:-l LANG, --language LANG [en] spoken language ('auto' for auto-detect)— the default really isen, so dropping the flag would not have been the same thing. Installed and restarted on mRock at 11:53:30; the old unit is kept as~/.config/systemd/user/whisper-server.service.bak-curie. The unit joins the repo assystemd/whisper-server.serviceso the next change is reviewable.2. The broker.
proxySTTWhisperCppnow forwards a language on every request,autoincluded, asks forresponse_format=verbose_json, and reports the language whisper detected.stt_languageused to be the constant"de"— a claim, not a measurement. whisper names languages in English ("german"), so the adapter maps to ISO-639-1; an unmapped language passes through verbatim rather than being guessed at, because the field is a log tag for the PWA and never a control input.Acceptance, measured
End to end through a staging broker (port 8771) against the real
whisper-serveron mRock, in the PWA's own dialect (stt_lang=auto, multipartaudio):user_textstt_languageHello Matthias, this is an English test sentence about the weather in London today.enHallo Otto, das ist ein deutscher Test Satz über das Wetter in Düsseldorf heute.deautoanddeproduce byte-identical text on the German reference clip, reproducing apollo's measurement, so drift there stays a real signal.detected_languagetracks the audio rather than the config.The clips are espeak-ng synthetic, so this proves the mechanism, not transcription quality. The translation symptom itself needs m's real voice — an espeak English clip is clean enough that even forced
language=detranscribed rather than translated it, while still reporting"language":"german". The forcing was demonstrably present; the clip was just too easy to break on it.One more defect found while verifying — the punctuation symptom
whisper carries the initial prompt's punctuation style into the transcript. Same audio, same terms, only the prompt's final character differs:
Reproducible, two runs each, live against
large-v3-turbo. Since m/mVoice#22's reported symptom was punctuation loss, this is not cosmetic. The generated prompt, the static fallback and the service's launch--promptnow all end in a full stop.That exposed a second one: whisper sometimes emits a sentence-final mark as its own segment, and joining the segments delivered
Juliane .to the PWA, which renders the raw string.normalizeTranscriptcloses that gap now.Tests
TestSTTReportsDetectedLanguage,TestSTTForwardsConcreteLanguage,TestSTTMissingLanguageDefaultsToAuto,TestSTTClosesGapBeforePunctuation, plus the reworkedTestSTTWhisperCppAdapter. Each was run as a negative control with its fix disabled, and each failed — build, vet and the full suite are green with them in place.Still open
One unit edit is outstanding and held: the launch
--promptgains its closing full stop, which needs anotherdaemon-reloadplus restart. Held at the head's request while mRock measurements run.The broker binary deploy to mRock is queued behind the VRAM stream's deploy, per the shared-binary rule.
Glossary work is on #10. Design note including what the choice costs:
docs/designs/issue-9-10-stt-language-and-lexicon.md.Deployed to mRock and verified against production
On main 7b2a0ba. Broker binary rebuilt from that merged main and deployed 12:05.
Live, through the production broker on
mrock:8770/v1/stt, in the PWA's own dialect:stt_languagetracks the audio, not the config. ✅whisper-server.serviceruns-l autoon mRock, confirmed from the liveExecStart. Both edits are backed up (.bak-curie,.bak-curie2), as is the previous broker binary (bin/mgpumanager.bak-curie).After the restart:
/healthzok,/v1/statuslists all four consumers healthy,POST /v1/gamemode200 and released cleanly (ollama back up,/api/tags200). mDock failover untouched and answering.The host-side
comfyui vram_resident_mib: 6000hand-edit was preserved; the repo says 13000.What this does not prove
The clips are espeak-ng synthetic. They show the mechanism — the language is forwarded, detection is honoured and reported. They cannot show the original symptom, because espeak English is clean enough that even forced
language=detranscribed rather than translated it. m's own English voice capture is the last check.Correction: what production returns now
The transcripts I posted earlier were from espeak-ng clips. mRock has m's own voice on disk —
~/dev/mVoice/samples/profiles/otto/ref_de.wavandref_en.wav, with the reference text inmetadata.json. Real audio, known transcript. Re-running the acceptance against those found a defect the synthetic clips could not.m's real German voice, through production, before the fix:
Anwaltsplit in two. whisper follows its tokenizer convention and omits the leading space when a segment continues the previous word —" … als Anw"then"alt in …"— andnormalizeTranscriptjoined every segment break with a space. The word boundary signal was in whisper's output the whole time;strings.Fieldsdiscarded it.Not introduced by the language or glossary work. Checked against three prompts, two runs each: the break appears with the old 11-term prompt as well, and only disappears with no prompt at all. It has been in production since the #7 polish, on every request that carries a per-request prompt. espeak never produced a mid-word segment break, which is why three rounds of synthetic verification missed it.
Fixed in 19a4279, on main beabc09, deployed. A segment joins with a space only when it begins with whitespace.
Production now, m's own voice:
Both verbatim against the reference text. #9's acceptance is now met on m's real speech rather than on synthetic audio: his English capture transcribes as English, not translated, and
stt_languagereportsen./healthz,/v1/statusand/v1/gamemodeverified after the restart; game mode released cleanly.The standing lesson, since this project keeps reaching for espeak: a synthetic voice can verify a mechanism, never a transcript. The reference recordings are on the box.