feat: Add OpenAI-compatible TTS endpoint and engines

- Implements POST /v1/audio/speech endpoint (OpenAI API compatible).
- Integrates Kokoro and XTTS engines (including dependencies and implementations).
- Updates main application to register new engines and router.
- Adds unit tests for OpenAI compatibility.
- Updates requirements.txt for new engines.
This commit is contained in:
2025-12-09 12:45:17 +01:00
parent c06fd677dc
commit fff0252d52
9 changed files with 985 additions and 3 deletions

View File

@ -20,15 +20,28 @@ import os
import base64
import shutil
import uvicorn
import logging
from app.config import settings
from app.engines.piper import PiperEngine
from app.engines.styletts import StyleTTSEngine
from app.engines.chattts import ChatTTSEngine
from app.engines.f5_tts import F5TTSEngine
from app.engines.kokoro import KokoroEngine
from app.engines.xtts import XTTSEngine
from app.utils.text import chunk_text
from app.utils.audio import concat_audio
from app.utils.cache import build_cache_key
from app.routers import openai_compatible
# Configure logging based on settings
logging.basicConfig(level=settings.LOG_LEVEL, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Explicitly configure uvicorn loggers
logging.getLogger("uvicorn.access").setLevel(settings.LOG_LEVEL)
logging.getLogger("uvicorn.error").setLevel(settings.LOG_LEVEL)
logging.getLogger("uvicorn.server").setLevel(settings.LOG_LEVEL)
# --- Master list of all possible engine classes. ---
ALL_ENGINES = {
@ -36,6 +49,8 @@ ALL_ENGINES = {
"styletts": StyleTTSEngine,
"chattts": ChatTTSEngine,
"f5-tts": F5TTSEngine,
"kokoro": KokoroEngine,
"xtts": XTTSEngine,
}
def create_app():
@ -50,14 +65,17 @@ def create_app():
app.ENGINE_REGISTRY = {}
for engine_name in settings.ACTIVE_ENGINES:
if engine_name in ALL_ENGINES:
print(f"Activating engine: {engine_name}")
logger.info(f"Activating engine: {engine_name}")
app.ENGINE_REGISTRY[engine_name] = ALL_ENGINES[engine_name]()
else:
print(f"Warning: Engine '{engine_name}' requested in config but not found in ALL_ENGINES.")
logger.warning(f"Engine '{engine_name}' requested in config but not found in ALL_ENGINES.")
# Ensure the audio asset/cache directory exists.
os.makedirs(settings.AUDIO_CACHE_DIR, exist_ok=True)
# Register Routers
app.include_router(openai_compatible.router)
class TTSRequest(BaseModel):
text: str
engine: str
@ -197,6 +215,10 @@ def create_app():
On startup, check for the existence of the models directory.
This helps prevent race conditions with volume mounts.
"""
if os.getenv("SKIP_MODEL_CHECK", "false").lower() == "true":
logger.info("Skipping model directory check (SKIP_MODEL_CHECK=true)")
return
model_path = "/models/piper"
max_retries = 10
retry_delay = 2 # seconds