a28f75994a
Kokoro has been stale upstream since April 2025 (`requires_python<3.13`), which broke the Python 3.14 build. Piper is the active replacement: maintained by OHF/Home Assistant, depends only on onnxruntime + pathvalidate (no torch, no spacy, no transformers), and has cp314 support today. Dockerfile: - Add `pip install piper-tts` after the STT install. - Bundle two default voices (en_US-amy-medium, en_US-ryan-medium) into /opt/piper-voices at build. Additional voices can be downloaded into /data/voices via the admin UI (separate commit). - Image add over the STT-only baseline: ~150 MB. services/tts.py — full rewrite: - New voice-discovery layer scans /opt/piper-voices + /data/voices for .onnx + .onnx.json pairs. /data wins over /opt for the same id so admin-downloaded voices can override bundled defaults. - Single PiperVoice kept warm; switches via _switch_voice() when the user changes their voice_tts_voice setting. - list_voices() returns metadata read from .onnx.json sidecars (label derived from filename, language, quality, sample_rate). - synthesise() uses piper's SynthesisConfig; converts kokoro-shaped `speed` multiplier to piper's `length_scale` (1.0 / speed). - `voice_blend` parameter accepted but ignored — piper has no blend equivalent; first entry's voice is used if anything is passed. - Dropped: HuggingFace commit-hash tracking (~80 lines), the daily check_for_kokoro_updates task, voice-tensor blending math. routes/voice.py: - tts_backend reports "piper" in /api/voice/status. - /api/voice/voices no longer requires tts_available() — even with the active voice failed to load, the catalog still lets the user pick a different one. - Synthesise request body dropped the voice_blend field; speed and voice still supported. alembic 0047_reset_voice_tts_settings: - Deletes any stored voice_tts_voice (kokoro IDs that don't map to piper) and voice_tts_blend (no piper equivalent) rows. Both re-default cleanly on next read. frontend: - VoiceBlendEntry type removed from api/client.ts. - synthesiseSpeech() signature dropped the voiceBlend parameter. - SettingsView.vue Voice Blend section removed entirely (slider, preview, slot management). voice_tts_blend save path removed. - Default voice id changed from "af_heart" to "en_US-amy-medium". - VoiceEntry gains optional language/quality/sample_rate fields from the richer piper sidecar metadata. Voice paths remain lazily guarded — `VOICE_ENABLED=false` (default) starts the app cleanly regardless of which TTS deps are present. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>