Make speech (STT/TTS) provider-agnostic (SPEECH_PROVIDER, OpenAI-compatible backends)#12
Closed
Averroeskw wants to merge 2 commits into
Closed
Conversation
Speech was the last hard-wired third-party dependency: TTS requires an Azure Speech key and STT a Groq key, with no way to point either at a different (e.g. self-hosted) backend. Following the same pattern as the search/weather providers: - SPEECH_PROVIDER = "azure" (stock: Azure TTS + Groq Whisper STT, default) | "openai" (any OpenAI-compatible audio API: OpenAI, LiteLLM, faster-whisper, openedai-speech, ...) - Auto-detects "openai" when OPENAI_SPEECH_BASE is configured and SPEECH_PROVIDER is unset; otherwise stock behavior is unchanged - OpenAI TTS output is transcoded to Ogg 16 kHz mono so the downstream ffmpeg pipeline and device see the same audio profile Azure produces - .env.template documents the new variables and fixes the stale SPEECH_KEY name (the code reads MSFT_SPEECH_KEY) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…on output-stream end to avoid truncated audio Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
|
Closing for now — pulling this back until I've verified the full stack end-to-end on the physical device (interposer inbound). Will reopen once it's hardware-verified. The branch lives on in my fork history if anyone needs the diff in the meantime. |
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.
Why
Speech is the last assistant-critical service that's hard-wired to specific vendors: TTS requires an Azure Speech key (
MSFT_SPEECH_KEY) and STT a Groq key, with no way to point either at a different backend. Same single-vendor situation as search/weather before #8 — anyone without those exact keys (or running fully self-hosted) has no voice pipeline at all.What
Speech is now provider-selectable via
SPEECH_PROVIDER(server/src/services/speech/):azure(default) — the stock pipeline, byte-for-byte unchanged: Azure Speech synthesis + Groq-hosted Whisper recognition. (Naming note: STT was already Groq, not Azure; "azure" here just means "the stock stack".)openai— any OpenAI-compatible audio API viaPOST /audio/transcriptions(multipart) andPOST /audio/speech: OpenAI itself, a LiteLLM proxy, self-hosted faster-whisper / Speaches, openedai-speech, etc. Configured withOPENAI_SPEECH_BASE,OPENAI_SPEECH_KEY(optional for keyless self-hosted servers),OPENAI_STT_MODEL(defaultwhisper-1),OPENAI_TTS_MODEL(defaulttts-1),OPENAI_TTS_VOICE(defaultalloy).If
SPEECH_PROVIDERis unset,openaiis auto-selected only whenOPENAI_SPEECH_BASEis configured — otherwise behavior is exactly as today.Audio formats (the honest part)
Ogg16Khz16BitMonoOpus, and the downstream pipeline depends on that:changeVolume/addBackgroundAudioforceinputFormat("ogg")before the audio reaches the device.response_format: "opus"(Ogg/Opus, 48 kHz) and transcodes to Ogg 16 kHz mono with the ffmpeg toolchain the server already uses (newtranscodeToOgghelper inservices/audio.ts), so everything downstream sees the same profile regardless of provider. One extra ffmpeg pass per response; no client/device changes.recognize()interface unchanged (Bufferin → transcript out); the device's Ogg capture buffer is uploaded asaudio.ogg, which Whisper-style endpoints accept natively. The silence gate (WHISPER_MIN_DB) stays provider-independent.azureprovider; theopenaiprovider takes its voice fromOPENAI_TTS_VOICE.speedcarries over cleanly (both are 1.0-based multipliers, clamped to OpenAI's 0.25–4 range). The translate feature's language-identifying STT (Google Speech v2) is a separate code path and is intentionally left untouched.Compatibility & verification
.env.templatedocuments the new block and fixes the staleSPEECH_KEYname — the code readsMSFT_SPEECH_KEY.tsc --noEmitclean; new files lint clean.changeVolumepath.🤖 Generated with Claude Code