Spaces:
Running on Zero
Running on Zero
File size: 1,686 Bytes
88fe4e7 | 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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 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
|