Slot 41 intentionally empty (Hitchhiker tribute). Voice is self-recorded by
speaker, AGPL-cleared, registered in voice_registry.json under new
`self-recorded` corpus. ref_text is a placeholder pending `make whisper-refs`
on a GPU host.
cloned-voices/foxhop.wav 313K mono 16kHz s16 PCM, ~10s, -3dBFS peak
voice_registry.json +foxhop entry, +self-recorded corpus
voice_to_speaker.default.yaml +foxhop block in tts-1-qwen and tts-1-f5
cloned-voices/voices_metadata.json +foxhop entry
normalize_text() handles three Whisper quirks that produced messy F5
ref_texts:
1. Lowercase output with no terminal period — capitalize first letter,
append "." if missing.
2. Hallucinated "' clusters Whisper inserts when it interprets a
fragment as quoted dialogue (cora, ivan, atlas, hope had these).
Strip everywhere; never legitimate English punctuation.
3. Trailing apostrophe-then-period (.'.) from earlier rounds where a
closing-quoted line got an extra "." appended — collapse to single
terminal. Function is now idempotent.
Adds --from-cache flag: skip ASR, re-apply normalize from cached
whisper_refs.json. No GPU needed, useful after tuning the normalizer.
Lazy-imports torch so --from-cache works on any host.
Affects 9 of 40 voices: clara, grace, hazel, iris, felix, hugo
(lowercase fix); cora, ivan, atlas, hope (quote-cluster fix).
Previous ref_texts were LibriSpeech dataset labels (ALL CAPS, no
punctuation). F5-TTS conditions on ref_text to align reference audio
prosody — commas, periods, casing matter. Now using whisper-large-v3
transcripts of the actual cloned-voices/*.wav files.
Generated via: make whisper-refs (on a GPU host).
Affects all 40 voices in both tts-1-f5 and tts-1-qwen engine blocks.
Sidecar cloned-voices/whisper_refs.json kept for traceability.
- Removed arbitrary OpenAI voice mappings from tts-1-silero (alloy→en_0, etc.)
- Kept intentional OpenAI-themed voices in tts-1-kokoro (af_alloy, am_echo, etc.)
- Silero's en_0-en_5 were random selections, not designed to match OpenAI voices
- Kokoro's af_alloy, am_echo, etc. are intentionally OpenAI-compatible by design
- Users can still access all voices by their native names
- Dropdown UI shows model name to differentiate duplicate voice names
🦝 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Fixed Silero model caching to track language+speaker combination
- Updated Russian voices to use ru_v3 model (was v4_ru)
- Updated Spanish voices to use v3_es model (was v1_es)
- All model loading now properly switches between languages
Status:
✅ English (v3_en) - 119 voices working
✅ German (v3_de) - 6 voices working
✅ French (v3_fr) - 7 voices working
⚠️ Russian (ru_v3) - Model loading issue (investigating speaker format)
⚠️ Spanish (v3_es) - Model loading issue (investigating speaker format)
🦝 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
INTEGRATED: Silero TTS (tts-1-silero)
- Added silero_wrapper class to speech.py for PyTorch Hub integration
- CPU-friendly, no GPU required (48kHz sample rate)
- Supports 5 languages: English (117 speakers), Russian, German, Spanish, French
- Loads on-demand via torch.hub from snakers4/silero-models
- Added 6 OpenAI-compatible voice mappings (alloy, echo, fable, etc.)
PREPARED: Chatterbox & Kokoro TTS
- Added dependencies to requirements.txt:
* git+https://github.com/resemble-ai/chatterbox.git
* transformers>=4.35.0 (for Kokoro)
* huggingface-hub[cli] (for model downloads)
- Created Makefile targets for downloading models
- Created test targets for all three new engines
Makefile Enhancements:
- make voices-silero: Download Silero models (en, ru, de, es, fr)
- make test-silero: Test Silero TTS endpoint
- make voices-chatterbox: Download Chatterbox models via HF CLI
- make test-chatterbox: Test Chatterbox with emotion control
- make voices-kokoro: Download Kokoro models via HF CLI
- make test-kokoro: Test Kokoro fast synthesis
speech.py Changes:
- Added silero_wrapper class with tts() method
- Added tts-1-silero model handler in generate_speech()
- Registered tts-1-silero model in app
- Added PCM media type for Silero (48000 Hz)
- Global state: silero_model, silero_speakers dict
Configuration:
- Updated voice_to_speaker.default.yaml with tts-1-silero section
- Mapped all 6 OpenAI voices to Silero speakers (en_0 through en_5)
Documentation:
- Updated docs/MODELS.md: Silero marked as ✅ INTEGRATED
- Updated roadmap: Phase 1 task 3 completed
- Updated status footer: 3 models rescued
- Added integration examples and Makefile commands
Next Steps:
- Test Silero integration in Docker
- Implement Chatterbox emotion control engine
- Implement Kokoro fast decoder engine
SOLUTION FOUND! Piper requires ABSOLUTE paths to model files, not relative paths.
Changes:
- Update voice_to_speaker.default.yaml to use /app/voices/... absolute paths
- Update Makefile voices target to set absolute paths via sed
- Tested: Piper works with /app/voices/en/en_US/libritts_r/medium/en_US-libritts_r-medium.onnx
Root cause: PyPI piper-tts package doesn't auto-download voices or support
voice name resolution. Must use full absolute file paths.
Co-Authored-By: Claude <noreply@anthropic.com>