SuperAPI AI Directory

voiceover-maker

Office & productivity

View repository

Updated 10-15 11:45

About this skill

voiceover-maker — Multi-provider TTS voiceover generator

Author: Produced by 43 COLLEGE 凯寓 (KAIYU) Version: v1.0

Throw any text in → MP3 voiceover audio file.Automatic routing by language:

  • Chinese → MiniMax (better Chinese quality)
  • English → ElevenLabs

Trigger scenarios

  • "Use TTS to generate a voiceover / narration / dubbing / read-aloud from this passage"
  • "Turn this text into speech / read it out / record it as audio"
  • "Make a video narration MP3"
  • "voice this / narrate this / read this aloud"
  • "Record this WeChat official account article as audio"

Do not trigger: the user is only asking "what does TTS mean" — this is a general-knowledge question. The Skill is only used togenerate MP3 files。

First-time use

You need to configure the API key of at least one provider first (recommended to configure both, for automatic routing by language). See SETUP.md。

Cross-platform compatibility

Project macOS / Linux Windows
Python python3 python
Path separator / \
Script path ${CLAUDE_SKILL_DIR}/scripts/tts.py ${CLAUDE_SKILL_DIR}\scripts\tts.py

All examples below use the python3 style (Mac/Linux). Windows users should replace python3 with python, and / with \ .

About ${CLAUDE_SKILL_DIR}: this is a documentation placeholder representing the installation directory of this skill (usually ~/.claude/skills/voiceover-maker/). Claude will automatically replace it with the actual path when executing commands in bash,users should not copy this string directly into the terminal— copying and pasting directly will fail because the variable is undefined. Either hand the command to the AI to execute, or replace it yourself with the specific directory.

Main script

scripts/tts.py, zero dependencies (only the Python 3 standard library).

Preflight (recommended for first-time use)

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --check

Does not call the real synthesis API, only checks: whether config.json exists and can be parsed, whether the ElevenLabs / MiniMax keys are filled in, whether the silent asset is in place, and the network reachability of the two endpoints. After configuring the keys, run the preflight once to confirm there are no problems before doing the actual synthesis.

Basic usage

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "你好世界,这是一段中文测试。"   # auto → MiniMax
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "Hello world, this is a test."   # auto → ElevenLabs

Output defaults to ~/Desktop, filename tts-{provider}-{voice}-{timestamp}.mp3。

Specify a voice (case-insensitive)

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "中文" --voice lyrical          # MiniMax 抒情男声
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "中文" --voice news_anchor      # MiniMax 新闻女声
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "English" --voice rachel        # ElevenLabs Rachel

--voice accepts both preset names and raw voice_id pass-through.

Force a provider

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "文本" --provider minimax
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "文本" --provider elevenlabs

MiniMax emotion / speed / pitch / volume

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "好消息!" --emotion happy --speed 1.1
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "深夜独白" --voice radio_host --emotion sad --speed 0.9
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "正式播报" --voice executive --pitch -2 --vol 1.2
  • --emotion:neutral / happy / sad / angry / fearful / disgusted / surprised
  • --speed:0.5–2.0
  • --pitch:-12–12
  • --vol:0.5–2.0

ElevenLabs does not support these parameters; if passed, they will be ignored and a warning will be logged.

Long text (read from a file + automatic segmentation)

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --file 旁白稿.txt
  • MiniMax single-call limit is 9500 characters (buffer kept; original 10000)
  • ElevenLabs single-call limit is 4500 characters
  • Overly long text is automatically segmented in the order paragraph → sentence-ending punctuation → hard cut, and the multiple MP3 frames are concatenated directly

Dry-run (estimate character count and price, without calling the API)

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --file 长稿.txt --dry-run
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "测试文本" --provider minimax --dry-run

Prints: text character count / estimated billable characters / estimated cost (CNY/USD) / number of segments + character count of each segment.

Dry-run long scripts first— MiniMax bills Chinese at CJK ×2, so for long Chinese scripts the billable characters are about twice the character count.

Voice preview (5-second sample)

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --preview lyrical
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --preview rachel

Quickly generate a 5s sample to ~/Desktop/preview-{provider}-{voice}.mp3using a fixed example sentence, for easy side-by-side voice comparison. Files with the same name will be overwritten automatically.

Silence between long-form paragraphs

When synthesizing multiple paragraphs, by default insert 300ms of silencebetween paragraphs (to avoid them sounding too rushed); the asset comes from assets/silence-300ms-32k-128k-mono.mp3(aligned with MiniMax's default audio_setting).

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --file 长稿.txt --gap-ms 600
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --file 长稿.txt --gap-ms 0

--gap-ms Rounded to 300ms units (the asset is one 300ms unit, repeated an integer number of times).

Output control

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "文本" -o ~/Desktop/旁白.mp3
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "文本" -o -          # stdout(管道)
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "文本" --force       # 覆盖已存在文件

By default, existing files are not overwritten (to protect against accidents).

List local presets

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --list-voices
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --list-voices minimax
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --list-voices elevenlabs

List MiniMax remote system voices (about 300)

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --list-remote-voices
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --list-remote-voices --filter Lyrical
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --list-remote-voices --filter Female

Call /v1/get_voice to get the full system_voice list. Pick the ones you want to use, add the voice_id to config.json 's providers.minimax.voices and give it a short name.

Local cache

The same (provider + voice_id + model + text + voice_settings + audio_setting) combination hits the cache and is reused directly, without calling the API again. On a cache hit, print ✓ cache hit [hash]。

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py "文本" --no-cache    # 跳过缓存
python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --clear-cache        # 清空缓存

Cache location:cache/{16位哈希}.mp3 + cache/{16位哈希}.json(meta)。

Usage statistics

python3 ${CLAUDE_SKILL_DIR}/scripts/tts.py --usage

Print: today's / this month's / cumulative request count + billed character count; broken down by key; cache size. Data comes from usage.jsonl(a JSON line is appended on every real API call; cache hits are not counted).

Unit tests (pure logic, no network calls)

cd ${CLAUDE_SKILL_DIR}
python3 -m unittest tests.test_logic -v

26 tests cover language detection, text segmentation, billed characters, cache key, and price estimation. Run them before and after changing core functions to avoid regressions.

Routing rules

config.json 's language_routing:

{ "zh": "minimax", "en": "elevenlabs" }

Language detection: a Chinese character ratio ≥ 15% is considered Chinese, otherwise English. When Chinese and English are mixed and the ratio ∈ [10%, 90%], print amixed warning, suggesting you can use --provider to force a switch.

Priority(high to low):

  1. --provider explicitly specified
  2. --voice is a preset name of some provider → infer backwards (a name conflict is an error, requiring --provider to be explicit)
  3. auto + language detection

Built-in voice presets + scenario suggestions

MiniMax (Chinese, default model speech-2.8-hd)

Preset Description Suitable scenarios
lyrical(default) Lyrical male voice, youthful and magnetic, smooth and expressive Rational narration, emotional passages
gentleman Warm male voice, youthful and magnetic, standard Mandarin Product introductions, customer video openings
radio_host Radio male host, youthful and poetic, late-night radio quality Artsy narration, brand mood films
executive Steady executive, middle-aged male, business depth Business PPT narration, investor roadshows
announcer Announcer male voice, middle-aged and magnetic, clear and authoritative Formal launches, annual report data
sincere Sincere youthful male voice, encouraging and highly approachable User thank-you notes, community announcements
news_anchor News female voice, middle-aged professional broadcasting tone News reports, serious popular science
sweet_lady Sweet female voice, youthful and gentle Lightweight tutorials, consumer goods
warm_bestie Warm bestie female voice, youthful, crisp and friendly Lifestyle vlogs, dialogue scenes
wise_women Experienced older-sister female voice, middle-aged lyrical Long-form article excerpts, reminiscing-style narration

MiniMax has about 300 system voices in total. To add other voices: use --list-remote-voices to look up the voice_id, and add it to config.json 's providers.minimax.voices。

ElevenLabs (English, default model eleven_multilingual_v2)

Preset Description
rachel(default) English female voice, steady, science-explainer narration
adam English male voice, deep
bella English female voice, young and lively
antoni English male voice, gentle
domi English female voice, powerful
josh English male voice, young

Configuration / Credentials

config.json(Do not commit, contains API keys) copied from config.json.template , structure:

{
  "default_output_dir": "~/Desktop",
  "default_provider": "auto",
  "language_routing": { "zh": "minimax", "en": "elevenlabs" },
  "providers": {
    "elevenlabs": { api_key, endpoint, default_voice, default_model, voices, voice_settings },
    "minimax":    { api_key, fallback_keys, endpoint, default_voice, default_model, voices, voice_settings, audio_setting }
  }
}

It can run with only one provider configured—if only ElevenLabs is filled in, Chinese text will also be routed to ElevenLabs (slightly lower quality, but usable). It's recommended to configure both.

Environment variable overrides

Priority: environment variables > config.json. When switching machines or in CI, use:

Variable Purpose
ELEVENLABS_API_KEY Override ElevenLabs key
MINIMAX_API_KEY Override MiniMax primary key
MINIMAX_FALLBACK_API_KEY Append as the highest-priority fallback key

Fault tolerance mechanism

Network layer (retry with the same key)

  • HTTP 5xx → exponential backoff (2s → 4s), retry 2 times
  • URLError (DNS, timeout, connection refused) → same as above
  • 4xx → no retry, hand over to the business layer for judgment

MiniMax dual-key fallback (switch key and retry)

Trigger conditions (strict whitelist, no longer substring keyword matching to avoid misjudgment):

  • HTTP status codes: 401 / 402 / 403 / 429
  • Business status codes: 1004 / 1008 / 1029 / 1039 / 2013 / 2049

If any is met → switch to fallback_keys and retry. Other errors (such as 2039 text moderation) fail directly, without wasting fallback quota.

api_key is used first (recommended to put the cheaper key, such as a Token Plan key),fallback_keys as the fallback (pay-as-you-go key). The two are not interchangeable, and both must be configured to use fallback. It can also run with only one configured.

Notes

  • ElevenLabs bills by characters; before long text, first --dry-run
  • MiniMax has a text limit of 10000 characters per request (the script uses 9500 to leave a buffer, and automatically segments)
  • MiniMax bills by UTF-8 bytes, 1 Chinese character ≈ 2 characters
  • Cross-platform: runs on Mac/Windows/Linux, zero third-party dependencies
  • Default output ~/Desktop, can be changed in config.json to default_output_dir
  • Existing output files are not overwritten by default; use --force

Source references