"""Utility functions for managing voice references and profiles.""" import os import logging import torch import torchaudio import shutil from typing import Dict, List, Optional, Any logger = logging.getLogger(__name__) # Define persistent paths VOICE_REFERENCES_DIR = "/app/voice_references" VOICE_PROFILES_DIR = "/app/voice_profiles" VOICE_MEMORIES_DIR = "/app/voice_memories" # Ensure directories exist os.makedirs(VOICE_REFERENCES_DIR, exist_ok=True) os.makedirs(VOICE_PROFILES_DIR, exist_ok=True) os.makedirs(VOICE_MEMORIES_DIR, exist_ok=True) def backup_voice_data(backup_dir: str = "/app/voice_backups"): """Create a backup of all voice data.""" os.makedirs(backup_dir, exist_ok=True) timestamp = torch.datetime.now().strftime("%Y%m%d_%H%M%S") backup_path = os.path.join(backup_dir, f"voice_backup_{timestamp}") os.makedirs(backup_path, exist_ok=True) # Backup voice references if os.path.exists(VOICE_REFERENCES_DIR): refs_backup = os.path.join(backup_path, "voice_references") shutil.copytree(VOICE_REFERENCES_DIR, refs_backup) # Backup voice profiles if os.path.exists(VOICE_PROFILES_DIR): profiles_backup = os.path.join(backup_path, "voice_profiles") shutil.copytree(VOICE_PROFILES_DIR, profiles_backup) # Backup voice memories if os.path.exists(VOICE_MEMORIES_DIR): memories_backup = os.path.join(backup_path, "voice_memories") shutil.copytree(VOICE_MEMORIES_DIR, memories_backup) logger.info(f"Voice data backed up to {backup_path}") return backup_path def restore_default_voices(): """Reset voices to their default state by removing existing voice data.""" for voice_dir in [VOICE_REFERENCES_DIR, VOICE_PROFILES_DIR, VOICE_MEMORIES_DIR]: if os.path.exists(voice_dir): # Create a backup before deleting backup_path = backup_voice_data() # Remove existing data for item in os.listdir(voice_dir): item_path = os.path.join(voice_dir, item) if os.path.isdir(item_path): shutil.rmtree(item_path) else: os.remove(item_path) logger.info(f"Removed existing voice data from {voice_dir}") logger.info(f"Voices reset to default state (backup created at {backup_path})") return backup_path def verify_voice_references(): """Check if voice references are complete and valid.""" standard_voices = ["alloy", "echo", "fable", "onyx", "nova", "shimmer"] missing_voices = [] for voice in standard_voices: voice_dir = os.path.join(VOICE_REFERENCES_DIR, voice) # Check if directory exists and contains reference files if not os.path.exists(voice_dir) or len(os.listdir(voice_dir)) == 0: missing_voices.append(voice) return { "complete": len(missing_voices) == 0, "missing_voices": missing_voices, "references_dir": VOICE_REFERENCES_DIR } def get_voice_storage_info() -> Dict[str, Any]: """Get information about voice storage usage and status.""" result = { "voice_references": { "path": VOICE_REFERENCES_DIR, "exists": os.path.exists(VOICE_REFERENCES_DIR), "voices": [], "total_size_mb": 0 }, "voice_profiles": { "path": VOICE_PROFILES_DIR, "exists": os.path.exists(VOICE_PROFILES_DIR), "file_count": 0, "total_size_mb": 0 }, "voice_memories": { "path": VOICE_MEMORIES_DIR, "exists": os.path.exists(VOICE_MEMORIES_DIR), "voices": [], "total_size_mb": 0 } } # Get voice references info if result["voice_references"]["exists"]: for voice in os.listdir(VOICE_REFERENCES_DIR): voice_dir = os.path.join(VOICE_REFERENCES_DIR, voice) if os.path.isdir(voice_dir): file_count = len([f for f in os.listdir(voice_dir) if f.endswith('.wav')]) dir_size = sum(os.path.getsize(os.path.join(voice_dir, f)) for f in os.listdir(voice_dir) if os.path.isfile(os.path.join(voice_dir, f))) result["voice_references"]["voices"].append({ "name": voice, "file_count": file_count, "size_mb": dir_size / (1024 * 1024) }) result["voice_references"]["total_size_mb"] += dir_size / (1024 * 1024) # Get voice profiles info if result["voice_profiles"]["exists"]: files = [f for f in os.listdir(VOICE_PROFILES_DIR) if os.path.isfile(os.path.join(VOICE_PROFILES_DIR, f))] result["voice_profiles"]["file_count"] = len(files) result["voice_profiles"]["total_size_mb"] = sum(os.path.getsize(os.path.join(VOICE_PROFILES_DIR, f)) for f in files) / (1024 * 1024) # Get voice memories info if result["voice_memories"]["exists"]: files = [f for f in os.listdir(VOICE_MEMORIES_DIR) if os.path.isfile(os.path.join(VOICE_MEMORIES_DIR, f))] result["voice_memories"]["voices"] = [f.replace('.pt', '') for f in files if f.endswith('.pt')] result["voice_memories"]["total_size_mb"] = sum(os.path.getsize(os.path.join(VOICE_MEMORIES_DIR, f)) for f in files) / (1024 * 1024) return result