7.6 KiB
Speech
Last updated: dev@df2fad2 | 2026-07-12
Scope
This spec covers speech behavior in:
- app service initialization and route registration in
app.py; services/stt/stt_service.py;services/tts/tts_service.py;routes/stt_routes.py;routes/tts_routes.py;src/upload_limits.py;- settings defaults/cache in
src/settings.py; - settings routes in
routes/auth_routes.py; - model endpoint cleanup in
routes/model_routes.py; - settings/tool aliases in
src/tool_implementations.py; - frontend modules
static/js/voiceRecorder.js,static/js/tts-ai.js,static/app.js,static/js/chat.js,static/js/slashCommands.js,static/js/keyboard-shortcuts.js,static/js/settings.js, andstatic/index.html; - optional dependency declarations in
requirements-optional.txt; - runtime cache path
data/tts_cache/; - tests covering speech service toggles, TTS speed/cache, STT temp cleanup, upload limits, settings scrubbing, and model endpoint cleanup.
Current Call Sites Include
- chat mic/send button behavior;
- browser and server STT recording paths;
- chat message read-aloud buttons and streaming TTS queueing;
/ttsslash command playback;- keyboard shortcut TTS activation;
- admin/settings API writes and
manage_settingsaliases; - model endpoint deletion cleanup for
endpoint:<id>speech providers.
STT
services.stt.STTService owns speech-to-text provider behavior. routes/stt_routes.py owns /api/stt/transcribe and /api/stt/stats. static/js/voiceRecorder.js owns microphone capture, browser STT, server upload, and audio-attachment fallback.
Provider runtime:
disabledreturns unavailable and avoids provider calls;browseris client-side only through Web Speech API and does not call/api/stt/transcribe;locallazily importsfaster-whisper, writes uploaded audio to a temporary WebM file, transcribes, and deletes the temp file infinally;endpoint:<id>resolves aModelEndpointand postsaudio.webmto/audio/transcriptionswith model and optional language.
Route behavior:
- audio uploads are capped by the shared STT upload limit from
src.upload_limits, including environment override validation; - empty uploads return a route error;
- uploaded content type, extension, and magic bytes are not strongly validated today;
- endpoint providers report optimistic availability and fail at request time if offline/misconfigured.
Frontend behavior:
- browser recording needs secure context and microphone permissions;
- server transcription success inserts text into the input;
- failed server transcription can attach the recorded audio file to chat instead; empty transcription shows a no-speech message.
TTS
services.tts.TTSService owns text-to-speech provider behavior, speed parsing, cache behavior, and local/provider-specific synthesis. routes/tts_routes.py owns /api/tts/stats, /api/tts/synthesize, and cache clearing. static/js/tts-ai.js owns frontend playback, client object-URL caching, browser TTS, queueing, and streaming button state.
Provider runtime:
disabledreturns unavailable and avoids provider calls;browseris client-side only throughspeechSynthesis;localcurrently means Kokoro and requirestorch,kokoro, and CUDA/import availability;endpoint:<id>resolves aModelEndpointand posts to/audio/speech.- unknown or non-string
tts_providervalues are treated as unavailable rather than being parsed as endpoint strings.
Route behavior:
/api/tts/synthesizesupports binaryaudioresponses and JSONbase64responses;- binary responses choose WAV or MP3 MIME by audio magic bytes;
- synthesis input is passed to the service as submitted and capped there;
- malformed or nonpositive
tts_speedfalls back to1.0; - provider unavailable returns 503; failed synthesis/transcription generally returns route-level failure.
Settings, Endpoints, And Cache
Speech providers are global settings under data/settings.json, with defaults in src/settings.py. Settings reads are scrubbed for non-admin callers, writes are admin-only, and manage_settings can change non-secret speech settings through aliases.
Visible UI state is not complete: backend and JS speech settings exist, the TTS settings card is currently hidden, and the STT settings JS exits when its removed DOM nodes are absent.
routes.model_routes clears tts_provider and stt_provider references when a referenced model endpoint is deleted.
TTS cache behavior:
- server cache lives under
data/tts_cache/; - cache keys include provider, model, voice, safe speed, and text;
- cache files are stored as MP3 or WAV;
- route stats expose global cache state;
- cache clear is global;
- frontend TTS has a separate object-URL cache.
Security And Provenance
Speech routes rely on app-wide authentication and do not implement route-local admin or scope checks. Bearer-token callers that pass app auth can reach speech stats/synthesis/transcription/cache-clear surfaces using global speech settings.
Endpoint providers send user audio or assistant text to configured ModelEndpoint URLs with optional bearer keys. Endpoint lookup is by configured endpoint ID and currently does not enforce per-request owner filtering. ModelEndpoint.api_key is encrypted at rest and forwarded only process-side.
Microphone audio, uploaded audio, endpoint transcripts, and assistant text sent to TTS are untrusted/user/provider-visible data flows. Transcripts become user input; they are not trusted system instructions.
TTS cached audio can contain sensitive assistant text rendered as speech. The cache is global, has no owner partition or TTL, and is served inline/base64 by POST responses without a dedicated generated-file route.
Degraded Behavior
- Optional local speech packages may be absent.
- Local STT can run CPU-only and tolerates missing/broken torch by falling back to CPU/int8 behavior.
- Local TTS/Kokoro is unavailable without CUDA/imports.
- External endpoint providers can be offline or misconfigured and may only fail at request time.
- Browser
speechSynthesis,SpeechRecognition,webkitSpeechRecognition, secure context, and microphone permissions can be absent. - Docker GPU overlays are passthrough-only and do not install speech engines by themselves.
- Optional dependency errors and route error wording are not fully consistent across STT and TTS.
Testing Coverage
Existing coverage includes test_speech_service_toggles, malformed/non-string TTS provider and speed handling, test_tts_cache_stats, test_stt_leak, test_direct_upload_limits, test_model_routes, and settings scrub coverage. A focused audit run of those relevant tests passed.
Missing coverage includes route-level STT/TTS success and failure shapes, auth/API-token behavior, endpoint owner isolation, STT type/magic rejection, TTS request-size/no-store/cache privacy behavior, degraded optional dependency paths, and frontend recorder/TTS fallback states.
Current Gaps
- Visible speech settings UI is incomplete relative to backend settings.
- Optional Kokoro dependencies are mentioned by service errors but are not declared in
requirements-optional.txt. - Speech routes need a deliberate API-token/scope policy.
- Endpoint speech providers need owner-isolation or explicit global-settings documentation.
- TTS cache needs privacy policy: owner partition, TTL, no-store response headers, or accepted global cache semantics.
- STT upload validation needs content type/extension/magic-byte policy.
- Browser/compare STT mic behavior needs a product decision or regression test because compare can force send-button visuals while shared empty-input logic can start recording.