Spaces:
Sleeping
Sleeping
File size: 1,457 Bytes
bf6e45c 97e667f bf6e45c 97e667f bf6e45c 97e667f bf6e45c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | from typing import Literal
from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import Response
from pydantic import BaseModel, Field
from services.auth import require_service_key
from services.tts_service import synthesize, is_available, backend_status
router = APIRouter(prefix="/tts", tags=["tts"])
class TtsRequest(BaseModel):
text: str = Field(..., min_length=1, max_length=1200)
voice: str | None = None
# "ogg" = Ogg/Opus (~10x smaller than WAV; not playable in Safari, so the
# client negotiates via canPlayType and asks for "wav" when needed).
format: Literal["wav", "ogg"] = "wav"
@router.get("/health")
def tts_health():
"""Reports whether Kokoro TTS is installed/usable and which backend runs it."""
return {"available": is_available(), "backend": backend_status()}
@router.post("", dependencies=[Depends(require_service_key)])
def tts(req: TtsRequest):
"""
Synthesize interviewer speech with Kokoro. Returns audio (WAV or Ogg/Opus)
on success, or 503 when TTS is unavailable so the caller falls back to
browser speech. Responses are LRU-cached per (text, voice, format).
"""
try:
audio, mime = synthesize(req.text, req.voice, req.format)
return Response(content=audio, media_type=mime)
except Exception as e: # noqa: BLE001 — TTS is optional; never hard-fail
raise HTTPException(status_code=503, detail=f"TTS unavailable: {e}")
|