""" NovaAi – TTS-Engine-Hub engines/kokoro_voices.py Version: v0.1.0 Description: Voice metadata for Kokoro TTS engine. Complete list of 54 voices across 8 languages with metadata. Source: https://huggingface.co/hexgrad/Kokoro-82M/blob/main/VOICES.md Author: Claude Code (Anthropic) Date: 2025-12-05 """ # Complete list of all 54 Kokoro voices ALL_VOICES = [ # American English (20 voices) 'af_heart', 'af_alloy', 'af_aoede', 'af_bella', 'af_jessica', 'af_kore', 'af_nicole', 'af_nova', 'af_river', 'af_sarah', 'af_sky', 'am_adam', 'am_echo', 'am_eric', 'am_fenrir', 'am_liam', 'am_michael', 'am_onyx', 'am_puck', 'am_santa', # British English (8 voices) 'bf_alice', 'bf_emma', 'bf_isabella', 'bf_lily', 'bm_daniel', 'bm_fable', 'bm_george', 'bm_lewis', # Japanese (5 voices) 'jf_alpha', 'jf_gongitsune', 'jf_nezumi', 'jf_tebukuro', 'jm_kumo', # Mandarin Chinese (8 voices) 'zf_xiaobei', 'zf_xiaoni', 'zf_xiaoxiao', 'zf_xiaoyi', 'zm_yunjian', 'zm_yunxi', 'zm_yunxia', 'zm_yunyang', # Spanish (3 voices) 'ef_dora', 'em_alex', 'em_santa', # French (1 voice) 'ff_siwis', # Hindi (4 voices) 'hf_alpha', 'hf_beta', 'hm_omega', 'hm_psi', # Italian (2 voices) 'if_sara', 'im_nicola', # Brazilian Portuguese (3 voices) 'pf_dora', 'pm_alex', 'pm_santa', ] # Voice metadata with gender and language information VOICE_METADATA = { # American English - Female 'af_heart': {'gender': 'F', 'language': 'en-us', 'description': 'Clear, warm female voice'}, 'af_alloy': {'gender': 'F', 'language': 'en-us', 'description': 'Professional female voice'}, 'af_aoede': {'gender': 'F', 'language': 'en-us', 'description': 'Expressive female voice'}, 'af_bella': {'gender': 'F', 'language': 'en-us', 'description': 'Warm, friendly female voice'}, 'af_jessica': {'gender': 'F', 'language': 'en-us', 'description': 'Natural female voice'}, 'af_kore': {'gender': 'F', 'language': 'en-us', 'description': 'Energetic female voice'}, 'af_nicole': {'gender': 'F', 'language': 'en-us', 'description': 'Smooth female voice'}, 'af_nova': {'gender': 'F', 'language': 'en-us', 'description': 'Bright female voice'}, 'af_river': {'gender': 'F', 'language': 'en-us', 'description': 'Calm female voice'}, 'af_sarah': {'gender': 'F', 'language': 'en-us', 'description': 'Professional female voice'}, 'af_sky': {'gender': 'F', 'language': 'en-us', 'description': 'Cheerful female voice'}, # American English - Male 'am_adam': {'gender': 'M', 'language': 'en-us', 'description': 'Deep male voice'}, 'am_echo': {'gender': 'M', 'language': 'en-us', 'description': 'Resonant male voice'}, 'am_eric': {'gender': 'M', 'language': 'en-us', 'description': 'Professional male voice'}, 'am_fenrir': {'gender': 'M', 'language': 'en-us', 'description': 'Strong male voice'}, 'am_liam': {'gender': 'M', 'language': 'en-us', 'description': 'Friendly male voice'}, 'am_michael': {'gender': 'M', 'language': 'en-us', 'description': 'Clear male voice'}, 'am_onyx': {'gender': 'M', 'language': 'en-us', 'description': 'Smooth male voice'}, 'am_puck': {'gender': 'M', 'language': 'en-us', 'description': 'Playful male voice'}, 'am_santa': {'gender': 'M', 'language': 'en-us', 'description': 'Warm, jolly male voice'}, # British English - Female 'bf_alice': {'gender': 'F', 'language': 'en-gb', 'description': 'British female voice'}, 'bf_emma': {'gender': 'F', 'language': 'en-gb', 'description': 'British female voice'}, 'bf_isabella': {'gender': 'F', 'language': 'en-gb', 'description': 'British female voice'}, 'bf_lily': {'gender': 'F', 'language': 'en-gb', 'description': 'British female voice'}, # British English - Male 'bm_daniel': {'gender': 'M', 'language': 'en-gb', 'description': 'British male voice'}, 'bm_fable': {'gender': 'M', 'language': 'en-gb', 'description': 'British male voice'}, 'bm_george': {'gender': 'M', 'language': 'en-gb', 'description': 'British male voice'}, 'bm_lewis': {'gender': 'M', 'language': 'en-gb', 'description': 'British male voice'}, # Japanese - Female 'jf_alpha': {'gender': 'F', 'language': 'ja', 'description': 'Japanese female voice'}, 'jf_gongitsune': {'gender': 'F', 'language': 'ja', 'description': 'Japanese female voice'}, 'jf_nezumi': {'gender': 'F', 'language': 'ja', 'description': 'Japanese female voice'}, 'jf_tebukuro': {'gender': 'F', 'language': 'ja', 'description': 'Japanese female voice'}, # Japanese - Male 'jm_kumo': {'gender': 'M', 'language': 'ja', 'description': 'Japanese male voice'}, # Mandarin Chinese - Female 'zf_xiaobei': {'gender': 'F', 'language': 'zh', 'description': 'Chinese female voice'}, 'zf_xiaoni': {'gender': 'F', 'language': 'zh', 'description': 'Chinese female voice'}, 'zf_xiaoxiao': {'gender': 'F', 'language': 'zh', 'description': 'Chinese female voice'}, 'zf_xiaoyi': {'gender': 'F', 'language': 'zh', 'description': 'Chinese female voice'}, # Mandarin Chinese - Male 'zm_yunjian': {'gender': 'M', 'language': 'zh', 'description': 'Chinese male voice'}, 'zm_yunxi': {'gender': 'M', 'language': 'zh', 'description': 'Chinese male voice'}, 'zm_yunxia': {'gender': 'M', 'language': 'zh', 'description': 'Chinese male voice'}, 'zm_yunyang': {'gender': 'M', 'language': 'zh', 'description': 'Chinese male voice'}, # Spanish - Female 'ef_dora': {'gender': 'F', 'language': 'es', 'description': 'Spanish female voice'}, # Spanish - Male 'em_alex': {'gender': 'M', 'language': 'es', 'description': 'Spanish male voice'}, 'em_santa': {'gender': 'M', 'language': 'es', 'description': 'Spanish male voice'}, # French - Female 'ff_siwis': {'gender': 'F', 'language': 'fr', 'description': 'French female voice'}, # Hindi - Female 'hf_alpha': {'gender': 'F', 'language': 'hi', 'description': 'Hindi female voice'}, 'hf_beta': {'gender': 'F', 'language': 'hi', 'description': 'Hindi female voice'}, # Hindi - Male 'hm_omega': {'gender': 'M', 'language': 'hi', 'description': 'Hindi male voice'}, 'hm_psi': {'gender': 'M', 'language': 'hi', 'description': 'Hindi male voice'}, # Italian - Female 'if_sara': {'gender': 'F', 'language': 'it', 'description': 'Italian female voice'}, # Italian - Male 'im_nicola': {'gender': 'M', 'language': 'it', 'description': 'Italian male voice'}, # Brazilian Portuguese - Female 'pf_dora': {'gender': 'F', 'language': 'pt', 'description': 'Portuguese female voice'}, # Brazilian Portuguese - Male 'pm_alex': {'gender': 'M', 'language': 'pt', 'description': 'Portuguese male voice'}, 'pm_santa': {'gender': 'M', 'language': 'pt', 'description': 'Portuguese male voice'}, } # Language mapping for voice filtering VOICES_BY_LANGUAGE = { 'en-us': [v for v in ALL_VOICES if v.startswith('a')], 'en-gb': [v for v in ALL_VOICES if v.startswith('b')], 'ja': [v for v in ALL_VOICES if v.startswith('j')], 'zh': [v for v in ALL_VOICES if v.startswith('z')], 'es': [v for v in ALL_VOICES if v.startswith('e')], 'fr': [v for v in ALL_VOICES if v.startswith('f')], 'hi': [v for v in ALL_VOICES if v.startswith('h')], 'it': [v for v in ALL_VOICES if v.startswith('i')], 'pt': [v for v in ALL_VOICES if v.startswith('p')], } def get_voices_for_model(model: str) -> list: """ Get voices compatible with a specific model/language. Args: model: Model name (e.g., 'kokoro-en-us', 'kokoro-ja') Returns: List of compatible voice IDs """ # Extract language code from model name if model == 'kokoro-en-us': return VOICES_BY_LANGUAGE['en-us'] elif model == 'kokoro-en-gb': return VOICES_BY_LANGUAGE['en-gb'] elif model == 'kokoro-ja': return VOICES_BY_LANGUAGE['ja'] elif model == 'kokoro-zh': return VOICES_BY_LANGUAGE['zh'] elif model == 'kokoro-es': return VOICES_BY_LANGUAGE['es'] elif model == 'kokoro-fr': return VOICES_BY_LANGUAGE['fr'] elif model == 'kokoro-hi': return VOICES_BY_LANGUAGE['hi'] elif model == 'kokoro-it': return VOICES_BY_LANGUAGE['it'] elif model == 'kokoro-pt': return VOICES_BY_LANGUAGE['pt'] else: # Return all voices if model not recognized return ALL_VOICES def get_voice_info(voice_id: str) -> dict: """ Get metadata for a specific voice. Args: voice_id: Voice identifier (e.g., 'af_bella') Returns: Dictionary with voice metadata """ return VOICE_METADATA.get(voice_id, { 'gender': 'Unknown', 'language': 'unknown', 'description': 'No description available' })