Improve live mic transcription accuracy at all three stages - #28
Merged
MyNamesEMurray merged 1 commit intoSep 7, 2026
Merged
Conversation
Voice awareness lost accuracy in three places and we only worked on the
last one. This works all three.
Decode. We knew the ghost names, the channel, the game and the protected
vocabulary and told all of it to the brain, but never to the transcriber
that was mishearing it. `buildInitialPrompt` writes the Whisper initial
prompt from those names, surfaced at Settings -> Voice -> LocalVocal
tuning as one line to paste, alongside the preset of plugin settings
that actually decide whether a transcript is usable (src/localvocal.js,
quoted in the plugin's own wording so they can be found).
Text repair. A mishear was only ever fixed if the 20-second mic-check
script happened to provoke it. Transcript lines now also get a phonetic
pass against the tracked names, so a mangling nobody read aloud is still
recovered. Deliberately hard to fire, because a wrong auto-correction
silently rewrites real speech for a whole stream: 4+ character names,
phonetic equality plus a character-similarity floor, a stricter floor
again before two spoken words are fused into a one-word name ("back on"
must not become "Beacon"), and the streamer's own word fixes run first
and win. Off with speech.matchVocabulary.
Capture. A new `engine` transcript mode connects to a speech-to-text
server running on the streamer's own machine (whisper.cpp server,
faster-whisper-server, WhisperLive), which gives us what a caption
plugin cannot: voice activity gating, so silence is never decoded into
filler; a confidence per line, so a half-heard line is dropped instead
of answered out loud; and the initial prompt wired in automatically and
re-sent when the detected game changes. Loopback URLs only, enforced
before dialing, because audio never leaving the PC is a product promise
and not a default. LocalVocal stays the default mode.
Plus voice health (src/voicehealth.js): most "the transcription is bad"
reports are a plugin setting, and every symptom is visible in the text
we already ingest, so the app now names the setting instead of leaving
the streamer to guess. Reported, never acted on -- every diagnosis is
inferential.
Release-Bump: minor
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
MyNamesEMurray
deleted the
claude/live-mic-transcription-accuracy-x5ptio
branch
September 7, 2026 01:24
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.
Summary
Voice awareness loses accuracy in three places (capture, decode, text repair) and until now the app only worked on the last one. This works all three: a local speech-to-text engine mode, a generated Whisper initial prompt, and phonetic recovery of mangled names, plus a diagnostic that names the LocalVocal setting behind a bad transcript.
Changes
Decode: we now bias the transcriber. We knew the ghost names, the channel, the game and
speech.vocabulary, told all of it to the brain, and never told the transcriber that was mishearing it.buildInitialPrompt()writes Whisper's initial prompt from those names. Settings → Voice → LocalVocal tuning shows it with a copy button, next to the preset of plugin settings that decide whether a transcript is usable at all (src/localvocal.js, quoted in LocalVocal's own labels so they can actually be found).Text repair: phonetic recovery of tracked names. A mishear was only ever fixed if the 20-second mic-check script happened to provoke it. Transcript lines now also get a phonetic pass against the tracked names, so a mangling nobody read aloud is still recovered. Deliberately hard to fire, because a wrong auto-correction silently rewrites real speech for a whole stream: names of 4+ characters, phonetic equality plus a character-similarity floor of 0.6, a stricter 0.8 floor before two spoken words are fused into a one-word name, and the streamer's own word fixes run first and win. Off with
speech.matchVocabulary.Capture: a new
enginetranscript mode.src/sttengine.jsconnects to a speech-to-text server on the streamer's own machine (whisper.cppserver, faster-whisper-server, WhisperLive), which gives us what a caption plugin cannot: voice activity gating, so silence is never decoded into filler; a confidence per line, so a half-heard line is dropped rather than answered out loud; and the initial prompt wired in automatically and re-sent when the detected game changes. LocalVocal stays the default and the other modes are unchanged.Voice health.
src/voicehealth.jsreads the transcript and names the misconfiguration behind what it sees: duplicate redraws mean partial transcription is on, fragment lines mean the buffer is too short, filler in the silences means VAD is off, identical lines in a row mean the decoder is stuck. Reported and never acted on, since every diagnosis is inferential.Deliberately not an OBS plugin: a plugin runs inside the OBS process, and the crash already documented in the README is LocalVocal faulting there and taking OBS with it. A separate process buys the same thing at a fraction of the risk.
Verification
config.example.jsonparse,npm test(162 tests, 0 failures; the 1 skip is the pre-existing Windows-only SAPI test),npm run smoke→ SMOKE OK.test/speech.test.js, the engine client intest/sttengine.test.js(fake socket, no network), the diagnostics intest/voicehealth.test.js, and the feed wiring intest/transcript.test.js./api/voice/tuningreturnedOn stream tonight we talk about Wisp, Beacon, emurray, and Hollow Knight.plus the 8-step preset;/api/voice/healthreturned all five checks.Risk & rollout
config.example.jsonand documented in the README table:transcript.engineUrl,transcript.engineMinConfidence,speech.matchVocabulary.transcript.modegainsengine. No migration; existing configs deep-merge and behave exactly as before.speech.matchVocabulary: falseturns it off entirely and the streamer's own fixes always win.127.0.0.1/localhost/[::1], and does not resolve hostnames (the same rebinding trap the Host check closes). Audio still never leaves the machine, and nothing here touches the API-key or Origin handling.wsis imported lazily insrc/transcript.js, so the non-engine modes (and their tests) still pull nothing.Release-Bump: minor.Checklist
npm run smokepasses locally (or CI is green)main🤖 Generated with Claude Code
https://claude.ai/code/session_01LWa54BF5RjHWC5GFaENZMM
Generated by Claude Code