TTS Skill
Route every request into exactly one lane.
Hard Routing Rules
- For local video production, use local IndexTTS2 only. Do not call MiniMax,
even when MiniMax credentials exist in
.env. - Use voice id
pluvio-indextts2-calm-v1and the canonical lossless WAV inautomation/config/tts-routing.json. Never use an MP3 as the speaker reference and never replace the canonical reference with the latest output; that would accumulate cloning drift. - Generate the locked narration as lossless WAV. MP3 may be emitted only as a portable audition copy, never as the source for another clone or for final subtitle timing.
- Apply the
default_delivery.playback_speeddeclared inautomation/config/tts-routing.jsonto every audition and final WAV. The production default is1.12x, implemented with FFmpegatemposo pitch is preserved. Record the effective multiplier invoice_manifest.json. - Do not silently fall back to macOS
say, browser speech, MiniMax, or another generic/cloud voice. If IndexTTS2, its model weights, Apple MPS/CPU, or the canonical reference is unavailable, repair the local lane or stop. - Every final narration render must leave
voice_manifest.jsonwith provider, voice id, model, canonical reference path and SHA-256, segment contract, output path, andused_fallback=false. - TTS segment durations are planning metadata only. Run
ra-audio-to-subtitlesagainst the exact concatenated lossless narration and use its word timestamps for final captions. - For digital-human production, treat the full narration as an audition until the user explicitly approves that exact audio version. Do not describe an unapproved audition as locked or forward it to HeyGen.
- Before every local audition or final render, enforce
references/pronunciation-lexicon.json. A user-approved pronunciation in that file overrides generic phonetic heuristics. Keep the display spelling separate from TTS text when needed, and stop rather than render a forbidden spelling.
Local Video Lane: IndexTTS2
Read the machine-readable route from:
automation/config/tts-routing.json
Generate a narration from a JSONL segment contract with:
python3 .claude/skills/tts-skill/scripts/generate_indextts2_narration.py \
--batch-file <segments.jsonl> \
--output <final-narration.wav> \
--manifest <voice_manifest.json>
Each non-empty JSONL line must follow the official IndexTTS2 batch contract and
contain text; it may also contain emotion_vector, emotion_weight, and
silence_after_ms. Default to a calm delivery. Add stronger emotion only when
the user explicitly asks for it.
Run --dry-run before a new contract or after changing the local model setup.
The helper verifies that the canonical speaker reference is a lossless PCM WAV,
invokes the official local IndexTTS2 CLI, normalizes the result, and writes the
manifest. Keep the raw WAV beside the normalized WAV for auditability.
For mixed Chinese/English scripts, inspect model names, brands, abbreviations,
and numbers before the full render. Load
references/pronunciation-lexicon.json first. Entries there are approved
production contracts: use their tts value exactly and reject every
forbidden_tts form. In particular, keep Codex as the raw English token;
never transliterate it as “扣代克斯”, “扣戴克斯”, or “扣德克斯”. For a term
that is not yet in the lexicon, audition alternatives while keeping canonical
spelling in the display script and final captions. After the user chooses,
record that decision in the lexicon before the full render.
Public Article Lane: MiniMax Relay
MiniMax is retained only as the public solution used in articles, tutorials,
course examples, and relay-station onboarding. It is not a local production
provider. When this lane is requested, read
references/minimax-relay-article.md and use assets/minimax_tts.py only for
the article/demo example.
QC
Before using narration in a final video:
- confirm
providerisIndexTTS2/indextts2-local - confirm
voice_idispluvio-indextts2-calm-v1 - confirm the reference SHA-256 matches the routing config
- confirm the recommended output is PCM WAV and decodes successfully
- confirm
playback_speedis1.12unless the production contract explicitly overrides the workspace default - confirm
used_fallback=falseand no segment provider is MiniMax - confirm the pronunciation contract is present in
voice_manifest.jsonand the approved mixed-language terms were used - generate captions from that exact WAV and require
caption-qc.jsonPASS - for a digital human, require explicit user approval of the exact audition WAV before any paid avatar generation; changing the audio invalidates approval