Murder.Ai / game /voice_manager.py
Justxd22's picture
Add voice generation and audio playback features using ElevenLabs API
5029863
import os
import random
from elevenlabs.client import ElevenLabs
class VoiceManager:
def __init__(self):
self.api_key = os.getenv("ELEVENLABS_API_KEY")
self.client = None
if self.api_key:
self.client = ElevenLabs(api_key=self.api_key)
# Archetype-based Voice Mapping
# We map the suspect's 'archetype' (from image metadata or role logic) or gender to these.
self.voices = {
"male": {
"executive": "ErXwobaYiN019PkySvjV", # Antoni (Polished)
"worker": "wI49R6YUU5NNP1h0CECc", # Josh (Casual)
"criminal": "VR6AewLTigWg4xSOukaG", # Arnold (Gravelly)
"artist": "D38z5RcWu1voky8WS1ja", # Fin (Expressive)
"default": "TxGEqnHWrfWFTfGW9XjX" # Josh
},
"female": {
"executive": "21m00Tcm4TlvDq8ikWAM", # Rachel (Professional)
"worker": "AZnzlk1XvdvUeBnXmlld", # Domi (Strong)
"socialite": "EXAVITQu4vr4xnSDxMaL", # Bella (Intense)
"artist": "nDJIICjR9zfJExIFeSCN", # Bella
"default": "6u6JbqKdaQy89ENzLSju" # Rachel
}
}
def assign_voice(self, gender, role=""):
"""Pick a voice based on gender and role archetype."""
g = "male" if gender.lower() == "male" else "female"
role = role.lower()
# Simple archetype matching logic (matches game_logic.js)
archetype = "default"
if "ceo" in role or "cfo" in role or "manager" in role or "dealer" in role:
archetype = "executive"
elif "janitor" in role or "chef" in role or "caterer" in role:
archetype = "worker"
elif "artist" in role or "curator" in role:
archetype = "artist"
elif "heir" in role or "collector" in role or "sister" in role:
archetype = "socialite"
elif "ex-" in role or "customer" in role:
archetype = "criminal"
# Return specific voice or random if not found?
# Better to return specific to ensure personality match.
voice_map = self.voices[g]
return voice_map.get(archetype, voice_map["default"])
def generate_audio(self, text, voice_id):
"""Generates audio bytes from text."""
if not self.client:
print("Warning: No ElevenLabs API Key. Skipping TTS.")
return None
try:
# Modern SDK usage
audio_generator = self.client.text_to_speech.convert(
text=text,
voice_id=voice_id,
model_id="eleven_monolingual_v1"
)
# Consolidate generator into bytes
audio_bytes = b"".join(audio_generator)
return audio_bytes
except Exception as e:
print(f"ElevenLabs Error: {e}")
return None