What this does
Reads a timestamped narration script and synthesizes one audio clip per segment, fitting speech
to each segment's time slot (dynamic rate), then records placement metadata. The only engine is
MiMo TTS (mimo-v2.5-tts).
Requirements
export MIMO_API_KEY=*** # MiMo TTS (or a TTS-specific MIMO_TTS_API_KEY)
Input contract
work_dir/narration.json — segments with start / end / narration (+ optional pause_after_ms,
overlaps_speech). Times are the output-timeline seconds the audio will be placed at.
In the orchestrated cut-mode flow, the agent writes narration.json directly against the output
timeline, and the orchestrator passes it here. In the legacy direct-cut path,
narration_mapped.json may be passed explicitly instead.
Running the scripts below — the scripts/… paths are relative to this skill's own directory (the folder containing this SKILL.md). Claude Code runs commands from there, so they work as written. If your harness runs commands from the project root instead (opencode / Codex / OpenClaw commonly do), prefix this skill's absolute directory — e.g. <skill-dir>/scripts/…, using the directory your harness reports when it loads the skill. The scripts self-locate from their own path, so once started by the correct path they resolve their sibling skills and assets regardless of the working directory.
Run
python3 scripts/voiceover.py --work-dir <work_dir> --narration <narration.json> \
[--mimo-voice 冰糖 | --voice-ref <reference-audio>]
For direct one-off use, omitting --narration reads work_dir/narration.json.
Pass --narration work_dir/narration_mapped.json explicitly only for the legacy direct-cut path;
the video-recap orchestrator always passes narration.json.
Output contract
tts_segments/*.wav — one synthesized clip per narration segment.
tts_meta.json — {segments: [...], engine, narration} where each segment carries its
audio_path, timing, pause_after_ms, and placement fields consumed by video-assemble.
When --allow-partial-tts lets a run continue past failed segments it also carries
partial: true and failures: [{index,start,end,text,error}] so missing lines stay visible
(a clean run carries partial: false and failures: []).
Notes
- Re-runs safely reuse only matching per-segment audio; edited narration or TTS settings regenerate the affected WAVs.
--voice-ref (full/cut recap only) switches narration to mimo-v2.5-tts-voiceclone; the reference
is normalized lazily once when fresh synthesis is needed, and its content/preparation fingerprint
invalidates stale cached segments. Use only with authorization; the reference is sent to MiMo.
TTS_WORKERS, TTS_TIMEOUT, TTS_RETRIES, ALLOW_PARTIAL_TTS tune throughput/robustness.
- Dub mode has its own deterministic gate:
dub_lint.json blocks empty/overlapping/out-of-range
translation lines BEFORE voiceclone spend, and dub_review.json scaffolds fidelity/tone/timing/
platform-fit review. dub.py --stage lint|review and dub.py --print-schema expose them directly.
What this skill does NOT do
- Does NOT write or edit narration text.
- Does NOT mux, duck, or render subtitles — that is video-assemble.
- Does NOT analyze the video or choose timestamps — it voices the segments it is given.
1---2name: video-voiceover3description: Synthesize Chinese narration audio (TTS voiceover) from a timestamped narration.json. Use to turn a written narration script into per-segment speech audio, with MiMo TTS (mimo-v2.5-tts), dynamic speed fitting, and loudness handling. Part of the video-recap bundle: consumes narration.json (output-timeline time), produces tts_segments + tts_meta.json. In the legacy direct-cut path, narration_mapped.json may be passed explicitly instead. 触发词: 配音, 语音合成, TTS, 解说配音, voiceover, text to speech, 旁白配音.4---5
6## What this does
7
8Reads a timestamped narration script and synthesizes one audio clip per segment, fitting speech
9to each segment's time slot (dynamic rate), then records placement metadata. The only engine is
10MiMo TTS (`mimo-v2.5-tts`).
11
12## Requirements
13
14```bash
15export MIMO_API_KEY=*** # MiMo TTS (or a TTS-specific MIMO_TTS_API_KEY)
16```
17
18## Input contract
19
20`work_dir/narration.json` — segments with `start` / `end` / `narration` (+ optional `pause_after_ms`,
21`overlaps_speech`). Times are the **output-timeline** seconds the audio will be placed at.
22In the orchestrated cut-mode flow, the agent writes `narration.json` directly against the output
23timeline, and the orchestrator passes it here. In the legacy direct-cut path,
24`narration_mapped.json` may be passed explicitly instead.
25
26> **Running the scripts below** — the `scripts/…` paths are relative to this skill's own directory (the folder containing this `SKILL.md`). Claude Code runs commands from there, so they work as written. If your harness runs commands from the project root instead (opencode / Codex / OpenClaw commonly do), prefix this skill's absolute directory — e.g. `<skill-dir>/scripts/…`, using the directory your harness reports when it loads the skill. The scripts self-locate from their own path, so once started by the correct path they resolve their sibling skills and assets regardless of the working directory.
27
28## Run
29
30```bash
31python3 scripts/voiceover.py --work-dir <work_dir> --narration <narration.json> \
32 [--mimo-voice 冰糖 | --voice-ref <reference-audio>]
33```
34
35For direct one-off use, omitting `--narration` reads `work_dir/narration.json`.
36Pass `--narration work_dir/narration_mapped.json` explicitly only for the legacy direct-cut path;
37the video-recap orchestrator always passes `narration.json`.
38
39## Output contract
40
41- `tts_segments/*.wav` — one synthesized clip per narration segment.
42- `tts_meta.json` — `{segments: [...], engine, narration}` where each segment carries its
43 `audio_path`, timing, `pause_after_ms`, and placement fields consumed by **video-assemble**.
44 When `--allow-partial-tts` lets a run continue past failed segments it also carries
45 `partial: true` and `failures: [{index,start,end,text,error}]` so missing lines stay visible
46 (a clean run carries `partial: false` and `failures: []`).
47
48## Notes
49- Re-runs safely reuse only matching per-segment audio; edited narration or TTS settings regenerate the affected WAVs.
50- `--voice-ref` (full/cut recap only) switches narration to `mimo-v2.5-tts-voiceclone`; the reference
51 is normalized lazily once when fresh synthesis is needed, and its content/preparation fingerprint
52 invalidates stale cached segments. Use only with authorization; the reference is sent to MiMo.
53- `TTS_WORKERS`, `TTS_TIMEOUT`, `TTS_RETRIES`, `ALLOW_PARTIAL_TTS` tune throughput/robustness.
54- Dub mode has its own deterministic gate: `dub_lint.json` blocks empty/overlapping/out-of-range
55 translation lines BEFORE voiceclone spend, and `dub_review.json` scaffolds fidelity/tone/timing/
56 platform-fit review. `dub.py --stage lint|review` and `dub.py --print-schema` expose them directly.
57
58## What this skill does NOT do
59- Does NOT write or edit narration text.
60- Does NOT mux, duck, or render subtitles — that is video-assemble.
61- Does NOT analyze the video or choose timestamps — it voices the segments it is given.