"""Voice design presets: load, save, slug helpers.""" from __future__ import annotations import json import re from core.constants import CONFIG_DIR, DESIGN_PRESETS_FILE from core.database import state_get, state_put _DEFAULT_DESIGN_PRESETS = { "EN_M_Young_Energetic": { "description": "Young adult male voice, clear English, bright and energetic, moderately high pitch, quick but controlled speaking rate, confident and friendly, suitable for tutorials or streaming.", "sample_text": "Hey everyone, welcome back. Today we are going to move quickly, keep it clear, and make this setup feel easy.", "language": "English", "gender": "M", }, "EN_F_Warm_Narrator": { "description": "Adult female English narrator, warm and smooth, medium pitch, calm pace, gentle emotion, clear articulation, suited for audiobooks and voice assistant responses.", "sample_text": "The room grew quiet as the morning light touched the window, and for a moment everything felt simple and kind.", "language": "English", "gender": "F", }, "DE_M_Elderly_Documentary": { "description": "Aeltere maennliche deutsche Stimme, tief und resonant, langsam und gelassen, klar artikuliert, ruhig und dokumentarisch, mit serioeser und vertrauensvoller Praesenz.", "sample_text": "Seit vielen Jahren beobachten wir diesen Ort, seine Geschichte und die Menschen, die ihn mit Leben fuellen.", "language": "German", "gender": "M", }, "DE_F_Young_Friendly": { "description": "Junge weibliche deutsche Stimme, hell und freundlich, natuerliche Sprechgeschwindigkeit, klare Aussprache, leicht optimistisch und nahbar, passend fuer Assistenten und kurze Erklaerungen.", "sample_text": "Hallo, schoen dass du da bist. Ich zeige dir kurz, wie alles funktioniert, Schritt fuer Schritt.", "language": "German", "gender": "F", }, "EN_N_Old_Wise_Assistant": { "description": "Older neutral English voice, gentle and wise, slightly low pitch, slow measured pace, soothing tone, very clear pronunciation, calm personality for guidance and reflective narration.", "sample_text": "Take a slow breath. We will look at the facts carefully, choose the next step, and keep moving.", "language": "English", "gender": "N", }, } def _slug_voice_design_name(name: str) -> str: slug = re.sub(r"[^A-Za-z0-9_.-]+", "_", name.strip()).strip("._-") return slug or "VoiceDesign" def _load_design_presets() -> dict: presets = dict(_DEFAULT_DESIGN_PRESETS) if DESIGN_PRESETS_FILE.exists(): try: saved = json.loads(DESIGN_PRESETS_FILE.read_text()) if isinstance(saved, dict): for name, preset in saved.items(): if isinstance(preset, dict): presets[_slug_voice_design_name(str(name))] = { "description": str(preset.get("description", "")), "sample_text": str(preset.get("sample_text", preset.get("text", ""))), "language": str(preset.get("language", "Auto")), "gender": str(preset.get("gender", "N")), } except Exception: pass try: saved = state_get("voice_design_presets", None) if isinstance(saved, dict): for name, preset in saved.items(): if isinstance(preset, dict): presets[_slug_voice_design_name(str(name))] = { "description": str(preset.get("description", "")), "sample_text": str(preset.get("sample_text", preset.get("text", ""))), "language": str(preset.get("language", "Auto")), "gender": str(preset.get("gender", "N")), } except Exception: pass return presets def _save_design_presets(presets: dict) -> None: cleaned = {} for name, preset in presets.items(): if not isinstance(preset, dict): continue key = _slug_voice_design_name(str(name)) cleaned[key] = { "description": str(preset.get("description", "")), "sample_text": str(preset.get("sample_text", preset.get("text", ""))), "language": str(preset.get("language", "Auto")), "gender": str(preset.get("gender", "N")), } CONFIG_DIR.mkdir(parents=True, exist_ok=True) state_put("voice_design_presets", cleaned) DESIGN_PRESETS_FILE.write_text(json.dumps(cleaned, indent=2)) def _virtual_voice_id(name: str) -> str: return f"vd_{_slug_voice_design_name(name)}" def _resolve_virtual_voice(voice: str) -> tuple[str, dict] | None: if not voice.startswith("vd_"): return None wanted = _slug_voice_design_name(voice[3:]) presets = _load_design_presets() for name, preset in presets.items(): if _slug_voice_design_name(name) == wanted: return name, preset return None