The prior docs claimed prod = 3090-ai running uncloseai-speech-server-1 via
docker compose. Reality (verified today): prod is bare python on the 4090
(ai.foxhop.net) using the f5-sidecar venv at /mnt/data/f5-sidecar/venv,
fronted by Caddy on 80/443. The container on 3090-ai exited 2 months ago and
docker compose v2 isn't installed there.
Cost of the drift today: one wrong-host deploy attempt that bounced off dead
infrastructure. This rewrites Production Deployment, Quick Production
Commands, Testing, When Things Break, and Common Mistakes to match reality.
Also drops hardcoded tmux window numbers (they shift) — every example now
reads <prod-window> with a reminder to rediscover via tmux-hosts.
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.
F5-TTS cloning quality depends on ref_text matching the prosody of ref_audio
(commas, periods, casing). Previous ref_texts were LibriSpeech ground-truth
labels: ALL CAPS, no punctuation — wrong signal for a flow-matching TTS
conditioned on text. Whisper hears what F5 will hear.
- scripts/whisper_refs.py — transcribe all wavs, rewrite
voice_to_speaker.default.yaml + cloned-voices/voices_metadata.json
in place. Also writes cloned-voices/whisper_refs.json sidecar.
- Makefile: whisper-refs target. Idempotent, rerun whenever
cloned-voices/ changes.
Run on a GPU host (4090/3090). ~30s for 40 short clips on a 4090.
Runs scripts/download_diverse_voices.py which pulls speaker samples
from LibriSpeech and assigns permanent human names via voice registry.
Works with venv or system python. Also adds Voices section to help.
- voice_registry.json: append-only registry with 50 name pools per gender,
locked speaker assignments, and multi-corpus support
- Rewrite download script to be registry-driven: loads registry, assigns
names deterministically (sorted by speaker ID), never changes existing
assignments
- Update docs/VOICES.md with registry system documentation
- Support --registry and --corpora CLI flags for multi-corpus downloads
Firefox MediaSource API supports audio/webm;codecs=opus but not
audio/ogg. Adding webm format lets Firefox clients use true
streaming playback via MediaSource instead of full buffering.
Previous version accumulated sentences until 500 chars, defeating
the purpose of streaming. Now splits on every sentence, only
combining very short sentences (<50 chars) with the next.
- Fix subprocess deadlock in Qwen TTS by using threading for stdin write
(prevents pipe buffer deadlock on large audio output)
- Set WORKERS=1 for GPU models to avoid VRAM duplication
(4 workers × 3GB model = OOM, 1 worker works fine)
- Update CLAUDE.md: use git push/pull instead of rsync for deployment
Explains source code requirements for network service operators,
practical compliance methods, and Raccoon Mission rationale.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace upstream ghcr.io/matatonic image references with local image names.
This was missed in the naming standardization commit 7559e56.
- docker-compose.yml: uncloseai-speech:local
- docker-compose.min.yml: uncloseai-speech-min:local
- docker-compose.rocm.yml: uncloseai-speech-rocm:local
- Add CHANGELOG.md with full version history (moved from README)
- Update all documentation to use lowercase 'uncloseai-speech' project name
- Update organization references to lowercase 'uncloseai' (not 'UncloseAI')
- Add Brand Identity section to docs/CLAUDE.md with naming guidelines
- Update speech.py argparse description to match branding
- Update README.md headers and sections with consistent naming
- Update all model documentation with consistent branding
Files updated:
- CHANGELOG.md (new file)
- README.md (changelog reference, server options, multilingual section)
- speech.py (--workers argument, branding in argparse)
- Makefile (header comment)
- docs/CLAUDE.md (Brand Identity section)
- docs/MODELS.md
- docs/MIRRORS.md
- docs/AUDIT.md
- docs/models/coqui-tts.md
- docs/research/tts-models-overview.md
Branding standard:
- Project: uncloseai-speech (lowercase, hyphenated)
- Organization: uncloseai (lowercase, one word)
🦝 Generated with Claude Code
The DefaultArgs class had xtts_device hardcoded to 'cpu', which meant
all uvicorn worker processes inherited this default instead of using
auto_torch_device() to detect GPU.
Changes:
- Set DefaultArgs.xtts_device to None initially
- Call auto_torch_device() after class definition to set default
- This ensures workers use GPU if available, not hardcoded CPU
- Fixed log message to show actual device being used (not args value)
- Log moved after device calculation for accuracy
This fixes Kokoro loading on CPU even when GPU is available.
Kokoro was hardcoded to use CPU, causing very slow generation times
(3+ minutes for long texts). Now Kokoro uses the same device as XTTS
(auto-detected as 'cuda' if available, otherwise 'cpu').
Changes:
- Add device parameter to kokoro_wrapper __init__ (defaults to 'cpu')
- Pass device to KPipeline constructor
- Use args.xtts_device when initializing Kokoro (same as XTTS)
- Add semaphore lock to prevent concurrent Kokoro model loading
- Log which device Kokoro is loading on
Performance improvement: ~60x faster on GPU vs CPU for long texts
The cleanup() callback was trying to delete generator_worker and
out_writer_worker unconditionally, but these variables are only
defined in certain code paths. This caused UnboundLocalError when
cleanup was called after requests that didn't create these workers.
Wrap the deletions in try/except blocks to handle cases where the
variables weren't created.
Worker processes need access to XTTS classes (ModelManager, XttsConfig,
Xtts, split_sentence, detect) but were only imported conditionally in
__main__ block.
**Solution:** Import at module level with try/except for graceful
degradation in minimal installations. Set XTTS_AVAILABLE flag.
This ensures worker processes can handle tts-1-hd requests properly.