🦝 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
This commit is contained in:
parent
ac305c31d7
commit
21e8f27519
1 changed files with 56 additions and 1 deletions
57
speech.py
57
speech.py
|
|
@ -42,6 +42,9 @@ args = None
|
|||
# Voice-to-model lookup cache (loaded at startup)
|
||||
voice_to_model_cache = {}
|
||||
|
||||
# Cached voice data for /v1/voices endpoint (loaded at startup)
|
||||
voices_cache = None
|
||||
|
||||
def unload_model():
|
||||
import torch, gc
|
||||
global xtts
|
||||
|
|
@ -336,6 +339,15 @@ async def list_models():
|
|||
@app.get("/v1/voices")
|
||||
async def list_voices():
|
||||
"""List all available voices with model mapping and metadata (extended endpoint)"""
|
||||
global voices_cache
|
||||
|
||||
# Return cached data if available
|
||||
if voices_cache is not None:
|
||||
return voices_cache
|
||||
|
||||
# This should never happen since cache is populated at startup,
|
||||
# but provide fallback just in case
|
||||
logger.warning("/v1/voices called but cache not initialized - loading now")
|
||||
default_exists('config/voice_to_speaker.yaml')
|
||||
|
||||
with open('config/voice_to_speaker.yaml', 'r', encoding='utf8') as file:
|
||||
|
|
@ -377,11 +389,13 @@ async def list_voices():
|
|||
|
||||
models_data.append(model_info)
|
||||
|
||||
return {
|
||||
voices_cache = {
|
||||
"object": "list",
|
||||
"data": models_data
|
||||
}
|
||||
|
||||
return voices_cache
|
||||
|
||||
@app.post("/v1/audio/speech", response_class=StreamingResponse)
|
||||
async def generate_speech(request: GenerateSpeechRequest):
|
||||
global xtts, args
|
||||
|
|
@ -732,6 +746,47 @@ if __name__ == "__main__":
|
|||
voice_to_model_cache[voice_name] = model_id
|
||||
print(f"Voice-to-model cache initialized with {len(voice_to_model_cache)} voices")
|
||||
|
||||
# Build voices cache for /v1/voices endpoint
|
||||
models_data = []
|
||||
for model_id, voices in voice_map.items():
|
||||
if isinstance(voices, dict):
|
||||
voice_list = list(voices.keys())
|
||||
|
||||
model_info = {
|
||||
"id": model_id,
|
||||
"object": "model",
|
||||
"created": 1700000000,
|
||||
"owned_by": "uncloseai",
|
||||
"voices": voice_list,
|
||||
"voice_count": len(voice_list)
|
||||
}
|
||||
|
||||
# Add engine-specific metadata
|
||||
if model_id == 'tts-1':
|
||||
model_info["engine"] = "piper"
|
||||
model_info["description"] = "Fast neural TTS with 100+ voices"
|
||||
model_info["sample_rate"] = 22050
|
||||
elif model_id == 'tts-1-hd':
|
||||
model_info["engine"] = "xtts"
|
||||
model_info["description"] = "High-quality voice cloning TTS"
|
||||
model_info["sample_rate"] = 24000
|
||||
elif model_id == 'tts-1-silero':
|
||||
model_info["engine"] = "silero"
|
||||
model_info["description"] = "Fast multilingual TTS (en, ru, de, es, fr)"
|
||||
model_info["sample_rate"] = 48000
|
||||
elif model_id == 'tts-1-kokoro':
|
||||
model_info["engine"] = "kokoro"
|
||||
model_info["description"] = "Lightweight decoder-only TTS (82M params)"
|
||||
model_info["sample_rate"] = 24000
|
||||
|
||||
models_data.append(model_info)
|
||||
|
||||
voices_cache = {
|
||||
"object": "list",
|
||||
"data": models_data
|
||||
}
|
||||
print(f"/v1/voices cache initialized with {len(models_data)} models")
|
||||
|
||||
logger.remove()
|
||||
logger.add(sink=sys.stderr, level=args.log_level)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue