| """ | |
| Attribute map utility | |
| --------------------- | |
| Expose a structured mapping of the voice design attributes described in | |
| `prompt.txt` together with the inline emotion tags listed in | |
| `emotions.txt`. The module returns data that can be consumed by tooling | |
| to programmatically build descriptions or sweep attribute combinations. | |
| """ | |
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| from typing import Dict, Iterable, List, TypedDict | |
| class AttributeMap(TypedDict, total=False): | |
| metadata: Dict[str, str] | |
| emotions: Dict[str, object] | |
| shared_attributes: Dict[str, Iterable[str]] | |
| realistic_only: Dict[str, object] | |
| creative_only: Dict[str, object] | |
| constraints: Dict[str, object] | |
| defaults: Dict[str, str] | |
| MODULE_DIR = Path(__file__).resolve().parent | |
| EMOTIONS_FILE = MODULE_DIR / "emotions.txt" | |
| PROMPT_FILE = MODULE_DIR / "prompt.txt" | |
| def _load_emotion_tags(path: Path) -> List[str]: | |
| if not path.exists(): | |
| raise FileNotFoundError(f"Emotion tag file not found: {path}") | |
| tags: List[str] = [] | |
| with path.open("r", encoding="utf-8") as handle: | |
| for raw_line in handle: | |
| line = raw_line.strip() | |
| if not line or line.startswith("#"): | |
| continue | |
| tags.append(line) | |
| return tags | |
| def build_attribute_map( | |
| emotions_path: Path | None = None, | |
| prompt_path: Path | None = None, | |
| ) -> AttributeMap: | |
| """ | |
| Return an attribute map that mirrors the guidance in `prompt.txt`. | |
| Parameters | |
| ---------- | |
| emotions_path: | |
| Optional override for the emotion tag file. Defaults to | |
| `maya1/emotions.txt`. | |
| prompt_path: | |
| Included for symmetry/future validation. Defaults to | |
| `maya1/prompt.txt` and is currently used only for metadata. | |
| """ | |
| emotions_file = emotions_path or EMOTIONS_FILE | |
| prompt_file = prompt_path or PROMPT_FILE | |
| emotion_tags = _load_emotion_tags(emotions_file) | |
| attribute_map: AttributeMap = { | |
| "metadata": { | |
| "source_prompt": str(prompt_file), | |
| "source_emotions": str(emotions_file), | |
| "description": ( | |
| "Programmatic representation of Maya voice design attributes. " | |
| "Derived from prompt.txt guidance." | |
| ), | |
| }, | |
| "emotions": { | |
| "inline_tags": emotion_tags, | |
| "persona_emotion_attribute": [ | |
| "neutral", | |
| "energetic", | |
| "excited", | |
| "sad", | |
| "sarcastic", | |
| "dry", | |
| ], | |
| "intensity": ["low", "med", "high"], | |
| }, | |
| "shared_attributes": { | |
| "age": ["20s", "30s", "40s"], | |
| "gender": ["male", "female"], | |
| "accent": [ | |
| "american", | |
| "indian", | |
| "middle_eastern", | |
| "asian_american", | |
| "british", | |
| ], | |
| "pitch": ["low", "normal", "high"], | |
| "timbre_realistic": [ | |
| "deep", | |
| "warm", | |
| "gravelly", | |
| "smooth", | |
| "raspy", | |
| "nasally", | |
| "throaty", | |
| "harsh", | |
| ], | |
| "timbre_creative": [ | |
| "deep", | |
| "warm", | |
| "gravelly", | |
| "smooth", | |
| "raspy", | |
| "nasally", | |
| "throaty", | |
| "harsh", | |
| "robotic", | |
| "ethereal", | |
| ], | |
| "pacing": [ | |
| "very_slow", | |
| "slow", | |
| "conversational", | |
| "brisk", | |
| "fast", | |
| "very_fast", | |
| ], | |
| "emotion_intensity": ["low", "med", "high"], | |
| }, | |
| "realistic_only": { | |
| "domain": [ | |
| "social_content", | |
| "podcast", | |
| "commercial", | |
| "education", | |
| "support", | |
| "entertainment", | |
| "corporate", | |
| "viral_content", | |
| ], | |
| "speaking_role": { | |
| "social_content": [ | |
| "youtube_vlogger", | |
| "social_media_creator", | |
| "influencer_voice", | |
| "streamer_companion", | |
| ], | |
| "podcast": ["podcast_host", "interviewer"], | |
| "commercial": [ | |
| "ad_narrator", | |
| "brand_spokesperson", | |
| "product_demo_voice", | |
| "sales_pitch_voice", | |
| ], | |
| "education": ["elearning_instructor", "kids_story_voice"], | |
| "support": [ | |
| "customer_support_agent", | |
| "virtual_receptionist", | |
| "healthcare_assistant", | |
| ], | |
| "entertainment": [ | |
| "storyteller", | |
| "social_media_reaction", | |
| "meme_voice", | |
| ], | |
| "corporate": [ | |
| "explainer_video_voice", | |
| "event_host", | |
| "corporate_training_narrator", | |
| ], | |
| "viral_content": ["short_form_narrator", "meme_voice"], | |
| }, | |
| "register": ["formal", "neutral", "casual"], | |
| }, | |
| "creative_only": { | |
| "character": [ | |
| "animated_cartoon", | |
| "ai_machine_voice", | |
| "alien_scifi", | |
| "seductively", | |
| "flirty", | |
| "anime", | |
| "cyborg", | |
| "pirate", | |
| "dark_villain", | |
| "demon", | |
| "gangster", | |
| "mafia", | |
| "dramatic_narrator", | |
| "mythical_godlike_magical", | |
| "spy", | |
| "vampire", | |
| "alpha", | |
| ], | |
| }, | |
| "constraints": { | |
| "pitch": { | |
| "note": ( | |
| "For age 40s, avoid high pitch (use sparingly, <= 15% of uses)." | |
| ) | |
| }, | |
| "creative_timbre": { | |
| "robotic": [ | |
| "ai_machine_voice", | |
| "cyborg", | |
| "alien_scifi", | |
| "mythical_godlike_magical", | |
| ], | |
| "ethereal": [ | |
| "ai_machine_voice", | |
| "cyborg", | |
| "alien_scifi", | |
| "mythical_godlike_magical", | |
| ], | |
| }, | |
| "character_pacing_overrides": { | |
| "mafia": ["slow", "conversational"], | |
| "flirty": ["slow", "conversational"], | |
| "alpha": ["fast", "very_fast"], | |
| "seductively": ["very_slow", "slow"], | |
| }, | |
| "defaults": "Default persona emotion should be neutral unless specified.", | |
| }, | |
| "defaults": { | |
| "age": "20s", | |
| "gender": "female", | |
| "accent": "american", | |
| "pitch": "high", | |
| "timbre": "warm", | |
| "pacing": "brisk", | |
| "emotion": "excited", | |
| "emotion_intensity": "med", | |
| "domain": "social_content", | |
| "speaking_role": "influencer_voice", | |
| "register": "casual", | |
| }, | |
| } | |
| return attribute_map | |
| def main() -> None: | |
| """ | |
| CLI helper: print the attribute map as JSON for inspection. | |
| """ | |
| attribute_map = build_attribute_map() | |
| print(json.dumps(attribute_map, indent=2, sort_keys=True)) | |
| if __name__ == "__main__": | |
| main() | |