Commit graph

51 commits

Author SHA1 Message Date
831b937fd1
F5-TTS: per-chunk silence trim + fade (port from VoiceClone) + restore per-sentence streaming 2026-05-24 11:39:49 -04:00
fc5af2b653
F5-TTS: drop per-sentence split — single infer() call avoids ref-to-gen artifact per chunk 2026-05-24 11:12:57 -04:00
2df34f85cc
Add F5-TTS as tts-1-f5 engine (additive, alongside tts-1-qwen) 2026-05-23 13:24:25 -04:00
16b281bab4 Add webm response format (opus in webm container)
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.
2026-01-27 09:28:38 -05:00
8f7f1318a1 Split on every sentence for streaming (no combining) 2026-01-26 19:52:41 -05:00
0a0d023517 Fix sentence splitter to split on every sentence boundary
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.
2026-01-26 19:41:44 -05:00
802eaf2b29 Add sentence-by-sentence streaming for Qwen TTS
Split text into sentences and stream each as it's generated,
so first audio arrives much faster for long text.
2026-01-26 19:32:51 -05:00
a148088cb0 Fix Qwen TTS deadlock, reduce workers to 1 for GPU
- 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
2026-01-26 19:14:19 -05:00
b315659be6 Make Qwen3-TTS the default engine, add CPU-only docker support
- Switch default TTS engine from Piper to Qwen3-TTS (1.7B params)
- Upgrade to Python 3.12
- Add docker-compose.cpu.yml for CPU-only deployments
- Improve GPU configuration with NVIDIA environment variables
- Comment out optional engines (Piper, XTTS, Silero, Kokoro) in requirements
- Update Makefile with local/local-cpu targets and venv support
- Simplify voice_to_speaker.default.yaml for Qwen3-TTS voices
- Update docs/MODELS.md with Qwen3-TTS documentation
- Add git commit guidelines to CLAUDE.md
2026-01-26 10:41:23 -05:00
7559e56d0c Standardize project naming to uncloseai-speech across all files
- 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
2025-11-10 05:23:34 -05:00
da8e960b2d Fix Kokoro defaulting to CPU in worker processes
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.
2025-11-10 04:22:53 -05:00
ae958d1bb6 Enable GPU acceleration for Kokoro TTS
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
2025-11-10 04:14:46 -05:00
4576afac39 Fix UnboundLocalError in cleanup function
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.
2025-11-10 04:01:39 -05:00
bb9823f6d0 🦝 Move XTTS imports to module level for worker processes
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.
2025-11-09 18:40:38 -05:00
be374409d6 🦝 Fix args being None in worker processes
**Problem:** Worker processes had `args = None` causing AttributeError
when accessing `args.xtts_device`, `args.use_deepspeed`, etc. This
broke all non-Piper TTS engines (Silero, Kokoro, XTTS).

**Root Cause:** `args` was parsed in `if __name__ == "__main__"` block
which only runs in parent process, not in uvicorn worker processes.

**Solution:** Created DefaultArgs class with sensible defaults for
worker processes. Main process still overrides these with actual
command-line arguments.

**Impact:** All TTS engines now work in worker processes.

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 18:22:19 -05:00
bc2071900c 🦝 Fix voice cache initialization in multiprocess workers
**Problem:** Voice-to-model cache was only initialized in parent process,
not in worker processes spawned by uvicorn workers=4. This caused ALL
voice auto-detection to fail with "Voice not found in any model" errors.

**Root Cause:** Cache initialization was in `if __name__ == "__main__"`
block, which only runs in the parent process. Worker processes import
the `app` object directly and don't execute the __main__ block.

**Solution:** Moved cache initialization to FastAPI `lifespan` context
manager, which runs during startup in EACH worker process. This ensures
every worker has the voice_to_model_cache and voices_cache populated.

**Impact:**
- Voice auto-detection now works in all 4 worker processes
- /v1/voices endpoint returns cached data in all workers
- All 227 voices can now be used without specifying model parameter

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 18:13:52 -05:00
aeebb69a8c 🦝 Fix uvicorn workers with import string
Workers require 'speech:app' import string, not app object directly
2025-11-09 17:10:08 -05:00
459e8d5896 🦝 Fix concurrency with multiprocess workers + semaphores
ROOT CAUSE: Python GIL prevents true concurrent execution
- asyncio.to_thread() still bound by GIL and limited thread pool
- Under load: 115+ threads exhausted default pool, server deadlocked
- ML models loading concurrently overwhelmed single-process server

SOLUTION:
1. Added uvicorn workers=4 for true multiprocess concurrency
   - Each worker = separate Python process with own GIL
   - Models loaded independently per worker
   - 4x capacity for concurrent requests

2. Added semaphores for model loading safety
   - silero_load_semaphore: Only 1 Silero load at a time per worker
   - kokoro_load_semaphore: Only 1 Kokoro load at a time per worker
   - Double-check pattern prevents race conditions

3. Increased timeout_keep_alive=300s for long model loads

IMPACT:
- Can now handle 100+ concurrent requests without deadlock
- Each worker independently serves requests during model loads
- Graceful degradation under extreme load
- Ready for production traffic

Alternative considered: Elixir/Phoenix with BEAM VM
- Would give millions of lightweight processes
- Better for massive scale (1000+ concurrent)
- Keep on roadmap for future if needed

Raccoon wisdom: Sometimes the solution is more processes, not more threads!
2025-11-09 16:44:06 -05:00
650ae49f65 🦝 Fix blocking model loads - enable concurrent TTS requests
Problem:
- Silero and Kokoro model initialization was blocking the FastAPI event loop
- First request to Silero downloads 54.5MB synchronously, blocking ALL requests
- No concurrent request handling - server frozen during model loads

Solution:
- Added asyncio import
- Wrapped blocking operations in asyncio.to_thread():
  * silero_wrapper() initialization (torch.hub.load download)
  * kokoro_wrapper() initialization
  * silero_model.tts() generation
  * kokoro_pipeline.tts() generation

Impact:
- Concurrent requests now work - fast models don't wait for slow ones
- Model loading runs in thread pool, freeing event loop
- Multiple users can make requests simultaneously
- First Silero request still takes time, but doesn't block other engines

Related to: User reported timeout issues with deployed TTS service
Raccoon Mission: Production-ready concurrent TTS serving
2025-11-09 16:05:12 -05:00
21e8f27519 🦝 Fix /v1/voices timeout by caching response data at startup
- Problem: /v1/voices endpoint was reading and parsing 800+ line YAML file on every request
- This caused 30+ second timeouts with 227 voices across 4 TTS engines
- Solution: Cache the entire response structure at startup (same pattern as voice_to_model_cache)
- Added voices_cache global variable populated during startup
- Endpoint now returns instantly from memory (< 1ms instead of 30+ seconds)
- Includes fallback for safety but should never execute

Performance impact:
- Before: O(n) YAML parse + dict construction on every request
- After: O(1) memory lookup from pre-built cache
- Startup time: +negligible (runs once alongside existing voice_to_model_cache)

Related to Raccoon Mission: Fast API responses essential for production TTS service
2025-11-09 15:58:01 -05:00
d8b9a06b45 Add voice-based model auto-detection and voice discovery endpoint
Features:
- Optional model parameter in /v1/audio/speech - auto-detects from voice name
- Voice-to-model cache loaded at startup for fast O(1) lookups
- First-match strategy for duplicate voice names across models
- New /v1/voices endpoint with extended voice info (engine, sample_rate, voice count)
- /v1/models kept OpenAI-compatible (minimal fields)

Implementation:
- speech.py:274: Made model parameter Optional[str] = None
- speech.py:253-260: Added detect_model_from_voice() using cached mapping
- speech.py:42: Added voice_to_model_cache global dict
- speech.py:723-732: Cache initialization at startup (227 voices)
- speech.py:336-383: New /v1/voices endpoint with voice lists and metadata
- speech.py:401-408: Auto-detection logic when model is None

Tested:
- bm_george auto-detected to tts-1-kokoro (unique voice)
- alloy auto-detected to tts-1 (first match of duplicate)
- /v1/models returns OpenAI-compatible minimal format
- /v1/voices returns extended info for all 4 models

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 14:45:06 -05:00
9b5caadb8f Fix Kokoro TTS integration - correct KPipeline API
- Removed model_path parameter (not supported by kokoro package)
- Removed repo_id parameter (causes KeyError)
- Use default KPipeline initialization with only lang_code
- Kokoro package handles model download automatically

Tested and working:
- American English voices (alloy, af_sarah, am_michael, etc.)
- British English voices (bm_george, bf_emma, etc.)
- Audio generation produces valid MP3 files

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 14:20:09 -05:00
603a211f47 Add /v1/models endpoint for voice discovery
- Implemented GET /v1/models endpoint
- Returns list of all TTS models with metadata
- Includes voice lists for each model
- Provides engine-specific information (sample rate, description)
- Enables frontend voice discovery and model type mapping

Response format:
{
  "object": "list",
  "data": [
    {
      "id": "tts-1",
      "engine": "piper",
      "description": "Fast neural TTS with 100+ voices",
      "sample_rate": 22050,
      "voices": [...],
      "voice_count": 40
    },
    ...
  ]
}

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 13:51:59 -05:00
d48fa6b29c Integrate Kokoro TTS as tts-1-kokoro model
- Added kokoro>=0.9.2 and soundfile to requirements.txt
- Created kokoro_wrapper class for 24kHz decoder-only TTS
- Added tts-1-kokoro endpoint with full voice mapping
- Mapped 32 Kokoro voices (11 female American, 9 male American, 4 female British, 4 male British, 4 Spanish, etc.)
- Added OpenAI-compatible aliases (alloy, echo, fable, onyx, nova, shimmer)
- Lightweight 82M parameter model, Apache licensed

Voices:
- American English (lang_code 'a'): 20 voices
- British English (lang_code 'b'): 8 voices
- Supports 9 languages total (a, b, e, f, h, i, j, p, z)

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 13:38:42 -05:00
20241632ea Fix Silero multilingual support with proper model loading
- 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>
2025-11-09 13:29:52 -05:00
01e51b08b5 🦝 Raccoon Mission: Silero TTS integration complete with 140 voices
 Integrated Silero TTS as tts-1-silero model
- Fixed omegaconf dependency
- Fixed Silero API integration (torch.hub.load returns 2 values)
- Fixed model.to(device) returning None bug
- Mapped all 140 Silero voices across 5 languages:
  * English (en): 118 speakers (en_0 to en_117) + random
  * Russian (ru): 5 speakers (aidar, baya, kseniya, xenia, eugene) + random
  * German (de): 5 speakers (bernd_ungerer, eva_k, friedrich, hokuspokus, karlsson) + random
  * Spanish (es): 3 speakers (es_0, es_1, es_2) + random
  * French (fr): 6 speakers (fr_0 to fr_5) + random

📝 Configuration changes:
- requirements.txt: Added omegaconf for Silero
- voice_to_speaker.default.yaml: All 140 Silero voices mapped
- speech.py: Silero wrapper class with proper API handling

🎯 Working TTS engines: 3
- Piper TTS (tts-1) - Fast, lightweight
- XTTS v2 (tts-1-hd) - High quality, voice cloning
- Silero TTS (tts-1-silero) - CPU-friendly, 5 languages, actively maintained

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 12:39:12 -05:00
4deedb9539 Fix syntax error in speech.py and document Chatterbox dependency conflict
- Fixed f-string syntax error in speech.py line 112 (unmatched parenthesis)
- Documented Chatterbox dependency conflict with Coqui TTS
- gradio 5.44.1 (Chatterbox) requires typer<1.0 and >=0.12
- spacy 3.6.x (Coqui TTS) requires typer<0.10.0 and >=0.3.0
- Commented out Chatterbox until conflict is resolved

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 10:49:34 -05:00
Claude
848c2c6cb5 Integrate Silero TTS and add infrastructure for Chatterbox/Kokoro
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
2025-11-09 10:48:44 -05:00
2c6c1ad577 Add XTTS support to Makefile and create CLAUDE.md guide
Makefile improvements:
- Add voices-xtts target to download speaker samples
- Add test-xtts target for testing HD model
- Split voices into voices-piper and voices-xtts
- Update help text with all new targets

speech.py:
- Fix threading import scope issue for XTTS
- Remove redundant 'import threading' inside Piper block

docs/CLAUDE.md:
- Complete guide for Claude Code contributors
- Makefile-first development philosophy
- Never create dirs manually, always use Makefile
- Documentation requirements and testing philosophy
- Common mistakes to avoid
- Raccoon mission values and principles

This ensures consistent, repeatable deployments and makes it easy
to add new TTS engines following the same pattern.

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 09:52:13 -05:00
4aebcc037f Rebrand project to UncloseAI Speech
Renamed all references from openedai-speech to uncloseai-speech across
the entire codebase, including:
- Project name in README and documentation
- Docker image names in compose files
- Makefile deployment paths and container names
- Configuration examples in vars.sh.example

This establishes our raccoon mission fork as UncloseAI Speech, a unified
TTS system supporting multiple engines (Piper, XTTS, etc.) with OpenAI
API compatibility.

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 09:11:09 -05:00
eb899deca2 Fix Piper TTS absolute path resolution and improve deployment workflow
This commit resolves the "download entire voices" issue by properly handling
absolute paths in Piper model configuration and improves the deployment system.

Key changes:
- speech.py: Detect absolute paths and omit --data-dir/--download-dir flags
  when using absolute model paths, allowing Piper to load models directly
- speech.py: Add debug logging and stderr capture for Piper subprocess
- voice_to_speaker.default.yaml: Use absolute paths for all Piper models
- Makefile: Load deployment config from vars.sh for better security
- Makefile: Change restart to rebuild container ensuring code updates apply
- Add vars.sh.example template for deployment configuration
- .gitignore: Add vars.sh to prevent committing deployment secrets

Tested successfully with en_US-libritts_r-medium model using absolute path:
/app/voices/en/en_US/libritts_r/medium/en_US-libritts_r-medium.onnx

🦝 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 09:05:13 -05:00
matatonic
e815ef2860 0.18.0 - Allow multiple samples in xtts. Closes: #38 2024-08-15 17:19:34 -04:00
matatonic
c51355ca38 Fixes #35, detect configured sample rates for piper 2024-08-14 21:25:57 -04:00
matatonic
43dbf431f8 unbreak -min 2024-07-01 20:38:44 -04:00
matatonic
fdd443b10f 0.17.1 2024-07-01 19:43:32 -04:00
book3
be02887ad9 using landetect to automatically set the language of the request in xtts
inference
2024-07-01 12:33:27 -03:00
matatonic
1d144a12e0 0.16.0 +Multi-client safe 2024-06-29 13:03:30 -04:00
matatonic
703dec32b1 0.15.2 Thread safe version 15 2024-06-28 16:09:48 -04:00
matatonic
964b23a21c 0.15.1 +Fixes #24, no deepspeed by default, you're on your own for now 2024-06-27 10:23:58 -04:00
matatonic
be759f3fea 0.15.0 2024-06-27 01:43:43 -04:00
matatonic
c957ad86fc 0.14.1 +deepspeed (not in prebuilt docker) 2024-06-27 00:47:56 -04:00
matatonic
ae6a384e75 0.14.0 +streaming, +pcm, +wav, +temp, top_p, etc. 2024-06-26 20:54:24 -04:00
matatonic
34bf525c89 0.13.0 final 2024-06-25 17:20:28 -04:00
matatonic
72c7b799b9 xtts: +AMD gpu ROCm, +Apple MPS 2024-06-24 20:35:07 -04:00
matatonic
ea4af74e5c 0.13.0 -parler, +arm64, +audio_reader 2024-06-23 12:52:03 -04:00
matatonic
f21ed56a00 0.12.0 - Improved errors & logging, swap alloy default voice
closes #3, re: #11
2024-06-16 23:35:11 -04:00
matatonic
2fcb7cef0f 0.11.0 - Multilingual, new startup & dockerfiles, Fixes: #5, #6, #8, #9 2024-05-29 17:01:11 -04:00
matatonic
6864cf03b1 0.10.0 2024-04-26 20:42:33 -04:00
matatonic
a2a3d2b3eb 0.9.0 + fix xtts not None 2024-04-23 22:35:03 -04:00
matatonic
4d76aca1af 0.9.0 2024-04-23 22:07:23 -04:00