Local speech output (Kokoro TTS) and voice input (Whisper STT) - #185
Local speech output (Kokoro TTS) and voice input (Whisper STT)#185suinswofi wants to merge 2 commits into
Conversation
Both run entirely on the user's machine, in a shared Electron utility process (audioengine.js) built on kokoro-js and transformers.js with onnxruntime-node. The game window (speech.js) reads each turn's new story text aloud, streaming sentence by sentence, and offers push-to- talk voice commands which are recognized and typed into the game's input line. Each feature is independently toggleable from a new Audio tab in Preferences and from the View menu; models are downloaded on first enable and neither feature is on by default. makedist.py packages the needed modules per platform (--no-audio and lectroteAudioFeatures:false opt out); the Mac plist/entitlements gain microphone permission. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The talk key can now be a modifier held on its own (Ctrl or Alt, either or right side); pressing another key while holding it cancels the recording, so shortcuts still work. A Custom option in Preferences captures whatever key or combination is pressed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
In case it's useful for anyone wanting to try the speech features without building from source: I've published unofficial prebuilt test builds of this branch on my fork's releases page — https://github.com/suinswofi/lectrote/releases/tag/v1.5.6-speech.1 (Linux x64/arm64 and Windows x64/arm64/ia32 zips, plus a Windows installer). They're unsigned, and the win32-ia32 build omits the speech features since there's no 32-bit ONNX runtime. If the feature lands here I'll retire them in favor of the official releases, of course. |
|
A side note unrelated to the speech changes: while building and testing the Windows installer for the fork release (silent install/uninstall cycles under Wine), I noticed a few small quirks in
Also, for anyone else building the installer: Happy to file these as a separate issue (or a small follow-up PR) if that's preferred — just didn't want the observations to get lost. |
Hi Andrew — this is a draft proposal for optional, fully local speech features. It works end to end on Linux with a real microphone and speakers; it's marked draft because it hasn't been tried on Mac/Windows builds yet, and because it adds two npm dependencies and ~70 MB to each package, which is your call to make. Happy to adjust, split up, or shelve it as you see fit.
What it does
Two features, each independently toggleable (Preferences → new Audio tab, or the View menu), both off by default:
kokoro-js), streamed sentence by sentence. Choice of voices and speaking rate; reading is interrupted by new input; Stop Speaking (Cmd/Ctrl-.) and Repeat Last Turn (Cmd/Ctrl-Shift-R). Optional OS-voice fallback while the model downloads.@huggingface/transformers; base/small/large-v3-turbo selectable). The transcript is typed into the game's input line and (optionally) sent; single-key prompts get the first letter or spoken digit. Talk key: presets including bare Ctrl/Alt, or any custom key/combination; a Listen (Toggle) command for hands-free use.Models are downloaded on first enable into
<userData>/modelswith progress shown, and nothing is ever sent anywhere.Screenshots
The Audio tab in Preferences (both features on, models loaded):
The bundled Advent at its opening, being read aloud (this is the same turn as the audio sample below); the small bar at bottom right shows the mic button and the current speech state:
Audio sample
What the speech output sounds like: the opening of the bundled Advent (banner and the first room, "At End Of Road"), read by the default Kokoro voice (
af_heart) at speed 1.0. This is the raw audio the engine hands to the game window, captured from a fresh start of the game and saved as-is (48 s, 24 kHz mono WAV, 2.3 MB):▶ advent-opening-kokoro.wav
Implementation
audioengine.js— one shared ElectronutilityProcessowning the models (ONNX Runtime, CPU, off the UI thread); shuts down after 30 s idle.speech.js— game-window side: text extraction from the GlkOte recording handler (buffer windows only, echoed commands skipped), Web Audio playback queue, mic capture (AudioWorklet) + resample to 16 kHz, injection into GlkOte's line/char input via a synthetic Enter keypress, small status bar.main.js— engine lifecycle, IPC relay, prefs, menu items;audioconfig.js— shared constants;prefs.html/js— Audio tab.makedist.py— copies just the needed module files per platform (--no-audioandlectroteAudioFeatures:falsefor bound games opt out; win32-ia32 never includes them, since ONNX Runtime has no 32-bit build). Mac plist/entitlements gain microphone permission.kokoro-js@1.2.1,@huggingface/transformers@3.8.1(one deduped copy ofonnxruntime-node, N-API, so no rebuild). No changes to Quixe/GlkOte. License notes added to the README (phonemizer embeds espeak-ng, GPL-3.0).Testing so far
--no-audiobuild.🤖 Generated with Claude Code