# backend/voice/elevenlabs_tts.py import httpx from config import ELEVENLABS_API_KEY, VOICE_ID_AGENT_A, VOICE_ID_AGENT_B async def generate_voice_summary(text: str, negotiation_id: str, voice_id: str = None) -> str: """Generate TTS MP3 and return file path. Returns None on failure.""" voice_id = voice_id or VOICE_ID_AGENT_A try: async with httpx.AsyncClient() as client: response = await client.post( f"https://api.elevenlabs.io/v1/text-to-speech/{voice_id}", headers={"xi-api-key": ELEVENLABS_API_KEY, "Content-Type": "application/json"}, json={ "text": text[:500], # Budget cap "model_id": "eleven_flash_v2_5", "voice_settings": {"stability": 0.5, "similarity_boost": 0.75} }, timeout=30.0 ) if response.status_code == 200: import tempfile, os voice_dir = os.path.join(tempfile.gettempdir(), "negot8_voice") os.makedirs(voice_dir, exist_ok=True) filepath = os.path.join(voice_dir, f"voice_{negotiation_id}.mp3") with open(filepath, "wb") as f: f.write(response.content) return filepath except Exception as e: print(f"Voice TTS failed: {e}") return None # Voice summary templates VOICE_TEMPLATES = { "expenses": "Expenses settled! After {rounds} rounds, {payer} owes {payee} {amount} rupees. A UPI payment link has been sent.", "collaborative": "Decision made! You're going to {choice}. Your agents found the perfect match in {rounds} rounds.", "scheduling": "Meeting scheduled for {date} at {time}, {location}. Agreed in {rounds} rounds.", "marketplace": "Deal done! {item} for {price} rupees. Payment link is ready.", "trip": "Trip planned! {destination} on {dates}, {budget} per person.", "freelance": "Project agreed! {scope} for {budget} rupees. First milestone payment ready via UPI.", "roommate": "Decision made! {option}. Cost split arranged.", "conflict": "Resolution reached! {summary}.", } def build_voice_text(feature_type: str, resolution: dict) -> str: template = VOICE_TEMPLATES.get(feature_type, "Negotiation resolved! Check Telegram for details.") try: return template.format(**resolution)[:500] except KeyError: summary = resolution.get("summary", "resolved") return f"Your {feature_type} negotiation is complete: {summary}"[:500]