SightLine / src /speech /tts.py
LovnishVerma's picture
Upload 42 files
88fe4e7 verified
Raw
History Blame Contribute Delete
1.69 kB
import asyncio
import threading
import tempfile
from typing import Optional
import edge_tts
from src.config import CONFIG
# Voice mappings for supported locales
VOICE_MAP = {
"English (US) - Aria": "en-US-AriaNeural",
"English (US) - Guy": "en-US-GuyNeural",
"English (UK) - Sonia": "en-GB-SoniaNeural",
"Hindi - Swara": "hi-IN-SwaraNeural",
"Hindi - Madhur": "hi-IN-MadhurNeural",
}
def init_tts_loop() -> asyncio.AbstractEventLoop:
"""Create a dedicated event loop for TTS in a background thread."""
loop = asyncio.new_event_loop()
def _run():
asyncio.set_event_loop(loop)
loop.run_forever()
threading.Thread(target=_run, daemon=True).start()
return loop
_TTS_LOOP = init_tts_loop()
def text_to_speech(text: str, voice_name: str = "English (US) - Aria") -> Optional[str]:
"""Convert text to speech, returning the audio file path."""
if not text or not text.strip():
return None
try:
voice_id = VOICE_MAP.get(voice_name, "en-US-AriaNeural")
async def _generate():
with tempfile.NamedTemporaryFile(delete=False, suffix=f".{CONFIG.AUDIO_FORMAT}") as f:
path = f.name
communicate = edge_tts.Communicate(
text.strip(),
voice=voice_id,
rate=CONFIG.TTS_RATE,
)
await communicate.save(path)
return path
future = asyncio.run_coroutine_threadsafe(_generate(), _TTS_LOOP)
return future.result(timeout=CONFIG.TTS_TIMEOUT)
except Exception as e:
print(f"TTS error: {e}")
return None