ElevenLabs Voice Personas v2.1 Comprehensive voice synthesis toolkit using ElevenLabs API. πŸš€ First Run - Setup Wizard When you first use this skill (no exists), run the interactive setup wizard: The wizard will guide you through: 1. API Key - Enter your ElevenLabs API key (required) 2. Default Voice - Choose from popular voices (Rachel, Adam, Bella, etc.) 3. Language - Set your preferred language (32 supported) 4. Audio Quality - Standard or high quality output 5. Cost Tracking - Enable usage and cost monitoring 6. Budget Limit - Optional monthly spending cap πŸ”’ Privacy: Your API key is stor…

, key):\n return False\n return True\n\ndef get_input(prompt: str, required: bool = True, default: str = None) -> str:\n \"\"\"Get user input with optional default.\"\"\"\n if default:\n prompt = f\"{prompt} [{Colors.DIM}{default}{Colors.RESET}]: \"\n else:\n prompt = f\"{prompt}: \"\n \n while True:\n value = input(f\"{Colors.CYAN}>{Colors.RESET} {prompt}\").strip()\n if not value and default:\n return default\n if not value and required:\n print(f\"{Colors.RED} This field is required.{Colors.RESET}\")\n continue\n return value\n\ndef get_choice(prompt: str, options: list, default: str = None) -> str:\n \"\"\"Get user choice from a list of options.\"\"\"\n print(f\"\\n{Colors.BOLD}{prompt}{Colors.RESET}\")\n for i, opt in enumerate(options, 1):\n marker = f\"{Colors.GREEN}*{Colors.RESET}\" if opt == default else \" \"\n print(f\" {marker} {i}. {opt}\")\n \n while True:\n choice = input(f\"\\n{Colors.CYAN}>{Colors.RESET} Enter number [1-{len(options)}]: \").strip()\n if not choice and default:\n return default\n try:\n idx = int(choice) - 1\n if 0 \u003c= idx \u003c len(options):\n return options[idx]\n except ValueError:\n pass\n print(f\"{Colors.RED} Please enter a number between 1 and {len(options)}.{Colors.RESET}\")\n\ndef get_yes_no(prompt: str, default: bool = True) -> bool:\n \"\"\"Get yes/no response.\"\"\"\n default_str = \"Y/n\" if default else \"y/N\"\n while True:\n response = input(f\"{Colors.CYAN}>{Colors.RESET} {prompt} [{default_str}]: \").strip().lower()\n if not response:\n return default\n if response in ('y', 'yes'):\n return True\n if response in ('n', 'no'):\n return False\n print(f\"{Colors.RED} Please enter 'y' or 'n'.{Colors.RESET}\")\n\ndef get_optional_number(prompt: str) -> float | None:\n \"\"\"Get optional numeric input.\"\"\"\n while True:\n value = input(f\"{Colors.CYAN}>{Colors.RESET} {prompt} [skip]: \").strip()\n if not value:\n return None\n try:\n return float(value)\n except ValueError:\n print(f\"{Colors.RED} Please enter a valid number or press Enter to skip.{Colors.RESET}\")\n\ndef run_setup():\n \"\"\"Run the interactive setup wizard.\"\"\"\n print_banner()\n \n config = {}\n \n # Step 1: API Key (required)\n print(f\"\\n{Colors.BOLD}━━━ Step 1/6: API Key ━━━{Colors.RESET}\")\n print(f\"{Colors.DIM}Get your API key from: https://elevenlabs.io/app/settings/api-keys{Colors.RESET}\")\n print()\n \n while True:\n api_key = get_input(\"Enter your ElevenLabs API key\", required=True)\n if validate_api_key(api_key):\n config['apiKey'] = api_key\n print(f\"{Colors.GREEN} βœ“ API key accepted{Colors.RESET}\")\n break\n print(f\"{Colors.RED} Invalid API key format. Keys are typically 32+ alphanumeric characters.{Colors.RESET}\")\n \n # Step 2: Default Voice\n print(f\"\\n{Colors.BOLD}━━━ Step 2/6: Default Voice ━━━{Colors.RESET}\")\n popular_voices = [\n \"Rachel (warm, friendly - recommended)\",\n \"Adam (narrator, documentaries)\",\n \"Bella (professional, business)\",\n \"Antoni (deep, confident)\",\n \"George (British storyteller)\",\n \"Alice (British educator)\",\n \"Brian (comforting, calm)\",\n \"Matilda (corporate, news)\",\n \"Liam (social media, energetic)\"\n ]\n voice_choice = get_choice(\"Choose your default voice:\", popular_voices, default=\"Rachel (warm, friendly - recommended)\")\n config['defaultVoice'] = voice_choice.split(' ')[0].lower()\n print(f\"{Colors.GREEN} βœ“ Default voice: {config['defaultVoice']}{Colors.RESET}\")\n \n # Step 3: Default Language\n print(f\"\\n{Colors.BOLD}━━━ Step 3/6: Default Language ━━━{Colors.RESET}\")\n languages = [\n \"English (en)\",\n \"German (de)\",\n \"Spanish (es)\",\n \"French (fr)\",\n \"Italian (it)\",\n \"Portuguese (pt)\",\n \"Dutch (nl)\",\n \"Polish (pl)\",\n \"Japanese (ja)\",\n \"Korean (ko)\",\n \"Chinese (zh)\"\n ]\n lang_choice = get_choice(\"Default language for synthesis:\", languages, default=\"English (en)\")\n # Extract language code from parentheses\n config['defaultLanguage'] = lang_choice.split('(')[1].rstrip(')')\n print(f\"{Colors.GREEN} βœ“ Default language: {config['defaultLanguage']}{Colors.RESET}\")\n \n # Step 4: Audio Quality\n print(f\"\\n{Colors.BOLD}━━━ Step 4/6: Audio Quality ━━━{Colors.RESET}\")\n print(f\"{Colors.DIM}Higher quality uses more API quota.{Colors.RESET}\")\n qualities = [\n \"standard (faster, smaller files)\",\n \"high (better quality, larger files)\"\n ]\n quality_choice = get_choice(\"Audio quality preference:\", qualities, default=\"standard (faster, smaller files)\")\n config['audioQuality'] = quality_choice.split(' ')[0]\n print(f\"{Colors.GREEN} βœ“ Audio quality: {config['audioQuality']}{Colors.RESET}\")\n \n # Step 5: Cost Tracking\n print(f\"\\n{Colors.BOLD}━━━ Step 5/6: Cost Tracking ━━━{Colors.RESET}\")\n print(f\"{Colors.DIM}Track character usage and estimate costs.{Colors.RESET}\")\n config['costTracking'] = get_yes_no(\"Enable cost tracking?\", default=True)\n status = \"enabled\" if config['costTracking'] else \"disabled\"\n print(f\"{Colors.GREEN} βœ“ Cost tracking: {status}{Colors.RESET}\")\n \n # Step 6: Budget Limit (optional)\n print(f\"\\n{Colors.BOLD}━━━ Step 6/6: Budget Limit ━━━{Colors.RESET}\")\n print(f\"{Colors.DIM}Optional: Set a monthly spending limit (in USD).{Colors.RESET}\")\n print(f\"{Colors.DIM}You'll get a warning when approaching this limit.{Colors.RESET}\")\n budget = get_optional_number(\"Monthly budget limit (USD)\")\n if budget is not None:\n config['monthlyBudget'] = budget\n print(f\"{Colors.GREEN} βœ“ Monthly budget: ${budget:.2f}{Colors.RESET}\")\n else:\n print(f\"{Colors.DIM} βœ“ No budget limit set{Colors.RESET}\")\n \n # Add metadata\n config['_version'] = '2.1.0'\n config['_created'] = True\n \n return config\n\ndef save_config(config: dict, path: Path):\n \"\"\"Save configuration to JSON file.\"\"\"\n with open(path, 'w') as f:\n json.dump(config, f, indent=2)\n print(f\"\\n{Colors.GREEN}βœ“ Configuration saved to: {path}{Colors.RESET}\")\n\ndef print_summary(config: dict):\n \"\"\"Print configuration summary.\"\"\"\n print(f\"\"\"\n{Colors.CYAN}{Colors.BOLD}━━━ Configuration Summary ━━━{Colors.RESET}\n\n API Key: {Colors.DIM}****{config['apiKey'][-4:]}{Colors.RESET}\n Default Voice: {config['defaultVoice']}\n Language: {config['defaultLanguage']}\n Audio Quality: {config['audioQuality']}\n Cost Tracking: {'enabled' if config['costTracking'] else 'disabled'}\n Monthly Budget: {f\"${config['monthlyBudget']:.2f}\" if config.get('monthlyBudget') else 'not set'}\n\"\"\")\n\ndef print_next_steps():\n \"\"\"Print next steps after setup.\"\"\"\n print(f\"\"\"{Colors.CYAN}{Colors.BOLD}━━━ You're all set! ━━━{Colors.RESET}\n\n{Colors.BOLD}Try these commands:{Colors.RESET}\n\n # Generate speech\n python3 scripts/tts.py --text \"Hello world\" --voice rachel\n\n # List all voices\n python3 scripts/tts.py --list\n\n # Generate sound effects\n python3 scripts/sfx.py --prompt \"Thunder rumbling\"\n\n # Check usage stats\n python3 scripts/tts.py --stats\n\n{Colors.DIM}Full documentation: SKILL.md{Colors.RESET}\n\"\"\")\n\ndef main():\n \"\"\"Main entry point.\"\"\"\n # Determine config path (skill root directory)\n script_dir = Path(__file__).parent\n skill_dir = script_dir.parent\n config_path = skill_dir / 'config.json'\n \n # Check if config already exists\n if config_path.exists():\n print(f\"\\n{Colors.YELLOW}⚠ Configuration already exists at: {config_path}{Colors.RESET}\")\n if not get_yes_no(\"Do you want to reconfigure?\", default=False):\n print(f\"{Colors.DIM}Setup cancelled. Existing config preserved.{Colors.RESET}\")\n return 0\n print()\n \n try:\n config = run_setup()\n save_config(config, config_path)\n print_summary(config)\n print_next_steps()\n return 0\n except KeyboardInterrupt:\n print(f\"\\n\\n{Colors.YELLOW}Setup cancelled.{Colors.RESET}\")\n return 1\n except Exception as e:\n print(f\"\\n{Colors.RED}Error: {e}{Colors.RESET}\")\n return 1\n\nif __name__ == '__main__':\n sys.exit(main())\n","content_type":"text/x-python; charset=utf-8","language":"python","size":10507,"content_sha256":"0be510b307d61839d93f0561f52c8c65dcd8343cf0a8e5c87c7fad0839c9e3a3"},{"filename":"scripts/sfx.py","content":"#!/usr/bin/env python3\n\"\"\"\nElevenLabs Sound Effects (SFX) Generator\n\nGenerate AI-powered sound effects using ElevenLabs Sound Generation API.\n\nUsage:\n python3 sfx.py --prompt \"Thunder rumbling in the distance\"\n python3 sfx.py --prompt \"Cat meowing\" --duration 3\n python3 sfx.py --prompt \"Footsteps on gravel\" --output footsteps.mp3\n\nAPI Documentation: https://elevenlabs.io/docs/api-reference/sound-generation\n\"\"\"\n\nimport argparse\nimport json\nimport os\nimport sys\nimport urllib.request\nimport urllib.error\nfrom pathlib import Path\nfrom datetime import datetime\n\nSCRIPT_DIR = Path(__file__).parent\nSKILL_DIR = SCRIPT_DIR.parent\nUSAGE_FILE = SKILL_DIR / \".usage.json\"\n\n# ElevenLabs Sound Generation API\nSFX_API_URL = \"https://api.elevenlabs.io/v1/sound-generation\"\n\n\ndef get_api_key() -> str:\n \"\"\"Get API key from environment or OpenClaw config.\"\"\"\n api_key = os.environ.get(\"ELEVEN_API_KEY\") or os.environ.get(\"ELEVENLABS_API_KEY\")\n if api_key:\n return api_key\n \n config_paths = [\n Path.home() / \".openclaw\" / \"openclaw.json\",\n Path(\"/root/.openclaw/openclaw.json\"),\n ]\n \n for config_path in config_paths:\n if config_path.exists():\n try:\n config = json.loads(config_path.read_text())\n api_key = config.get(\"tts\", {}).get(\"elevenlabs\", {}).get(\"apiKey\")\n if api_key:\n return api_key\n except Exception:\n continue\n \n env_file = SKILL_DIR / \".env\"\n if env_file.exists():\n for line in env_file.read_text().splitlines():\n if line.startswith(\"ELEVEN_API_KEY=\"):\n return line.split(\"=\", 1)[1].strip().strip('\"\\'')\n \n print(\"❌ No ElevenLabs API key found.\")\n print(\" Set ELEVEN_API_KEY environment variable or configure in OpenClaw\")\n sys.exit(1)\n\n\ndef load_usage() -> dict:\n \"\"\"Load usage statistics.\"\"\"\n if not USAGE_FILE.exists():\n return {\"sfx_requests\": 0, \"sfx_seconds\": 0}\n try:\n return json.loads(USAGE_FILE.read_text())\n except Exception:\n return {\"sfx_requests\": 0, \"sfx_seconds\": 0}\n\n\ndef save_usage(usage: dict):\n \"\"\"Save usage statistics.\"\"\"\n USAGE_FILE.write_text(json.dumps(usage, indent=2))\n\n\ndef track_sfx_usage(duration: float, prompt: str):\n \"\"\"Track SFX usage.\"\"\"\n usage = load_usage()\n usage[\"sfx_requests\"] = usage.get(\"sfx_requests\", 0) + 1\n usage[\"sfx_seconds\"] = usage.get(\"sfx_seconds\", 0) + duration\n \n # Add SFX session entry\n if \"sfx_sessions\" not in usage:\n usage[\"sfx_sessions\"] = []\n \n usage[\"sfx_sessions\"].append({\n \"timestamp\": datetime.now().isoformat(),\n \"duration\": duration,\n \"prompt\": prompt[:100]\n })\n \n # Keep only last 100 SFX sessions\n if len(usage[\"sfx_sessions\"]) > 100:\n usage[\"sfx_sessions\"] = usage[\"sfx_sessions\"][-100:]\n \n save_usage(usage)\n\n\ndef generate_sfx(\n prompt: str,\n output_path: str,\n duration: float = None,\n prompt_influence: float = 0.3,\n api_key: str = None\n) -> bool:\n \"\"\"\n Generate a sound effect from a text prompt.\n \n Args:\n prompt: Text description of the desired sound effect\n output_path: Where to save the generated audio\n duration: Duration in seconds (0.5 to 22, optional - AI decides if not set)\n prompt_influence: How closely to follow the prompt (0.0-1.0)\n api_key: ElevenLabs API key\n \n Returns:\n True if successful, False otherwise\n \"\"\"\n headers = {\n \"xi-api-key\": api_key,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"audio/mpeg\"\n }\n \n payload = {\n \"text\": prompt,\n \"prompt_influence\": prompt_influence\n }\n \n if duration is not None:\n # Clamp duration to valid range\n duration = max(0.5, min(22.0, duration))\n payload[\"duration_seconds\"] = duration\n \n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(SFX_API_URL, data=data, headers=headers, method=\"POST\")\n \n try:\n print(f\"🎡 Generating: {prompt}\")\n if duration:\n print(f\" Duration: {duration}s\")\n \n with urllib.request.urlopen(req, timeout=60) as response:\n audio_data = response.read()\n \n with open(output_path, \"wb\") as f:\n f.write(audio_data)\n \n size_kb = len(audio_data) / 1024\n print(f\"βœ… Saved: {output_path} ({size_kb:.1f} KB)\")\n \n # Track usage (estimate duration if not specified)\n actual_duration = duration or 5.0\n track_sfx_usage(actual_duration, prompt)\n \n return True\n \n except urllib.error.HTTPError as e:\n error_body = e.read().decode(\"utf-8\") if e.fp else \"\"\n print(f\"❌ API Error ({e.code}): {error_body[:200]}\")\n return False\n except urllib.error.URLError as e:\n print(f\"❌ Network Error: {e.reason}\")\n return False\n\n\ndef batch_sfx(batch_file: str, output_dir: str, api_key: str) -> tuple:\n \"\"\"\n Generate multiple sound effects from a batch file.\n \n Batch file format (JSON):\n [\n {\"prompt\": \"Thunder rumbling\", \"duration\": 5, \"output\": \"thunder.mp3\"},\n {\"prompt\": \"Rain on window\", \"output\": \"rain.mp3\"}\n ]\n \n Or newline-separated prompts (one per line).\n \"\"\"\n batch_path = Path(batch_file)\n if not batch_path.exists():\n print(f\"❌ Batch file not found: {batch_file}\")\n return 0, 0\n \n out_path = Path(output_dir)\n out_path.mkdir(parents=True, exist_ok=True)\n \n content = batch_path.read_text()\n \n items = []\n try:\n data = json.loads(content)\n if isinstance(data, list):\n items = data\n except json.JSONDecodeError:\n # Treat as newline-separated prompts\n for i, line in enumerate(content.splitlines(), 1):\n line = line.strip()\n if line:\n items.append({\n \"prompt\": line,\n \"output\": f\"sfx_{i:04d}.mp3\"\n })\n \n if not items:\n print(\"❌ No items found in batch file\")\n return 0, 0\n \n print(f\"πŸ“¦ Processing SFX batch: {len(items)} items\\n\")\n \n success = 0\n failed = 0\n \n for i, item in enumerate(items, 1):\n if isinstance(item, str):\n item = {\"prompt\": item, \"output\": f\"sfx_{i:04d}.mp3\"}\n \n prompt = item.get(\"prompt\", \"\")\n duration = item.get(\"duration\")\n output_name = item.get(\"output\", f\"sfx_{i:04d}.mp3\")\n output_file = out_path / output_name\n \n print(f\" [{i}/{len(items)}] {prompt[:50]}...\")\n \n if generate_sfx(prompt, str(output_file), duration, 0.3, api_key):\n success += 1\n else:\n failed += 1\n \n # Rate limiting\n import time\n time.sleep(1.0)\n \n print(f\"\\nβœ… Complete: {success} success, {failed} failed\")\n print(f\"πŸ“ Output: {out_path}\")\n return success, failed\n\n\n# Sound effect prompt examples\nSFX_EXAMPLES = \"\"\"\n🎡 Sound Effect Prompt Examples:\n\nNature:\n \"Thunder rumbling in the distance\"\n \"Heavy rain on a tin roof\"\n \"Wind howling through trees\"\n \"Ocean waves crashing on rocks\"\n \"Crickets chirping at night\"\n\nUrban:\n \"Traffic noise in a busy city\"\n \"Subway train arriving at platform\"\n \"Doorbell ringing\"\n \"Phone ringing with old-fashioned bell\"\n \"Typing on a mechanical keyboard\"\n\nAnimals:\n \"Cat purring contentedly\"\n \"Dog barking in the distance\"\n \"Birds chirping at dawn\"\n \"Owl hooting at night\"\n \"Horse galloping on dirt road\"\n\nActions:\n \"Footsteps on wooden floor\"\n \"Door creaking open slowly\"\n \"Glass shattering\"\n \"Paper rustling\"\n \"Knife chopping vegetables\"\n\nSci-Fi/Fantasy:\n \"Spaceship engine humming\"\n \"Laser gun firing\"\n \"Magic spell casting with sparkles\"\n \"Robot walking with mechanical steps\"\n \"Teleportation whoosh\"\n\nAmbient:\n \"Coffee shop background chatter\"\n \"Office ambient noise with keyboard typing\"\n \"Library quiet ambience\"\n \"Fireplace crackling\"\n \"Clock ticking\"\n\"\"\"\n\n\ndef main():\n parser = argparse.ArgumentParser(\n description=\"ElevenLabs Sound Effects Generator\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog=\"\"\"\nExamples:\n python3 sfx.py --prompt \"Thunder rumbling in the distance\"\n python3 sfx.py --prompt \"Cat meowing\" --duration 3\n python3 sfx.py --prompt \"Footsteps\" --output steps.mp3 --influence 0.5\n python3 sfx.py --batch sounds.json --output-dir ./sfx\n python3 sfx.py --examples\n \"\"\"\n )\n \n parser.add_argument(\"--prompt\", \"-p\", help=\"Text description of the sound effect\")\n parser.add_argument(\"--output\", \"-o\", default=\"sfx_output.mp3\", help=\"Output file (default: sfx_output.mp3)\")\n parser.add_argument(\"--duration\", \"-d\", type=float, help=\"Duration in seconds (0.5-22)\")\n parser.add_argument(\"--influence\", \"-i\", type=float, default=0.3, \n help=\"Prompt influence (0.0-1.0, default: 0.3)\")\n parser.add_argument(\"--batch\", \"-b\", help=\"Batch file (JSON or newline-separated prompts)\")\n parser.add_argument(\"--output-dir\", default=\"./sfx_output\", help=\"Output directory for batch mode\")\n parser.add_argument(\"--examples\", \"-e\", action=\"store_true\", help=\"Show prompt examples\")\n \n args = parser.parse_args()\n \n if args.examples:\n print(SFX_EXAMPLES)\n return\n \n api_key = get_api_key()\n \n if args.batch:\n batch_sfx(args.batch, args.output_dir, api_key)\n return\n \n if not args.prompt:\n parser.print_help()\n print(\"\\n❌ --prompt is required. Try --examples for ideas.\")\n sys.exit(1)\n \n generate_sfx(\n args.prompt,\n args.output,\n args.duration,\n args.influence,\n api_key\n )\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":9951,"content_sha256":"3fedc9fdb883824fbc2914614d2b3904e2581be30e912117068405f397d66931"},{"filename":"scripts/tts.py","content":"#!/usr/bin/env python3\n\"\"\"\nElevenLabs TTS Script - Text to Speech with Voice Personas v2.0.0\n\nFeatures:\n- 18 voice personas with presets\n- 32 language support\n- Streaming audio output\n- Batch processing\n- Cost tracking\n- Pronunciation dictionary support\n\nUsage:\n python3 tts.py --text \"Hello world\" --voice rachel\n python3 tts.py --text \"Hallo Welt\" --voice rachel --lang de\n python3 tts.py --text \"Hello\" --voice rachel --stream\n python3 tts.py --batch input.txt --voice rachel\n python3 tts.py --stats\n python3 tts.py --list\n\"\"\"\n\nimport argparse\nimport json\nimport os\nimport sys\nimport urllib.request\nimport urllib.error\nimport time\nfrom pathlib import Path\nfrom datetime import datetime\n\nSCRIPT_DIR = Path(__file__).parent\nSKILL_DIR = SCRIPT_DIR.parent\nVOICES_FILE = SKILL_DIR / \"voices.json\"\nPRONUNCIATIONS_FILE = SKILL_DIR / \"pronunciations.json\"\nUSAGE_FILE = SKILL_DIR / \".usage.json\"\n\n# ElevenLabs API\nAPI_URL = \"https://api.elevenlabs.io/v1/text-to-speech\"\nSTREAM_URL = \"https://api.elevenlabs.io/v1/text-to-speech\"\n\n# Supported languages (32 languages)\nSUPPORTED_LANGUAGES = {\n \"en\": {\"name\": \"English\", \"code\": \"en\"},\n \"de\": {\"name\": \"German\", \"code\": \"de\"},\n \"es\": {\"name\": \"Spanish\", \"code\": \"es\"},\n \"fr\": {\"name\": \"French\", \"code\": \"fr\"},\n \"it\": {\"name\": \"Italian\", \"code\": \"it\"},\n \"pt\": {\"name\": \"Portuguese\", \"code\": \"pt\"},\n \"pl\": {\"name\": \"Polish\", \"code\": \"pl\"},\n \"nl\": {\"name\": \"Dutch\", \"code\": \"nl\"},\n \"sv\": {\"name\": \"Swedish\", \"code\": \"sv\"},\n \"da\": {\"name\": \"Danish\", \"code\": \"da\"},\n \"fi\": {\"name\": \"Finnish\", \"code\": \"fi\"},\n \"no\": {\"name\": \"Norwegian\", \"code\": \"no\"},\n \"tr\": {\"name\": \"Turkish\", \"code\": \"tr\"},\n \"ru\": {\"name\": \"Russian\", \"code\": \"ru\"},\n \"uk\": {\"name\": \"Ukrainian\", \"code\": \"uk\"},\n \"cs\": {\"name\": \"Czech\", \"code\": \"cs\"},\n \"sk\": {\"name\": \"Slovak\", \"code\": \"sk\"},\n \"hu\": {\"name\": \"Hungarian\", \"code\": \"hu\"},\n \"ro\": {\"name\": \"Romanian\", \"code\": \"ro\"},\n \"bg\": {\"name\": \"Bulgarian\", \"code\": \"bg\"},\n \"hr\": {\"name\": \"Croatian\", \"code\": \"hr\"},\n \"el\": {\"name\": \"Greek\", \"code\": \"el\"},\n \"hi\": {\"name\": \"Hindi\", \"code\": \"hi\"},\n \"ta\": {\"name\": \"Tamil\", \"code\": \"ta\"},\n \"id\": {\"name\": \"Indonesian\", \"code\": \"id\"},\n \"ms\": {\"name\": \"Malay\", \"code\": \"ms\"},\n \"vi\": {\"name\": \"Vietnamese\", \"code\": \"vi\"},\n \"th\": {\"name\": \"Thai\", \"code\": \"th\"},\n \"ja\": {\"name\": \"Japanese\", \"code\": \"ja\"},\n \"ko\": {\"name\": \"Korean\", \"code\": \"ko\"},\n \"zh\": {\"name\": \"Chinese\", \"code\": \"zh\"},\n \"ar\": {\"name\": \"Arabic\", \"code\": \"ar\"},\n}\n\n# ElevenLabs pricing (per 1000 characters)\nPRICING = {\n \"starter\": 0.30, # $0.30 per 1000 chars\n \"creator\": 0.24,\n \"pro\": 0.18,\n \"scale\": 0.11,\n}\n\n\ndef load_voices() -> dict:\n \"\"\"Load voice configurations from voices.json.\"\"\"\n if not VOICES_FILE.exists():\n print(f\"❌ voices.json not found at {VOICES_FILE}\")\n sys.exit(1)\n return json.loads(VOICES_FILE.read_text())\n\n\ndef load_pronunciations() -> dict:\n \"\"\"Load custom pronunciation rules.\"\"\"\n if not PRONUNCIATIONS_FILE.exists():\n return {\"rules\": [], \"phonemes\": {}}\n try:\n return json.loads(PRONUNCIATIONS_FILE.read_text())\n except Exception:\n return {\"rules\": [], \"phonemes\": {}}\n\n\ndef apply_pronunciations(text: str, pronunciations: dict) -> str:\n \"\"\"Apply pronunciation rules to text.\"\"\"\n rules = pronunciations.get(\"rules\", [])\n for rule in rules:\n word = rule.get(\"word\", \"\")\n replacement = rule.get(\"replacement\", \"\")\n if word and replacement:\n # Case-insensitive replacement\n import re\n text = re.sub(re.escape(word), replacement, text, flags=re.IGNORECASE)\n return text\n\n\ndef load_usage() -> dict:\n \"\"\"Load usage statistics.\"\"\"\n if not USAGE_FILE.exists():\n return {\n \"total_characters\": 0,\n \"total_requests\": 0,\n \"sessions\": [],\n \"last_reset\": datetime.now().isoformat()\n }\n try:\n return json.loads(USAGE_FILE.read_text())\n except Exception:\n return {\n \"total_characters\": 0,\n \"total_requests\": 0,\n \"sessions\": [],\n \"last_reset\": datetime.now().isoformat()\n }\n\n\ndef save_usage(usage: dict):\n \"\"\"Save usage statistics.\"\"\"\n USAGE_FILE.write_text(json.dumps(usage, indent=2))\n\n\ndef track_usage(chars: int, voice: str):\n \"\"\"Track character usage.\"\"\"\n usage = load_usage()\n usage[\"total_characters\"] += chars\n usage[\"total_requests\"] += 1\n \n # Add session entry\n session = {\n \"timestamp\": datetime.now().isoformat(),\n \"characters\": chars,\n \"voice\": voice\n }\n usage[\"sessions\"].append(session)\n \n # Keep only last 1000 sessions\n if len(usage[\"sessions\"]) > 1000:\n usage[\"sessions\"] = usage[\"sessions\"][-1000:]\n \n save_usage(usage)\n\n\ndef show_stats():\n \"\"\"Display usage statistics.\"\"\"\n usage = load_usage()\n \n total_chars = usage.get(\"total_characters\", 0)\n total_requests = usage.get(\"total_requests\", 0)\n last_reset = usage.get(\"last_reset\", \"Unknown\")\n \n print(\"πŸ“Š ElevenLabs Usage Statistics\\n\")\n print(f\" Total Characters: {total_chars:,}\")\n print(f\" Total Requests: {total_requests:,}\")\n print(f\" Since: {last_reset[:10]}\")\n print()\n \n # Estimated costs\n print(\"πŸ’° Estimated Costs:\")\n for plan, rate in PRICING.items():\n cost = (total_chars / 1000) * rate\n print(f\" {plan.capitalize():\u003c10} ${cost:.2f} (${rate}/1k chars)\")\n \n # Recent sessions\n sessions = usage.get(\"sessions\", [])[-10:]\n if sessions:\n print(\"\\nπŸ“œ Recent Sessions:\")\n for s in reversed(sessions):\n ts = s.get(\"timestamp\", \"\")[:16].replace(\"T\", \" \")\n chars = s.get(\"characters\", 0)\n voice = s.get(\"voice\", \"unknown\")\n print(f\" {ts} | {chars:>6} chars | {voice}\")\n\n\ndef reset_stats():\n \"\"\"Reset usage statistics.\"\"\"\n usage = {\n \"total_characters\": 0,\n \"total_requests\": 0,\n \"sessions\": [],\n \"last_reset\": datetime.now().isoformat()\n }\n save_usage(usage)\n print(\"βœ… Usage statistics reset.\")\n\n\ndef get_api_key() -> str:\n \"\"\"Get API key from environment or OpenClaw config.\"\"\"\n # Try environment first\n api_key = os.environ.get(\"ELEVEN_API_KEY\") or os.environ.get(\"ELEVENLABS_API_KEY\")\n if api_key:\n return api_key\n \n # Try OpenClaw config (multiple possible locations)\n config_paths = [\n Path.home() / \".openclaw\" / \"openclaw.json\",\n Path(\"/root/.openclaw/openclaw.json\"),\n ]\n \n for config_path in config_paths:\n if config_path.exists():\n try:\n config = json.loads(config_path.read_text())\n api_key = config.get(\"tts\", {}).get(\"elevenlabs\", {}).get(\"apiKey\")\n if api_key:\n return api_key\n except Exception:\n continue\n \n # Try skill-local .env file\n env_file = SKILL_DIR / \".env\"\n if env_file.exists():\n for line in env_file.read_text().splitlines():\n if line.startswith(\"ELEVEN_API_KEY=\"):\n return line.split(\"=\", 1)[1].strip().strip('\"\\'')\n \n print(\"❌ No ElevenLabs API key found.\")\n print(\" Options:\")\n print(\" 1. Set ELEVEN_API_KEY environment variable\")\n print(\" 2. Configure in OpenClaw (tts.elevenlabs.apiKey)\")\n print(\" 3. Create .env file in skill directory\")\n sys.exit(1)\n\n\ndef list_voices(voices_data: dict):\n \"\"\"List all available voices.\"\"\"\n voices = voices_data.get(\"voices\", {})\n presets = voices_data.get(\"presets\", {})\n \n print(\"πŸŽ™οΈ Available Voices\\n\")\n print(f\"{'Name':\u003c15} {'Language':\u003c10} {'Gender':\u003c8} {'Persona':\u003c15} Description\")\n print(\"-\" * 80)\n \n for name, v in sorted(voices.items()):\n print(f\"{name:\u003c15} {v.get('language', 'n/a'):\u003c10} {v.get('gender', 'n/a'):\u003c8} {v.get('persona', 'n/a'):\u003c15} {v.get('description', '')[:40]}...\")\n \n print(f\"\\nπŸ“‹ Presets: {', '.join(presets.keys())}\")\n\n\ndef list_languages():\n \"\"\"List all supported languages.\"\"\"\n print(\"🌍 Supported Languages (32)\\n\")\n print(f\"{'Code':\u003c6} {'Language':\u003c15}\")\n print(\"-\" * 25)\n for code, info in sorted(SUPPORTED_LANGUAGES.items()):\n print(f\"{code:\u003c6} {info['name']:\u003c15}\")\n\n\ndef synthesize(\n text: str, \n voice_name: str, \n output_path: str, \n voices_data: dict, \n api_key: str,\n language: str = None,\n stream: bool = False,\n pronunciations: dict = None\n) -> bool:\n \"\"\"Synthesize text to speech.\"\"\"\n voices = voices_data.get(\"voices\", {})\n \n if voice_name not in voices:\n # Check if it's a preset\n presets = voices_data.get(\"presets\", {})\n if voice_name in presets:\n voice_name = presets[voice_name]\n else:\n print(f\"❌ Voice '{voice_name}' not found.\")\n print(f\" Available: {', '.join(voices.keys())}\")\n return False\n \n voice = voices[voice_name]\n voice_id = voice[\"voice_id\"]\n settings = voice.get(\"settings\", {})\n \n # Apply pronunciation rules\n if pronunciations:\n text = apply_pronunciations(text, pronunciations)\n \n # Build language instruction if specified\n if language and language != \"en\":\n lang_info = SUPPORTED_LANGUAGES.get(language, {})\n if lang_info:\n # Multilingual model handles this via the text itself\n pass\n \n # Prepare request\n url = f\"{API_URL}/{voice_id}\"\n if stream:\n url += \"/stream\"\n \n headers = {\n \"xi-api-key\": api_key,\n \"Content-Type\": \"application/json\",\n \"Accept\": \"audio/mpeg\"\n }\n \n payload = {\n \"text\": text,\n \"model_id\": \"eleven_multilingual_v2\",\n \"voice_settings\": {\n \"stability\": settings.get(\"stability\", 0.75),\n \"similarity_boost\": settings.get(\"similarity_boost\", 0.75),\n \"style\": settings.get(\"style\", 0.5),\n \"use_speaker_boost\": True\n }\n }\n \n # Add language hint if specified\n if language:\n payload[\"language_code\"] = language\n \n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(url, data=data, headers=headers, method=\"POST\")\n \n try:\n if stream:\n # Streaming mode - write chunks as they arrive\n with urllib.request.urlopen(req, timeout=60) as response:\n with open(output_path, \"wb\") as f:\n total_bytes = 0\n while True:\n chunk = response.read(4096)\n if not chunk:\n break\n f.write(chunk)\n total_bytes += len(chunk)\n print(f\"\\r⏳ Streaming: {total_bytes / 1024:.1f} KB\", end=\"\", flush=True)\n print()\n print(f\"βœ… Saved: {output_path} ({total_bytes / 1024:.1f} KB)\")\n else:\n with urllib.request.urlopen(req, timeout=30) as response:\n audio_data = response.read()\n \n # Write to file\n with open(output_path, \"wb\") as f:\n f.write(audio_data)\n \n print(f\"βœ… Saved: {output_path} ({len(audio_data) / 1024:.1f} KB)\")\n \n # Track usage\n track_usage(len(text), voice_name)\n return True\n \n except urllib.error.HTTPError as e:\n error_body = e.read().decode(\"utf-8\") if e.fp else \"\"\n print(f\"❌ API Error ({e.code}): {error_body[:200]}\")\n return False\n except urllib.error.URLError as e:\n print(f\"❌ Network Error: {e.reason}\")\n return False\n\n\ndef process_batch(\n batch_file: str,\n voice_name: str,\n output_dir: str,\n voices_data: dict,\n api_key: str,\n language: str = None,\n pronunciations: dict = None\n) -> tuple:\n \"\"\"Process batch of texts from file.\"\"\"\n batch_path = Path(batch_file)\n if not batch_path.exists():\n print(f\"❌ Batch file not found: {batch_file}\")\n return 0, 0\n \n out_path = Path(output_dir)\n out_path.mkdir(parents=True, exist_ok=True)\n \n content = batch_path.read_text()\n \n # Try to parse as JSON first\n texts = []\n try:\n data = json.loads(content)\n if isinstance(data, list):\n texts = data\n elif isinstance(data, dict) and \"texts\" in data:\n texts = data[\"texts\"]\n except json.JSONDecodeError:\n # Treat as newline-separated text\n texts = [line.strip() for line in content.splitlines() if line.strip()]\n \n if not texts:\n print(\"❌ No texts found in batch file\")\n return 0, 0\n \n print(f\"πŸ“¦ Processing batch: {len(texts)} items\\n\")\n \n success = 0\n failed = 0\n \n for i, text in enumerate(texts, 1):\n # Handle dict entries with custom voice/output\n if isinstance(text, dict):\n t = text.get(\"text\", \"\")\n v = text.get(\"voice\", voice_name)\n o = text.get(\"output\", f\"output_{i:04d}.mp3\")\n else:\n t = str(text)\n v = voice_name\n o = f\"output_{i:04d}.mp3\"\n \n output_file = out_path / o\n print(f\" [{i}/{len(texts)}] Processing: {t[:50]}...\")\n \n if synthesize(t, v, str(output_file), voices_data, api_key, language, False, pronunciations):\n success += 1\n else:\n failed += 1\n \n # Rate limiting\n time.sleep(0.5)\n \n print(f\"\\nβœ… Complete: {success} success, {failed} failed\")\n print(f\"πŸ“ Output: {out_path}\")\n return success, failed\n\n\ndef test_voices(voices_data: dict, api_key: str):\n \"\"\"Test all voices with sample text.\"\"\"\n voices = voices_data.get(\"voices\", {})\n output_dir = SKILL_DIR / \"samples\"\n output_dir.mkdir(exist_ok=True)\n \n test_texts = {\n \"en\": \"Hello! This is a test of the ElevenLabs voice synthesis.\",\n \"de\": \"Hallo! Dies ist ein Test der ElevenLabs Sprachsynthese.\",\n \"es\": \"Β‘Hola! Esta es una prueba de la sΓ­ntesis de voz de ElevenLabs.\",\n \"fr\": \"Bonjour! Ceci est un test de la synthΓ¨se vocale ElevenLabs.\",\n \"it\": \"Ciao! Questo Γ¨ un test della sintesi vocale ElevenLabs.\"\n }\n \n print(\"πŸ§ͺ Testing all voices...\\n\")\n \n success = 0\n failed = 0\n \n for name, v in voices.items():\n lang = v.get(\"language\", \"en-US\")[:2]\n text = test_texts.get(lang, test_texts[\"en\"])\n output = output_dir / f\"{name}.mp3\"\n \n print(f\" Testing {name}...\", end=\" \", flush=True)\n if synthesize(text, name, str(output), voices_data, api_key):\n success += 1\n else:\n failed += 1\n \n print(f\"\\nβœ… Success: {success}, ❌ Failed: {failed}\")\n print(f\"πŸ“ Samples saved to: {output_dir}\")\n\n\ndef main():\n parser = argparse.ArgumentParser(\n description=\"ElevenLabs TTS with Voice Personas v2.0.0\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog=\"\"\"\nExamples:\n python3 tts.py --text \"Hello world\" --voice rachel\n python3 tts.py --text \"Bonjour\" --voice rachel --lang fr\n python3 tts.py --text \"Hello\" --voice rachel --stream\n python3 tts.py --batch texts.txt --voice adam --output-dir ./audio\n python3 tts.py --stats\n python3 tts.py --languages\n \"\"\"\n )\n \n # Input options\n parser.add_argument(\"--text\", \"-t\", help=\"Text to synthesize\")\n parser.add_argument(\"--batch\", \"-b\", help=\"Batch file (JSON or newline-separated)\")\n \n # Voice options\n parser.add_argument(\"--voice\", \"-v\", default=\"rachel\", help=\"Voice name or preset (default: rachel)\")\n parser.add_argument(\"--lang\", \"-L\", help=\"Language code (e.g., de, fr, es)\")\n \n # Output options\n parser.add_argument(\"--output\", \"-o\", default=\"output.mp3\", help=\"Output file (default: output.mp3)\")\n parser.add_argument(\"--output-dir\", \"-d\", default=\"./batch_output\", help=\"Output directory for batch mode\")\n parser.add_argument(\"--stream\", \"-s\", action=\"store_true\", help=\"Use streaming mode\")\n \n # Info options\n parser.add_argument(\"--list\", \"-l\", action=\"store_true\", help=\"List available voices\")\n parser.add_argument(\"--languages\", action=\"store_true\", help=\"List supported languages\")\n parser.add_argument(\"--test\", action=\"store_true\", help=\"Test all voices\")\n \n # Usage tracking\n parser.add_argument(\"--stats\", action=\"store_true\", help=\"Show usage statistics\")\n parser.add_argument(\"--reset-stats\", action=\"store_true\", help=\"Reset usage statistics\")\n \n # Advanced\n parser.add_argument(\"--no-pronunciations\", action=\"store_true\", help=\"Disable pronunciation dictionary\")\n \n args = parser.parse_args()\n \n voices_data = load_voices()\n \n # Info commands\n if args.list:\n list_voices(voices_data)\n return\n \n if args.languages:\n list_languages()\n return\n \n if args.stats:\n show_stats()\n return\n \n if args.reset_stats:\n reset_stats()\n return\n \n # Commands requiring API key\n api_key = get_api_key()\n \n if args.test:\n test_voices(voices_data, api_key)\n return\n \n # Load pronunciations unless disabled\n pronunciations = None if args.no_pronunciations else load_pronunciations()\n \n # Batch mode\n if args.batch:\n process_batch(\n args.batch,\n args.voice,\n args.output_dir,\n voices_data,\n api_key,\n args.lang,\n pronunciations\n )\n return\n \n # Single synthesis\n if not args.text:\n parser.print_help()\n print(\"\\n❌ --text or --batch is required for synthesis\")\n sys.exit(1)\n \n synthesize(\n args.text,\n args.voice,\n args.output,\n voices_data,\n api_key,\n args.lang,\n args.stream,\n pronunciations\n )\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":18134,"content_sha256":"011fc27104fe15d419c6c9be7f2170630d04f7b8e950582d369fa5fba78fbc4b"},{"filename":"scripts/voice-design.py","content":"#!/usr/bin/env python3\n\"\"\"\nElevenLabs Voice Design - Create Custom Voices from Text Description\n\nGenerate unique AI voices using ElevenLabs Voice Design API.\nDescribe the voice you want and get a preview, then optionally save it to your account.\n\nUsage:\n python3 voice-design.py --gender female --age middle_aged --accent american --description \"A warm, motherly voice with a gentle tone\"\n python3 voice-design.py --gender male --age young --accent british --description \"Energetic narrator\" --save \"MyNarrator\"\n\nAPI Documentation: https://elevenlabs.io/docs/api-reference/voice-generation\n\"\"\"\n\nimport argparse\nimport json\nimport os\nimport sys\nimport urllib.request\nimport urllib.error\nfrom pathlib import Path\nfrom datetime import datetime\n\nSCRIPT_DIR = Path(__file__).parent\nSKILL_DIR = SCRIPT_DIR.parent\n\n# ElevenLabs Voice Design API\nVOICE_DESIGN_URL = \"https://api.elevenlabs.io/v1/voice-generation/generate-voice\"\nVOICE_PREVIEW_URL = \"https://api.elevenlabs.io/v1/voice-generation/generate-voice/preview\"\n\n# Valid options for voice design\nVALID_GENDERS = [\"male\", \"female\", \"neutral\"]\nVALID_AGES = [\"young\", \"middle_aged\", \"old\"]\nVALID_ACCENTS = [\n \"american\", \"british\", \"african\", \"australian\", \"indian\",\n \"latin\", \"middle_eastern\", \"scandinavian\", \"eastern_european\"\n]\n\n# Sample texts for preview\nPREVIEW_TEXTS = {\n \"en\": \"Hello! This is a preview of my voice. I can speak naturally and expressively, adapting my tone to match any content you need.\",\n \"professional\": \"Welcome to our quarterly business review. Today, I'll be presenting our key achievements and strategic initiatives for the upcoming fiscal year.\",\n \"storytelling\": \"Once upon a time, in a land far, far away, there lived a curious young adventurer who dreamed of discovering the world's greatest mysteries.\",\n \"casual\": \"Hey there! Just checking in to see how you're doing. Hope you're having an awesome day! Let me know if you need anything.\",\n}\n\n\ndef get_api_key() -> str:\n \"\"\"Get API key from environment or OpenClaw config.\"\"\"\n api_key = os.environ.get(\"ELEVEN_API_KEY\") or os.environ.get(\"ELEVENLABS_API_KEY\")\n if api_key:\n return api_key\n \n config_paths = [\n Path.home() / \".openclaw\" / \"openclaw.json\",\n Path(\"/root/.openclaw/openclaw.json\"),\n ]\n \n for config_path in config_paths:\n if config_path.exists():\n try:\n config = json.loads(config_path.read_text())\n api_key = config.get(\"tts\", {}).get(\"elevenlabs\", {}).get(\"apiKey\")\n if api_key:\n return api_key\n except Exception:\n continue\n \n env_file = SKILL_DIR / \".env\"\n if env_file.exists():\n for line in env_file.read_text().splitlines():\n if line.startswith(\"ELEVEN_API_KEY=\"):\n return line.split(\"=\", 1)[1].strip().strip('\"\\'')\n \n print(\"❌ No ElevenLabs API key found.\")\n sys.exit(1)\n\n\ndef generate_voice_preview(\n gender: str,\n age: str,\n accent: str,\n accent_strength: float,\n description: str,\n preview_text: str,\n output_path: str,\n api_key: str\n) -> dict:\n \"\"\"\n Generate a preview of a designed voice.\n \n Returns generated_voice_id if successful.\n \"\"\"\n # Validate inputs\n if gender not in VALID_GENDERS:\n print(f\"❌ Invalid gender: {gender}\")\n print(f\" Valid options: {', '.join(VALID_GENDERS)}\")\n return None\n \n if age not in VALID_AGES:\n print(f\"❌ Invalid age: {age}\")\n print(f\" Valid options: {', '.join(VALID_AGES)}\")\n return None\n \n if accent not in VALID_ACCENTS:\n print(f\"❌ Invalid accent: {accent}\")\n print(f\" Valid options: {', '.join(VALID_ACCENTS)}\")\n return None\n \n headers = {\n \"xi-api-key\": api_key,\n \"Content-Type\": \"application/json\",\n }\n \n payload = {\n \"gender\": gender,\n \"age\": age,\n \"accent\": accent,\n \"accent_strength\": max(0.3, min(2.0, accent_strength)),\n \"text\": preview_text\n }\n \n # Add description if provided\n if description:\n payload[\"text\"] = f\"{description}\\n\\n{preview_text}\"\n \n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(VOICE_DESIGN_URL, data=data, headers=headers, method=\"POST\")\n \n print(f\"🎨 Designing voice...\")\n print(f\" Gender: {gender}\")\n print(f\" Age: {age}\")\n print(f\" Accent: {accent} (strength: {accent_strength})\")\n if description:\n print(f\" Description: {description[:50]}...\")\n \n try:\n with urllib.request.urlopen(req, timeout=60) as response:\n # Response includes audio and voice ID\n content_type = response.headers.get(\"Content-Type\", \"\")\n \n if \"audio\" in content_type:\n audio_data = response.read()\n with open(output_path, \"wb\") as f:\n f.write(audio_data)\n print(f\"βœ… Preview saved: {output_path}\")\n \n # Try to get voice ID from header\n voice_id = response.headers.get(\"generated_voice_id\")\n return {\"voice_id\": voice_id, \"audio_saved\": True}\n else:\n result = json.loads(response.read().decode(\"utf-8\"))\n \n # Save audio if included\n if \"audio_base64\" in result:\n import base64\n audio_data = base64.b64decode(result[\"audio_base64\"])\n with open(output_path, \"wb\") as f:\n f.write(audio_data)\n print(f\"βœ… Preview saved: {output_path}\")\n \n return result\n \n except urllib.error.HTTPError as e:\n error_body = e.read().decode(\"utf-8\") if e.fp else \"\"\n print(f\"❌ API Error ({e.code}): {error_body[:300]}\")\n return None\n except urllib.error.URLError as e:\n print(f\"❌ Network Error: {e.reason}\")\n return None\n\n\ndef save_voice_to_library(voice_id: str, name: str, description: str, api_key: str) -> bool:\n \"\"\"\n Save a generated voice preview to your ElevenLabs voice library.\n \n Note: This requires the voice_id from a preview generation.\n \"\"\"\n url = f\"https://api.elevenlabs.io/v1/voice-generation/create-voice\"\n \n headers = {\n \"xi-api-key\": api_key,\n \"Content-Type\": \"application/json\",\n }\n \n payload = {\n \"voice_name\": name,\n \"voice_description\": description or f\"Custom voice: {name}\",\n \"generated_voice_id\": voice_id,\n \"labels\": {\"type\": \"designed\", \"source\": \"openclaw-skill\"}\n }\n \n data = json.dumps(payload).encode(\"utf-8\")\n req = urllib.request.Request(url, data=data, headers=headers, method=\"POST\")\n \n try:\n with urllib.request.urlopen(req, timeout=30) as response:\n result = json.loads(response.read().decode(\"utf-8\"))\n saved_voice_id = result.get(\"voice_id\")\n print(f\"βœ… Voice saved to library!\")\n print(f\" Name: {name}\")\n print(f\" Voice ID: {saved_voice_id}\")\n print(f\"\\nπŸ’‘ Add this to voices.json to use with tts.py:\")\n print(f'''\n \"{name.lower().replace(' ', '_')}\": {{\n \"voice_id\": \"{saved_voice_id}\",\n \"name\": \"{name}\",\n \"language\": \"en-US\",\n \"gender\": \"custom\",\n \"persona\": \"designed\",\n \"description\": \"{description or 'Custom designed voice'}\",\n \"settings\": {{ \"stability\": 0.75, \"similarity_boost\": 0.75, \"style\": 0.5 }}\n }}\n''')\n return True\n \n except urllib.error.HTTPError as e:\n error_body = e.read().decode(\"utf-8\") if e.fp else \"\"\n print(f\"❌ Save Error ({e.code}): {error_body[:200]}\")\n return False\n except urllib.error.URLError as e:\n print(f\"❌ Network Error: {e.reason}\")\n return False\n\n\ndef list_options():\n \"\"\"Display all valid voice design options.\"\"\"\n print(\"🎨 Voice Design Options\\n\")\n \n print(\"Gender:\")\n for g in VALID_GENDERS:\n print(f\" β€’ {g}\")\n \n print(\"\\nAge:\")\n for a in VALID_AGES:\n print(f\" β€’ {a}\")\n \n print(\"\\nAccent:\")\n for a in VALID_ACCENTS:\n print(f\" β€’ {a}\")\n \n print(\"\\nAccent Strength: 0.3 - 2.0 (default: 1.0)\")\n print(\" β€’ 0.3-0.7: Subtle accent\")\n print(\" β€’ 0.8-1.2: Moderate accent\")\n print(\" β€’ 1.3-2.0: Strong accent\")\n \n print(\"\\nPreview Text Styles:\")\n for style, text in PREVIEW_TEXTS.items():\n print(f\" β€’ {style}: {text[:50]}...\")\n\n\ndef main():\n parser = argparse.ArgumentParser(\n description=\"ElevenLabs Voice Design - Create Custom Voices\",\n formatter_class=argparse.RawDescriptionHelpFormatter,\n epilog=\"\"\"\nExamples:\n # Generate a preview\n python3 voice-design.py --gender female --age middle_aged --accent american \\\\\n --description \"A warm, motherly voice\"\n \n # With custom preview text\n python3 voice-design.py --gender male --age young --accent british \\\\\n --text \"Welcome to the adventure!\"\n \n # Save to your library\n python3 voice-design.py --gender female --age young --accent american \\\\\n --description \"Energetic host\" --save \"MyHost\"\n \n # List all options\n python3 voice-design.py --options\n \"\"\"\n )\n \n # Voice characteristics\n parser.add_argument(\"--gender\", \"-g\", default=\"female\", \n help=f\"Gender ({', '.join(VALID_GENDERS)})\")\n parser.add_argument(\"--age\", \"-a\", default=\"middle_aged\",\n help=f\"Age ({', '.join(VALID_AGES)})\")\n parser.add_argument(\"--accent\", \"-c\", default=\"american\",\n help=f\"Accent ({', '.join(VALID_ACCENTS)})\")\n parser.add_argument(\"--accent-strength\", \"-s\", type=float, default=1.0,\n help=\"Accent strength (0.3-2.0, default: 1.0)\")\n \n # Description and text\n parser.add_argument(\"--description\", \"-d\", default=\"\",\n help=\"Voice description (characteristics, tone, personality)\")\n parser.add_argument(\"--text\", \"-t\", help=\"Custom preview text\")\n parser.add_argument(\"--style\", choices=list(PREVIEW_TEXTS.keys()), default=\"en\",\n help=\"Preview text style (default: en)\")\n \n # Output\n parser.add_argument(\"--output\", \"-o\", default=\"voice_preview.mp3\",\n help=\"Output file (default: voice_preview.mp3)\")\n \n # Save to library\n parser.add_argument(\"--save\", metavar=\"NAME\",\n help=\"Save voice to ElevenLabs library with this name\")\n \n # Info\n parser.add_argument(\"--options\", action=\"store_true\",\n help=\"List all valid options\")\n \n args = parser.parse_args()\n \n if args.options:\n list_options()\n return\n \n api_key = get_api_key()\n \n # Determine preview text\n preview_text = args.text or PREVIEW_TEXTS.get(args.style, PREVIEW_TEXTS[\"en\"])\n \n # Generate preview\n result = generate_voice_preview(\n args.gender,\n args.age,\n args.accent,\n args.accent_strength,\n args.description,\n preview_text,\n args.output,\n api_key\n )\n \n if not result:\n sys.exit(1)\n \n # Save to library if requested\n if args.save:\n voice_id = result.get(\"voice_id\") or result.get(\"generated_voice_id\")\n if voice_id:\n save_voice_to_library(\n voice_id,\n args.save,\n args.description,\n api_key\n )\n else:\n print(\"⚠️ Could not save: No voice ID returned from preview\")\n print(\" Try generating again and using --save with the resulting ID\")\n\n\nif __name__ == \"__main__\":\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":11842,"content_sha256":"e63a62f998e0eb880cf0bb9b854f80ae87b481e15ecd24d68962f7161320418a"},{"filename":"voices.json","content":"{\n \"voices\": {\n \"rachel\": {\n \"voice_id\": \"EXAVITQu4vr4xnSDxMaL\",\n \"name\": \"Sarah\",\n \"language\": \"en-US\",\n \"gender\": \"female\",\n \"persona\": \"warm\",\n \"description\": \"Mature, reassuring, confident. Perfect for conversational content.\",\n \"settings\": { \"stability\": 0.75, \"similarity_boost\": 0.75, \"style\": 0.5 },\n \"use_cases\": [\"conversation\", \"tutorials\", \"friendly content\", \"narration\"]\n },\n \"adam\": {\n \"voice_id\": \"pNInz6obpgDQGcFmaJgB\",\n \"name\": \"Adam\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"narrator\",\n \"description\": \"Dominant, firm male voice. Ideal for documentaries and serious narration.\",\n \"settings\": { \"stability\": 0.80, \"similarity_boost\": 0.75, \"style\": 0.4 },\n \"use_cases\": [\"documentaries\", \"audiobooks\", \"professional narration\", \"news\"]\n },\n \"bella\": {\n \"voice_id\": \"hpp4J3VqNfWA7E7KEGDY\",\n \"name\": \"Bella\",\n \"language\": \"en-US\",\n \"gender\": \"female\",\n \"persona\": \"professional\",\n \"description\": \"Professional, bright, warm female voice.\",\n \"settings\": { \"stability\": 0.70, \"similarity_boost\": 0.80, \"style\": 0.6 },\n \"use_cases\": [\"business\", \"tutorials\", \"professional content\", \"presentations\"]\n },\n \"brian\": {\n \"voice_id\": \"nPczCjzI2devNBz1zQrb\",\n \"name\": \"Brian\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"comforting\",\n \"description\": \"Deep, resonant and comforting. Great for meditation and calm content.\",\n \"settings\": { \"stability\": 0.80, \"similarity_boost\": 0.75, \"style\": 0.4 },\n \"use_cases\": [\"meditation\", \"calm content\", \"bedtime stories\", \"relaxation\"]\n },\n \"george\": {\n \"voice_id\": \"JBFqnCBsd6RMkjVDRZzb\",\n \"name\": \"George\",\n \"language\": \"en-GB\",\n \"gender\": \"male\",\n \"persona\": \"storyteller\",\n \"description\": \"Warm, captivating British storyteller. Perfect for audiobooks.\",\n \"settings\": { \"stability\": 0.75, \"similarity_boost\": 0.80, \"style\": 0.5 },\n \"use_cases\": [\"audiobooks\", \"storytelling\", \"narration\", \"british content\"]\n },\n \"alice\": {\n \"voice_id\": \"Xb7hH8MSUJpSbSDYk0k2\",\n \"name\": \"Alice\",\n \"language\": \"en-GB\",\n \"gender\": \"female\",\n \"persona\": \"educator\",\n \"description\": \"Clear, engaging British educator. Ideal for tutorials and explanations.\",\n \"settings\": { \"stability\": 0.80, \"similarity_boost\": 0.75, \"style\": 0.4 },\n \"use_cases\": [\"education\", \"tutorials\", \"explanations\", \"british content\"]\n },\n \"callum\": {\n \"voice_id\": \"N2lVS1w4EtoT3dr4eOWO\",\n \"name\": \"Callum\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"trickster\",\n \"description\": \"Husky trickster voice. Great for playful, mischievous content.\",\n \"settings\": { \"stability\": 0.70, \"similarity_boost\": 0.80, \"style\": 0.6 },\n \"use_cases\": [\"playful content\", \"entertainment\", \"gaming\", \"casual\"]\n },\n \"charlie\": {\n \"voice_id\": \"IKne3meq5aSn9XLyUdCD\",\n \"name\": \"Charlie\",\n \"language\": \"en-AU\",\n \"gender\": \"male\",\n \"persona\": \"energetic\",\n \"description\": \"Deep, confident, energetic Australian voice.\",\n \"settings\": { \"stability\": 0.75, \"similarity_boost\": 0.75, \"style\": 0.5 },\n \"use_cases\": [\"sports\", \"energetic content\", \"australian content\", \"motivation\"]\n },\n \"jessica\": {\n \"voice_id\": \"cgSgspJ2msm64kCltF4R\",\n \"name\": \"Jessica\",\n \"language\": \"en-US\",\n \"gender\": \"female\",\n \"persona\": \"playful\",\n \"description\": \"Playful, bright, warm. Great for friendly, casual content.\",\n \"settings\": { \"stability\": 0.70, \"similarity_boost\": 0.80, \"style\": 0.6 },\n \"use_cases\": [\"friendly content\", \"social media\", \"casual\", \"youth content\"]\n },\n \"lily\": {\n \"voice_id\": \"pFZP5JQG7iQjIQuC4Bku\",\n \"name\": \"Lily\",\n \"language\": \"en-GB\",\n \"gender\": \"female\",\n \"persona\": \"actress\",\n \"description\": \"Velvety British actress voice. Elegant and sophisticated.\",\n \"settings\": { \"stability\": 0.75, \"similarity_boost\": 0.80, \"style\": 0.5 },\n \"use_cases\": [\"drama\", \"audiobooks\", \"elegant content\", \"storytelling\"]\n },\n \"matilda\": {\n \"voice_id\": \"XrExE9yKIg1WjnnlVkGX\",\n \"name\": \"Matilda\",\n \"language\": \"en-US\",\n \"gender\": \"female\",\n \"persona\": \"professional\",\n \"description\": \"Knowledgeable, professional. Perfect for informative content.\",\n \"settings\": { \"stability\": 0.85, \"similarity_boost\": 0.75, \"style\": 0.3 },\n \"use_cases\": [\"professional\", \"informative\", \"corporate\", \"news\"]\n },\n \"river\": {\n \"voice_id\": \"SAz9YHcvj6GT2YYXdXww\",\n \"name\": \"River\",\n \"language\": \"en-US\",\n \"gender\": \"neutral\",\n \"persona\": \"neutral\",\n \"description\": \"Relaxed, neutral, informative. Androgynous voice for inclusive content.\",\n \"settings\": { \"stability\": 0.80, \"similarity_boost\": 0.75, \"style\": 0.4 },\n \"use_cases\": [\"neutral content\", \"informative\", \"inclusive\", \"general\"]\n },\n \"roger\": {\n \"voice_id\": \"CwhRBWXzGAHq8TQ4Fs17\",\n \"name\": \"Roger\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"casual\",\n \"description\": \"Laid-back, casual, resonant. Great for relaxed, friendly content.\",\n \"settings\": { \"stability\": 0.70, \"similarity_boost\": 0.80, \"style\": 0.5 },\n \"use_cases\": [\"casual\", \"podcasts\", \"friendly\", \"relaxed\"]\n },\n \"daniel\": {\n \"voice_id\": \"onwK4e9ZLuTAKqWW03F9\",\n \"name\": \"Daniel\",\n \"language\": \"en-GB\",\n \"gender\": \"male\",\n \"persona\": \"broadcaster\",\n \"description\": \"Steady British broadcaster. Professional news anchor style.\",\n \"settings\": { \"stability\": 0.85, \"similarity_boost\": 0.75, \"style\": 0.3 },\n \"use_cases\": [\"news\", \"broadcasting\", \"professional\", \"announcements\"]\n },\n \"eric\": {\n \"voice_id\": \"cjVigY5qzO86Huf0OWal\",\n \"name\": \"Eric\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"trustworthy\",\n \"description\": \"Smooth, trustworthy voice. Ideal for credible, professional content.\",\n \"settings\": { \"stability\": 0.85, \"similarity_boost\": 0.75, \"style\": 0.3 },\n \"use_cases\": [\"business\", \"trustworthy\", \"corporate\", \"professional\"]\n },\n \"chris\": {\n \"voice_id\": \"iP95p4xoKVk53GoZ742B\",\n \"name\": \"Chris\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"friendly\",\n \"description\": \"Charming, down-to-earth. Great for approachable, friendly content.\",\n \"settings\": { \"stability\": 0.75, \"similarity_boost\": 0.75, \"style\": 0.5 },\n \"use_cases\": [\"friendly\", \"approachable\", \"tutorials\", \"casual\"]\n },\n \"will\": {\n \"voice_id\": \"bIHbv24MWmeRgasZH58o\",\n \"name\": \"Will\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"optimist\",\n \"description\": \"Relaxed optimist. Positive, uplifting voice.\",\n \"settings\": { \"stability\": 0.75, \"similarity_boost\": 0.80, \"style\": 0.5 },\n \"use_cases\": [\"positive content\", \"motivation\", \"uplifting\", \"friendly\"]\n },\n \"liam\": {\n \"voice_id\": \"TX3LPaxmHKxFdv7VOQHJ\",\n \"name\": \"Liam\",\n \"language\": \"en-US\",\n \"gender\": \"male\",\n \"persona\": \"social\",\n \"description\": \"Energetic social media creator voice. Youthful and dynamic.\",\n \"settings\": { \"stability\": 0.70, \"similarity_boost\": 0.80, \"style\": 0.7 },\n \"use_cases\": [\"social media\", \"youtube\", \"energetic\", \"youth\"]\n }\n },\n \"presets\": {\n \"default\": \"rachel\",\n \"narrator\": \"adam\",\n \"professional\": \"matilda\",\n \"warm\": \"rachel\",\n \"energetic\": \"liam\",\n \"trustworthy\": \"eric\",\n \"storyteller\": \"george\",\n \"educator\": \"alice\",\n \"british\": \"george\",\n \"australian\": \"charlie\",\n \"calm\": \"brian\",\n \"neutral\": \"river\",\n \"broadcaster\": \"daniel\"\n },\n \"languages\": {\n \"en-US\": [\"rachel\", \"adam\", \"bella\", \"brian\", \"callum\", \"jessica\", \"matilda\", \"river\", \"roger\", \"eric\", \"chris\", \"will\", \"liam\"],\n \"en-GB\": [\"george\", \"alice\", \"lily\", \"daniel\"],\n \"en-AU\": [\"charlie\"]\n },\n \"supported_languages\": [\n \"en\", \"de\", \"es\", \"fr\", \"it\", \"pt\", \"pl\", \"nl\", \"sv\", \"da\", \"fi\", \"no\",\n \"tr\", \"ru\", \"uk\", \"cs\", \"sk\", \"hu\", \"ro\", \"bg\", \"hr\", \"el\", \"hi\", \"ta\",\n \"id\", \"ms\", \"vi\", \"th\", \"ja\", \"ko\", \"zh\", \"ar\"\n ],\n \"model\": \"eleven_multilingual_v2\",\n \"version\": \"2.0.0\"\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":8356,"content_sha256":"32e1e68fda8d4f01b3c0133593e1f3abf4d71100cf3d54c4a54697d3d32da760"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"ElevenLabs Voice Personas v2.1","type":"text"}]},{"type":"paragraph","content":[{"text":"Comprehensive voice synthesis toolkit using ElevenLabs API.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸš€ First Run - Setup Wizard","type":"text"}]},{"type":"paragraph","content":[{"text":"When you first use this skill (no ","type":"text"},{"text":"config.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" exists), run the interactive setup wizard:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 scripts/setup.py","type":"text"}]},{"type":"paragraph","content":[{"text":"The wizard will guide you through:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"API Key","type":"text","marks":[{"type":"strong"}]},{"text":" - Enter your ElevenLabs API key (required)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Default Voice","type":"text","marks":[{"type":"strong"}]},{"text":" - Choose from popular voices (Rachel, Adam, Bella, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Language","type":"text","marks":[{"type":"strong"}]},{"text":" - Set your preferred language (32 supported)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Audio Quality","type":"text","marks":[{"type":"strong"}]},{"text":" - Standard or high quality output","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cost Tracking","type":"text","marks":[{"type":"strong"}]},{"text":" - Enable usage and cost monitoring","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Budget Limit","type":"text","marks":[{"type":"strong"}]},{"text":" - Optional monthly spending cap","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"πŸ”’ Privacy:","type":"text","marks":[{"type":"strong"}]},{"text":" Your API key is stored locally in ","type":"text"},{"text":"config.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" only. It never leaves your machine and is automatically excluded from git via ","type":"text"},{"text":".gitignore","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"paragraph","content":[{"text":"To reconfigure at any time, simply run the setup wizard again.","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"✨ Features","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"18 Voice Personas","type":"text","marks":[{"type":"strong"}]},{"text":" - Carefully curated voices for different use cases","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"32 Languages","type":"text","marks":[{"type":"strong"}]},{"text":" - Multi-language synthesis with the multilingual v2 model","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Streaming Mode","type":"text","marks":[{"type":"strong"}]},{"text":" - Real-time audio output as it generates","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Sound Effects (SFX)","type":"text","marks":[{"type":"strong"}]},{"text":" - AI-generated sound effects from text prompts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Batch Processing","type":"text","marks":[{"type":"strong"}]},{"text":" - Process multiple texts in one go","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cost Tracking","type":"text","marks":[{"type":"strong"}]},{"text":" - Monitor character usage and estimated costs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Voice Design","type":"text","marks":[{"type":"strong"}]},{"text":" - Create custom voices from descriptions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pronunciation Dictionary","type":"text","marks":[{"type":"strong"}]},{"text":" - Custom word pronunciation rules","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"OpenClaw Integration","type":"text","marks":[{"type":"strong"}]},{"text":" - Works with OpenClaw's built-in TTS","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸŽ™οΈ Available Voices","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Voice","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Accent","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Gender","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Persona","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Best For","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"rachel","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"female","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"warm","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Conversations, tutorials","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"adam","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"narrator","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Documentaries, audiobooks","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"bella","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"female","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"professional","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Business, presentations","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"brian","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"comforting","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meditation, calm content","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"george","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡¬πŸ‡§ UK","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"storyteller","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Audiobooks, storytelling","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"alice","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡¬πŸ‡§ UK","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"female","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"educator","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tutorials, explanations","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"callum","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"trickster","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Playful, gaming","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"charlie","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡¦πŸ‡Ί AU","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"energetic","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Sports, motivation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"jessica","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"female","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"playful","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Social media, casual","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"lily","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡¬πŸ‡§ UK","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"female","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"actress","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Drama, elegant content","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"matilda","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"female","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"professional","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Corporate, news","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"river","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"neutral","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"neutral","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Inclusive, informative","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"roger","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"casual","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Podcasts, relaxed","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"daniel","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡¬πŸ‡§ UK","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"broadcaster","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"News, announcements","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"eric","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"trustworthy","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Business, corporate","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"chris","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"friendly","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tutorials, approachable","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"will","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"optimist","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Motivation, uplifting","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"liam","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"πŸ‡ΊπŸ‡Έ US","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"social","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"YouTube, social media","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"🎯 Quick Presets","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"default","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ rachel (warm, friendly)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"narrator","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ adam (documentaries)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"professional","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ matilda (corporate)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"storyteller","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ george (audiobooks)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"educator","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ alice (tutorials)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"calm","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ brian (meditation)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"energetic","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ liam (social media)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"trustworthy","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ eric (business)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"neutral","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ river (inclusive)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"british","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ george","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"australian","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ charlie","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"broadcaster","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ daniel (news)","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"🌍 Supported Languages (32)","type":"text"}]},{"type":"paragraph","content":[{"text":"The multilingual v2 model supports these languages:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Code","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Language","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Code","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Language","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"en","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"English","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pl","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Polish","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"de","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"German","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"nl","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Dutch","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"es","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Spanish","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sv","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Swedish","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fr","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"French","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"da","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Danish","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"it","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Italian","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"fi","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Finnish","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"pt","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Portuguese","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"no","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Norwegian","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ru","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Russian","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tr","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Turkish","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"uk","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Ukrainian","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"cs","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Czech","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ja","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Japanese","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"sk","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Slovak","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ko","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Korean","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"hu","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hungarian","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"zh","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Chinese","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ro","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Romanian","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ar","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Arabic","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"bg","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Bulgarian","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"hi","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Hindi","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"hr","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Croatian","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ta","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tamil","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"el","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Greek","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"id","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Indonesian","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ms","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Malay","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"vi","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Vietnamese","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"th","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Thai","type":"text"}]}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Synthesize in German\npython3 tts.py --text \"Guten Tag!\" --voice rachel --lang de\n\n# Synthesize in French\npython3 tts.py --text \"Bonjour le monde!\" --voice adam --lang fr\n\n# List all languages\npython3 tts.py --languages","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ’» CLI Usage","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Basic Text-to-Speech","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# List all voices\npython3 scripts/tts.py --list\n\n# Generate speech\npython3 scripts/tts.py --text \"Hello world\" --voice rachel --output hello.mp3\n\n# Use a preset\npython3 scripts/tts.py --text \"Breaking news...\" --voice broadcaster --output news.mp3\n\n# Multi-language\npython3 scripts/tts.py --text \"Bonjour!\" --voice rachel --lang fr --output french.mp3","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Streaming Mode","type":"text"}]},{"type":"paragraph","content":[{"text":"Generate audio with real-time streaming (good for long texts):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Stream audio as it generates\npython3 scripts/tts.py --text \"This is a long story...\" --voice adam --stream\n\n# Streaming with custom output\npython3 scripts/tts.py --text \"Chapter one...\" --voice george --stream --output chapter1.mp3","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Batch Processing","type":"text"}]},{"type":"paragraph","content":[{"text":"Process multiple texts from a file:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# From newline-separated text file\npython3 scripts/tts.py --batch texts.txt --voice rachel --output-dir ./audio\n\n# From JSON file\npython3 scripts/tts.py --batch batch.json --output-dir ./output","type":"text"}]},{"type":"paragraph","content":[{"text":"JSON batch format:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"[\n {\"text\": \"First line\", \"voice\": \"rachel\", \"output\": \"line1.mp3\"},\n {\"text\": \"Second line\", \"voice\": \"adam\", \"output\": \"line2.mp3\"},\n {\"text\": \"Third line\"}\n]","type":"text"}]},{"type":"paragraph","content":[{"text":"Simple text format (one per line):","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Hello, this is the first sentence.\nThis is the second sentence.\nAnd this is the third.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Usage Statistics","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Show usage stats and cost estimates\npython3 scripts/tts.py --stats\n\n# Reset statistics\npython3 scripts/tts.py --reset-stats","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"🎡 Sound Effects (SFX)","type":"text"}]},{"type":"paragraph","content":[{"text":"Generate AI-powered sound effects from text descriptions:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Generate a sound effect\npython3 scripts/sfx.py --prompt \"Thunder rumbling in the distance\"\n\n# With specific duration (0.5-22 seconds)\npython3 scripts/sfx.py --prompt \"Cat meowing\" --duration 3 --output cat.mp3\n\n# Adjust prompt influence (0.0-1.0)\npython3 scripts/sfx.py --prompt \"Footsteps on gravel\" --influence 0.5\n\n# Batch SFX generation\npython3 scripts/sfx.py --batch sounds.json --output-dir ./sfx\n\n# Show prompt examples\npython3 scripts/sfx.py --examples","type":"text"}]},{"type":"paragraph","content":[{"text":"Example prompts:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Thunder rumbling in the distance\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Cat purring contentedly\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Typing on a mechanical keyboard\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Spaceship engine humming\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"Coffee shop background chatter\"","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"🎨 Voice Design","type":"text"}]},{"type":"paragraph","content":[{"text":"Create custom voices from text descriptions:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Basic voice design\npython3 scripts/voice-design.py --gender female --age middle_aged --accent american \\\n --description \"A warm, motherly voice\"\n\n# With custom preview text\npython3 scripts/voice-design.py --gender male --age young --accent british \\\n --text \"Welcome to the adventure!\" --output preview.mp3\n\n# Save to your ElevenLabs library\npython3 scripts/voice-design.py --gender female --age young --accent american \\\n --description \"Energetic podcast host\" --save \"MyHost\"\n\n# List all design options\npython3 scripts/voice-design.py --options","type":"text"}]},{"type":"paragraph","content":[{"text":"Voice Design Options:","type":"text","marks":[{"type":"strong"}]}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Option","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Values","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Gender","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"male, female, neutral","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Age","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"young, middle_aged, old","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Accent","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"american, british, african, australian, indian, latin, middle_eastern, scandinavian, eastern_european","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Accent Strength","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.3-2.0 (subtle to strong)","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ“– Pronunciation Dictionary","type":"text"}]},{"type":"paragraph","content":[{"text":"Customize how words are pronounced:","type":"text"}]},{"type":"paragraph","content":[{"text":"Edit ","type":"text"},{"text":"pronunciations.json","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"rules\": [\n {\n \"word\": \"OpenClaw\",\n \"replacement\": \"Open Claw\",\n \"comment\": \"Pronounce as two words\"\n },\n {\n \"word\": \"API\",\n \"replacement\": \"A P I\",\n \"comment\": \"Spell out acronym\"\n }\n ]\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Usage:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Pronunciations are applied automatically\npython3 scripts/tts.py --text \"The OpenClaw API is great\" --voice rachel\n\n# Disable pronunciations\npython3 scripts/tts.py --text \"The API is great\" --voice rachel --no-pronunciations","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ’° Cost Tracking","type":"text"}]},{"type":"paragraph","content":[{"text":"The skill tracks your character usage and estimates costs:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"python3 scripts/tts.py --stats","type":"text"}]},{"type":"paragraph","content":[{"text":"Output:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"πŸ“Š ElevenLabs Usage Statistics\n\n Total Characters: 15,230\n Total Requests: 42\n Since: 2024-01-15\n\nπŸ’° Estimated Costs:\n Starter $4.57 ($0.30/1k chars)\n Creator $3.66 ($0.24/1k chars)\n Pro $2.74 ($0.18/1k chars)\n Scale $1.68 ($0.11/1k chars)","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ€– OpenClaw TTS Integration","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Using with OpenClaw's Built-in TTS","type":"text"}]},{"type":"paragraph","content":[{"text":"OpenClaw has built-in TTS support that can use ElevenLabs. Configure in ","type":"text"},{"text":"~/.openclaw/openclaw.json","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"tts\": {\n \"enabled\": true,\n \"provider\": \"elevenlabs\",\n \"elevenlabs\": {\n \"apiKey\": \"your-api-key-here\",\n \"voice\": \"rachel\",\n \"model\": \"eleven_multilingual_v2\"\n }\n }\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Triggering TTS in Chat","type":"text"}]},{"type":"paragraph","content":[{"text":"In OpenClaw conversations:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"/tts on","type":"text","marks":[{"type":"code_inline"}]},{"text":" to enable automatic TTS","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use the ","type":"text"},{"text":"tts","type":"text","marks":[{"type":"code_inline"}]},{"text":" tool directly for one-off speech","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Request \"read this aloud\" or \"speak this\"","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Using Skill Scripts from OpenClaw","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# OpenClaw can run these scripts directly\nexec python3 /path/to/skills/elevenlabs-voices/scripts/tts.py --text \"Hello\" --voice rachel","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"βš™οΈ Configuration","type":"text"}]},{"type":"paragraph","content":[{"text":"The scripts look for API key in this order:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ELEVEN_API_KEY","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"ELEVENLABS_API_KEY","type":"text","marks":[{"type":"code_inline"}]},{"text":" environment variable","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"OpenClaw config (","type":"text"},{"text":"~/.openclaw/openclaw.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" β†’ tts.elevenlabs.apiKey)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Skill-local ","type":"text"},{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":" file","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Create .env file:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"echo 'ELEVEN_API_KEY=your-key-here' > .env","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸŽ›οΈ Voice Settings","type":"text"}]},{"type":"paragraph","content":[{"text":"Each voice has tuned settings for optimal output:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Setting","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Range","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Description","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"stability","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.0-1.0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Higher = consistent, lower = expressive","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"similarity_boost","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.0-1.0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"How closely to match original voice","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"style","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"0.0-1.0","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Exaggeration of speaking style","type":"text"}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ“ Triggers","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"use {voice_name} voice\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"speak as {persona}\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"list voices\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"voice settings\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"generate sound effect\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"design a voice\"","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ“ Files","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"elevenlabs-voices/\nβ”œβ”€β”€ SKILL.md # This documentation\nβ”œβ”€β”€ README.md # Quick start guide\nβ”œβ”€β”€ config.json # Your local config (created by setup, in .gitignore)\nβ”œβ”€β”€ voices.json # Voice definitions & settings\nβ”œβ”€β”€ pronunciations.json # Custom pronunciation rules\nβ”œβ”€β”€ examples.md # Detailed usage examples\nβ”œβ”€β”€ scripts/\nβ”‚ β”œβ”€β”€ setup.py # Interactive setup wizard\nβ”‚ β”œβ”€β”€ tts.py # Main TTS script\nβ”‚ β”œβ”€β”€ sfx.py # Sound effects generator\nβ”‚ └── voice-design.py # Voice design tool\n└── references/\n └── voice-guide.md # Voice selection guide","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ”— Links","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ElevenLabs","type":"text","marks":[{"type":"link","attrs":{"href":"https://elevenlabs.io","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"API Documentation","type":"text","marks":[{"type":"link","attrs":{"href":"https://docs.elevenlabs.io","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Voice Library","type":"text","marks":[{"type":"link","attrs":{"href":"https://elevenlabs.io/voice-library","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Sound Effects API","type":"text","marks":[{"type":"link","attrs":{"href":"https://elevenlabs.io/docs/api-reference/sound-generation","title":null}}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Voice Design API","type":"text","marks":[{"type":"link","attrs":{"href":"https://elevenlabs.io/docs/api-reference/voice-generation","title":null}}]}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":2},"content":[{"text":"πŸ“‹ Changelog","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"v2.1.0","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added interactive setup wizard (","type":"text"},{"text":"scripts/setup.py","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Onboarding guides through API key, voice, language, quality, and budget settings","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Config stored locally in ","type":"text"},{"text":"config.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" (added to ","type":"text"},{"text":".gitignore","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Professional, privacy-focused setup experience","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"v2.0.0","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added 32 language support with ","type":"text"},{"text":"--lang","type":"text","marks":[{"type":"code_inline"}]},{"text":" parameter","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added streaming mode with ","type":"text"},{"text":"--stream","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added sound effects generation (","type":"text"},{"text":"sfx.py","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added batch processing with ","type":"text"},{"text":"--batch","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added cost tracking with ","type":"text"},{"text":"--stats","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added voice design tool (","type":"text"},{"text":"voice-design.py","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added pronunciation dictionary support","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Added OpenClaw TTS integration documentation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Improved error handling and progress output","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"elevenlabs-voices","tags":["tts","voice","speech","elevenlabs","audio","sound-effects","voice-design","multilingual"],"author":"@skillopedia","source":{"stars":609,"repo_name":"awesome-openclaw-skills","origin_url":"https://github.com/sundial-org/awesome-openclaw-skills/blob/HEAD/skills/elevenlabs-voices/SKILL.md","repo_owner":"sundial-org","body_sha256":"308abe6a098bcd2eb79314875bade20a232f243353396c4aff2f6380463d99d5","cluster_key":"107294db899f69d09146246492b27a7dae78799e50d9c17f73a58a42eea257d0","clean_bundle":{"format":"clean-skill-bundle-v1","source":"sundial-org/awesome-openclaw-skills/skills/elevenlabs-voices/SKILL.md","attachments":[{"id":"ace25e85-a613-5eb3-983b-e7d95090c774","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ace25e85-a613-5eb3-983b-e7d95090c774/attachment.md","path":"README.md","size":1806,"sha256":"94ae8fc27df2797b1196840cc0977cef3c961d4eb8b5c91c3a013ca2a2fa1f26","contentType":"text/markdown; charset=utf-8"},{"id":"36dc9776-729b-5c30-b37f-3f2b7a1a0e8a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/36dc9776-729b-5c30-b37f-3f2b7a1a0e8a/attachment.md","path":"examples.md","size":14107,"sha256":"de74e902bef52f56b736287a714eac2b6703dad38eaf9dc0a8e791041270af9f","contentType":"text/markdown; charset=utf-8"},{"id":"886aa8b0-3588-5221-b305-a82bc5770760","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/886aa8b0-3588-5221-b305-a82bc5770760/attachment.json","path":"package.json","size":455,"sha256":"14b36862d062bd888744349d700e2c2ee72f6ec8cd2469add2572b782497c108","contentType":"application/json; charset=utf-8"},{"id":"e9b9d4be-a699-5788-8eed-e916308918b4","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e9b9d4be-a699-5788-8eed-e916308918b4/attachment.json","path":"pronunciations.json","size":1603,"sha256":"e3e2ad5dde61cb6e2656d52d6ae1f6b1bbd71f0fa0ebbadef3a7455ed202e3d7","contentType":"application/json; charset=utf-8"},{"id":"644e226b-9653-5b07-9662-50981fd9292f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/644e226b-9653-5b07-9662-50981fd9292f/attachment.md","path":"references/voice-guide.md","size":8006,"sha256":"bb447bf045b686a94bb9cc6f96d2a54ef5deabd814c4b27cf1e82bba52111250","contentType":"text/markdown; charset=utf-8"},{"id":"7428ec23-ee99-5dc3-9efc-8abbb69e5c5a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7428ec23-ee99-5dc3-9efc-8abbb69e5c5a/attachment.py","path":"scripts/setup.py","size":10507,"sha256":"0be510b307d61839d93f0561f52c8c65dcd8343cf0a8e5c87c7fad0839c9e3a3","contentType":"text/x-python; charset=utf-8"},{"id":"03ae2925-fe7c-570c-bdfc-792b2edb5a7c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/03ae2925-fe7c-570c-bdfc-792b2edb5a7c/attachment.py","path":"scripts/sfx.py","size":9951,"sha256":"3fedc9fdb883824fbc2914614d2b3904e2581be30e912117068405f397d66931","contentType":"text/x-python; charset=utf-8"},{"id":"fd1ba925-4c0c-50e9-9fba-80edd29a5229","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fd1ba925-4c0c-50e9-9fba-80edd29a5229/attachment.py","path":"scripts/tts.py","size":18134,"sha256":"011fc27104fe15d419c6c9be7f2170630d04f7b8e950582d369fa5fba78fbc4b","contentType":"text/x-python; charset=utf-8"},{"id":"d71dfd8b-aaef-5d8d-83b6-a425a482c1a9","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d71dfd8b-aaef-5d8d-83b6-a425a482c1a9/attachment.py","path":"scripts/voice-design.py","size":11842,"sha256":"e63a62f998e0eb880cf0bb9b854f80ae87b481e15ecd24d68962f7161320418a","contentType":"text/x-python; charset=utf-8"},{"id":"bd882cd0-695b-5676-8c57-92186fa1ff59","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/bd882cd0-695b-5676-8c57-92186fa1ff59/attachment.json","path":"voices.json","size":8356,"sha256":"32e1e68fda8d4f01b3c0133593e1f3abf4d71100cf3d54c4a54697d3d32da760","contentType":"application/json; charset=utf-8"}],"bundle_sha256":"e6abf3414f4e96c3dd826eae210605d38abe208828a7a8b50c3aeb74d541a14d","attachment_count":10,"text_attachments":10,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":2,"skill_md_path":"skills/elevenlabs-voices/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"design-ux","category_label":"Design"},"exact_dupes_collapsed_into_this":1},"version":"v1","category":"design-ux","import_tag":"clean-skills-v1","description":"High-quality voice synthesis with 18 personas, 32 languages, sound effects, batch processing, and voice design using ElevenLabs API."}},"renderedAt":1782981803698}

ElevenLabs Voice Personas v2.1 Comprehensive voice synthesis toolkit using ElevenLabs API. πŸš€ First Run - Setup Wizard When you first use this skill (no exists), run the interactive setup wizard: The wizard will guide you through: 1. API Key - Enter your ElevenLabs API key (required) 2. Default Voice - Choose from popular voices (Rachel, Adam, Bella, etc.) 3. Language - Set your preferred language (32 supported) 4. Audio Quality - Standard or high quality output 5. Cost Tracking - Enable usage and cost monitoring 6. Budget Limit - Optional monthly spending cap πŸ”’ Privacy: Your API key is stor…