maya1 / attribute_map.py
acrosley's picture
Upload attribute_map.py
3c9face verified
raw
history blame
7.94 kB
"""
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()