import base64 import httpx2 from app.config import SARVAM_API_KEY class SarvamClient: _client = None def __init__(self): self.api_key = SARVAM_API_KEY self.base_url = "https://api.sarvam.ai" def _get_client(self) -> httpx2.AsyncClient: if SarvamClient._client is None: SarvamClient._client = httpx2.AsyncClient( timeout=12.0, limits=httpx2.Limits(max_keepalive_connections=5, max_connections=10), ) return SarvamClient._client async def speech_to_text( self, audio_bytes: bytes, filename: str = "audio.webm", language_code: str = "ta-IN", ) -> str: if not self.api_key or self.api_key == "your_sarvam_key": return "" client = self._get_client() files = {"file": (filename, audio_bytes, "audio/webm")} data = {"model": "saaras:v2", "language_code": language_code} headers = {"api-subscription-key": self.api_key} try: res = await client.post( f"{self.base_url}/speech-to-text", files=files, data=data, headers=headers, ) if res.status_code == 200: return res.json().get("transcript", "").strip() except Exception as e: print(f"[Sarvam STT Error]: {e}") return "" async def text_to_speech( self, text: str, language_code: str = "ta-IN", ) -> bytes | None: if not self.api_key or self.api_key == "your_sarvam_key": return None lang_prefix = language_code.lower()[:2] speaker = "kavya" client = self._get_client() headers = { "api-subscription-key": self.api_key, "Content-Type": "application/json", } payload = { "inputs": [text], "target_language_code": language_code, "speaker": speaker, "model": "bulbul:v2", } try: res = await client.post( f"{self.base_url}/text-to-speech", json=payload, headers=headers, ) if res.status_code == 200: audios = res.json().get("audios", []) if audios: return base64.b64decode(audios[0]) except Exception as e: print(f"[Sarvam TTS Error]: {e}") return None