Spaces:
Running
Running
| import asyncio | |
| import httpx | |
| from app.core.exceptions import GenerationError | |
| class TTSClient: | |
| def __init__(self, tts_space_url: str, timeout_seconds: float) -> None: | |
| self._tts_space_url = tts_space_url.rstrip("/") | |
| self._timeout_seconds = timeout_seconds | |
| def is_configured(self) -> bool: | |
| return bool(self._tts_space_url) | |
| async def synthesize(self, text: str, voice: str = "am_adam") -> bytes: | |
| if not self.is_configured: | |
| raise GenerationError("TTS client is not configured") | |
| async def _call() -> bytes: | |
| async with httpx.AsyncClient(timeout=self._timeout_seconds) as client: | |
| response = await client.post( | |
| f"{self._tts_space_url}/synthesize", | |
| json={"text": text, "voice": voice}, | |
| headers={"Content-Type": "application/json"}, | |
| ) | |
| response.raise_for_status() | |
| audio_bytes = response.content | |
| if not audio_bytes: | |
| raise GenerationError("TTS response was empty") | |
| return audio_bytes | |
| try: | |
| return await asyncio.wait_for(_call(), timeout=self._timeout_seconds) | |
| except TimeoutError as exc: | |
| raise GenerationError("TTS request timed out") from exc | |
| except httpx.HTTPStatusError as exc: | |
| raise GenerationError( | |
| "TTS upstream returned an error", | |
| context={"status_code": exc.response.status_code}, | |
| ) from exc | |
| except GenerationError: | |
| raise | |
| except Exception as exc: | |
| raise GenerationError("TTS synthesis failed", context={"error": str(exc)}) from exc | |