diff --git a/voice_manager.py b/voice_manager.py index bb6d869..635cdf7 100644 --- a/voice_manager.py +++ b/voice_manager.py @@ -105,26 +105,36 @@ class VoiceManager: "macOS System Voices:\n" + "\n".join(macos_lines) ) + def set_voice(self, voice_name: str) -> tuple[bool, str]: + return self.apply_voice(voice_name) + def apply_voice(self, voice_name: str) -> tuple[bool, str]: + import re voice_name = voice_name.strip() matched_voice = None - # Check voice aliases first (e.g. Daniel -> bm_george) clean_name = voice_name.lower() + norm_name = re.sub(r"[^a-z0-9]", "", clean_name) + + # Check voice aliases first (e.g. Daniel -> bm_george, bella -> af_bella) if clean_name in VOICE_ALIASES: matched_voice = VOICE_ALIASES[clean_name] + elif norm_name in VOICE_ALIASES: + matched_voice = VOICE_ALIASES[norm_name] - # Exact match or fuzzy match + # Exact or normalized match in Kokoro voices (e.g. afbella -> af_bella) if not matched_voice: for v in KOKORO_VOICES: - if clean_name == v.lower(): + v_norm = re.sub(r"[^a-z0-9]", "", v.lower()) + if norm_name == v_norm or clean_name == v.lower(): matched_voice = v break if not matched_voice: - # Partial match search + # Partial/substring match search for v in KOKORO_VOICES: - if clean_name in v.lower(): + v_norm = re.sub(r"[^a-z0-9]", "", v.lower()) + if norm_name in v_norm or v_norm in norm_name: matched_voice = v break