From 8ce84e5523c9762dc134b19c8e85e5321e385623 Mon Sep 17 00:00:00 2001 From: mARTin-B78 Date: Tue, 9 Jun 2026 02:23:43 +0200 Subject: [PATCH] Fix voice_clone/streaming backends and POST /v1/audio/voices (port from -1 repo) - voice_clone and streaming now return active library voices instead of probing upstream /v1/models (which only exposed 8 model entries) - Accept POST on /v1/audio/voices for clients that probe with POST - Fall back to first active voice when voice field missing in /v1/audio/speech Co-Authored-By: Claude Sonnet 4.6 --- routes/tts.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/routes/tts.py b/routes/tts.py index 213d551..3cfee3d 100644 --- a/routes/tts.py +++ b/routes/tts.py @@ -254,7 +254,7 @@ def _active_library_voice_options(settings: dict) -> list[dict]: def _fetch_backend_voices(settings: dict, backend: str) -> list: backend = _clean_preview_backend(backend) - if backend in {"nvidia_zeroshot", "nvidia_flow"}: + if backend in {"voice_clone", "streaming", "nvidia_zeroshot", "nvidia_flow"}: return _active_library_voice_options(settings) tts_url = _validate_http_url(_preview_backend_base_url(settings, backend), allow_private=True).rstrip("/") key = (settings.get("voice_design_api_key") if backend == "voice_design" else settings.get("tts_api_key")) or "" @@ -683,7 +683,7 @@ async def openai_audio_models_proxy(): return await openai_models_proxy() -@router.get("/v1/audio/voices") +@router.api_route("/v1/audio/voices", methods=["GET", "POST"]) async def openai_audio_voices_proxy(): models = await openai_models_proxy() return [m["id"] for m in models["data"]] @@ -706,15 +706,17 @@ async def openai_speech_proxy(request: Request): text=text, error="input is required", ) raise HTTPException(400, "input is required") - if not voice: - _routing_log_request( - request, status="error", app=request_app, requested_voice=original_voice, - routed_voice=voice, backend="", route=None, response_format=response_format, - text=text, error="voice is required", - ) - raise HTTPException(400, "voice is required") - settings = _load_settings() + if not voice: + fallback = next((v["id"] for v in _active_library_voice_options(settings)), "") + if not fallback: + _routing_log_request( + request, status="error", app=request_app, requested_voice=original_voice, + routed_voice=voice, backend="", route=None, response_format=response_format, + text=text, error="voice is required", + ) + raise HTTPException(400, "voice is required") + voice = fallback voice, route = _resolve_tts_route(request_app, voice, text) backend = _route_backend(route, voice) style_instruction = str(data.get("instruct") or data.get("style_instruction") or "")