#!/usr/bin/env python3 """ ai_voice_generator.py AI Voice Generation for DolinaSmrti using Edge-TTS NO RECORDING NEEDED - Pure AI! Characters: - Gronk: Deep, raspy, laid-back (English-UK-Ryan) - Ana: Mysterious, calm (English-US-Jenny) - Kai: Energetic, bold (English-US-Aria) Usage: python ai_voice_generator.py Created: Jan 10, 2026 Author: David "HIPO" Kotnik Studio: Hipodevil666 Studiosโ„ข """ import asyncio import os from pathlib import Path try: import edge_tts except ImportError: print("โŒ Error: edge-tts not installed!") print("Install it with: pip install edge-tts") exit(1) # Voice profiles for characters VOICE_PROFILES = { 'gronk': { 'voice': 'en-GB-RyanNeural', # Deep, laid-back British 'rate': '-10%', # Slower (laid back) 'pitch': '-5Hz', # Deeper 'volume': '+0%' }, 'ana': { 'voice': 'en-US-JennyNeural', # Calm, mysterious American 'rate': '-5%', # Slightly slower (mysterious) 'pitch': '+0Hz', # Normal 'volume': '+0%' }, 'kai': { 'voice': 'en-US-AriaNeural', # Energetic, bold American 'rate': '+10%', # Faster (energetic) 'pitch': '+2Hz', # Slightly higher 'volume': '+5%' # Louder (bold) }, 'npc_male': { 'voice': 'en-GB-ThomasNeural', # Generic male NPC 'rate': '+0%', 'pitch': '+0Hz', 'volume': '+0%' }, 'npc_female': { 'voice': 'en-US-SaraNeural', # Generic female NPC 'rate': '+0%', 'pitch': '+0Hz', 'volume': '+0%' } } # Output directory OUTPUT_DIR = Path('assets/audio/voice') # Key phrases for each character KEY_PHRASES = { 'gronk': [ "Gronk sorry... Gronk no mean to scare.", "Pink is best color! Make Gronk happy!", "Bubble Gum vape... ahhhh, tasty!", "Gronk help Kai! Gronk protect!", "Smash things? Gronk good at smash!", "Ana sister? Gronk help find!", "Old troll ways... rave culture... good times.", "System no change Gronk! Gronk change system!" ], 'ana': [ "Kai... can you hear me? It's Ana.", "I'm still here. Still fighting.", "They don't know what I've discovered.", "The cure is in my blood... literally.", "Twin bond... I can feel you searching.", "Don't give up on me, sister.", "Level seven. Reactor core. Hurry.", "I remember everything. Every moment." ], 'kai': [ "Who... who am I?", "This place feels... familiar?", "I won't give up. Someone's waiting for me.", "These memories... they're mine!", "Ana, I remember everything! Hold on!", "I'll tear down Chernobyl to find you!", "No more running. Time to fight!", "System won't change me. I change the system!" ] } async def generate_voice(text, character, filename): """Generate AI voice for text""" profile = VOICE_PROFILES.get(character) if not profile: print(f"โŒ Unknown character: {character}") return False voice = profile['voice'] rate = profile['rate'] pitch = profile['pitch'] volume = profile['volume'] # Full output path output_path = OUTPUT_DIR / character / filename output_path.parent.mkdir(parents=True, exist_ok=True) print(f"๐ŸŽ™๏ธ Generating: {character} - '{text[:50]}...'") print(f" Voice: {voice}") print(f" Output: {output_path}") try: # Create TTS communicator communicate = edge_tts.Communicate( text, voice, rate=rate, pitch=pitch, volume=volume ) # Save as MP3 first (Edge-TTS native format) mp3_path = output_path.with_suffix('.mp3') await communicate.save(str(mp3_path)) print(f" โœ… Generated: {mp3_path.name}") # Convert to OGG for game (using ffmpeg if available) ogg_path = output_path.with_suffix('.ogg') import subprocess try: subprocess.run([ 'ffmpeg', '-i', str(mp3_path), '-c:a', 'libvorbis', '-q:a', '5', '-y', str(ogg_path) ], check=True, capture_output=True) print(f" โœ… Converted: {ogg_path.name}") # Delete MP3 (keep only OGG) mp3_path.unlink() except (subprocess.CalledProcessError, FileNotFoundError): print(f" โš ๏ธ ffmpeg not found - keeping MP3 format") print(f" ๐Ÿ’ก Install ffmpeg: brew install ffmpeg") return True except Exception as e: print(f" โŒ Error: {e}") return False async def generate_all_voices(): """Generate all key phrases""" print("๐ŸŽ™๏ธ DolinaSmrti AI Voice Generator") print("=" * 60) print(f"Output: {OUTPUT_DIR}") print() # Create output directory OUTPUT_DIR.mkdir(parents=True, exist_ok=True) total = 0 success = 0 for character, phrases in KEY_PHRASES.items(): print(f"\n๐ŸŽญ CHARACTER: {character.upper()}") print("-" * 60) for i, text in enumerate(phrases, 1): filename = f"{character}_phrase_{i:02d}.ogg" if await generate_voice(text, character, filename): success += 1 total += 1 print() # Summary print("=" * 60) print("๐ŸŽ‰ Voice Generation Complete!") print() print(f"Total phrases: {total}") print(f"Successful: {success}") print(f"Failed: {total - success}") print() print("๐Ÿ“‚ Files saved to:") for character in KEY_PHRASES.keys(): char_dir = OUTPUT_DIR / character if char_dir.exists(): count = len(list(char_dir.glob('*.ogg'))) or len(list(char_dir.glob('*.mp3'))) print(f" - {char_dir}: {count} files") print() print("๐ŸŽฎ Ready for game integration!") async def generate_custom_phrase(character, text, filename=None): """Generate single custom phrase (for manual use)""" if not filename: # Auto-generate filename safe_name = text[:30].replace(' ', '_').replace('.', '').replace(',', '') filename = f"{character}_{safe_name}.ogg" return await generate_voice(text, character, filename) def main(): """Main entry point""" asyncio.run(generate_all_voices()) if __name__ == '__main__': main()