personabot-api / app /services /tts_client.py
GitHub Actions
Deploy 2e8cff3
c44df3b
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
@property
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