Make voice_tool dependency-free and add voice alias mappings for macOS vs Kokoro names
This commit is contained in:
+34
-10
@@ -4,8 +4,13 @@ Supports both Kokoro TTS voices and macOS System voices, persisting user voice p
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from loguru import logger
|
||||
|
||||
try:
|
||||
from loguru import logger
|
||||
except ImportError:
|
||||
logger = logging.getLogger("voice_manager")
|
||||
|
||||
# Supported Kokoro TTS voices categorized by style
|
||||
KOKORO_VOICES = {
|
||||
@@ -32,6 +37,19 @@ MACOS_VOICES = {
|
||||
"Alex": "US Male",
|
||||
}
|
||||
|
||||
VOICE_ALIASES = {
|
||||
"daniel": "bm_george", # British Male
|
||||
"moira": "bf_emma", # British Female
|
||||
"samantha": "af_bella", # US Female
|
||||
"alex": "am_michael", # US Male
|
||||
"karen": "bf_isabella", # AU/UK Female
|
||||
"michael": "am_michael",
|
||||
"bella": "af_bella",
|
||||
"heart": "af_heart",
|
||||
"fenrir": "am_fenrir",
|
||||
"adam": "am_adam",
|
||||
}
|
||||
|
||||
|
||||
class VoiceManager:
|
||||
"""Manages active voice settings and dynamic voice switching."""
|
||||
@@ -78,21 +96,27 @@ class VoiceManager:
|
||||
voice_name = voice_name.strip()
|
||||
matched_voice = None
|
||||
|
||||
# Exact match or fuzzy match
|
||||
for v in {**KOKORO_VOICES, **MACOS_VOICES}:
|
||||
if voice_name.lower() == v.lower():
|
||||
matched_voice = v
|
||||
break
|
||||
# Check voice aliases first (e.g. Daniel -> bm_george)
|
||||
clean_name = voice_name.lower()
|
||||
if clean_name in VOICE_ALIASES:
|
||||
matched_voice = VOICE_ALIASES[clean_name]
|
||||
|
||||
# Exact match or fuzzy match
|
||||
if not matched_voice:
|
||||
# Partial match search
|
||||
for v in {**KOKORO_VOICES, **MACOS_VOICES}:
|
||||
if voice_name.lower() in v.lower():
|
||||
for v in KOKORO_VOICES:
|
||||
if clean_name == v.lower():
|
||||
matched_voice = v
|
||||
break
|
||||
|
||||
if not matched_voice:
|
||||
available = ", ".join(list(KOKORO_VOICES.keys()) + list(MACOS_VOICES.keys()))
|
||||
# Partial match search
|
||||
for v in KOKORO_VOICES:
|
||||
if clean_name in v.lower():
|
||||
matched_voice = v
|
||||
break
|
||||
|
||||
if not matched_voice:
|
||||
available = ", ".join(list(KOKORO_VOICES.keys()))
|
||||
return False, f"Voice '{voice_name}' not found. Available voices: {available}"
|
||||
|
||||
self._active_voice = matched_voice
|
||||
|
||||
Reference in New Issue
Block a user