关于 document-to-narration
document-to-narration 可将书面文档转换为视频旁白脚本、音频和逐词时间字幕,适合将长文制作成视频内容。它依据文章的论述脉络划分场景,而非机械套用固定分段。
主要功能
- 01将文档拆分为场景
- 02改写为适合口述的文本
- 03生成旁白音频
- 04创建逐词时间字幕
- 05提取场景时间点
适用场景
- 01将文章转换为视频旁白
- 02为 TTS 音频准备文本
- 03制作同步视频字幕
- 04为 Remotion 规划场景时间
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jwynia/ agent-skills --skill document-to-narration安装后在 Claude Code 中输入/document-to-narration确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitignoredata/adaptation-rules.jsonreferences/spoken-adaptation-guide.mdscripts/extract-scene-boundaries.pyfull-pipeline.tsnarrate-full.pynarrate-scenes.pysplit-to-scenes.tstranscribe-full.pytranscribe-scenes.tstts/requirements.txtsetup-venv.shtts/model/.gitkeep详细介绍
文档转旁白
将书面文档转换为旁白视频脚本,并精确标注词级时间。
核心原则
由 Agent 解读,文档引导。 此技能不会僵硬地按模板切分,而是运用 Agent 的判断,找出内容自然停顿、论证和转折之处。场景分界由文档的论述脉络决定,而非预设结构。
何时使用此技能
在以下情况使用此技能:
- 将博客文章或随笔转换为视频旁白
- 为 TTS 音频生成准备内容
- 将长篇内容拆分为易于消化的场景
- 为视频创建词级同步字幕
在以下情况不要使用此技能:
- 内容已采用场景/脚本格式
- 需要实时语音合成(此流程是批处理)
- 处理对话或多说话人内容(仅支持单一语音)
前提条件
- 已安装 Deno(https://deno.land/)
- 支持 venv 的 Python 3.12
- 用于音频转换的 ffmpeg
- whisper-cpp(通过 @remotion/install-whisper-cpp 安装)
tts/model/中的 TTS 模型(因文件过大,未纳入 git,请参阅下方的模型设置)
完整流程
有两种方式:按场景处理(旧版)和完整旁白(推荐)。
完整旁白流程(推荐)
生成单个音频文件,以保持音量和语速一致:
Document (.md)
↓ [agent interprets scene breaks]
Scene .txt files (01-scene-name.txt, 02-scene-name.txt, ...)
↓ [TTS via narrate-full.py - SINGLE PASS]
full-narration.wav (one consistent audio file)
↓ [Whisper via transcribe-full.py]
full-narration.json + full-narration.vtt (word-level timing)
↓ [extract-scene-boundaries.py]
Scene timing boundaries for video composition
按场景处理流程(旧版)
为每个场景分别生成音频——可能导致音量不一致:
Scene .txt files
↓ [TTS via narrate-scenes.py - MULTIPLE PASSES]
Scene .wav files (volume may vary between scenes)
↓ [concatenate]
Combined audio (may have clipping at boundaries)
警告: 按场景进行 TTS 会生成音量和语速各不相同的音频。拼接后会造成明显的跳变和削波。请改用完整旁白流程。
快速开始
完整旁白流程(推荐)
cd .claude/skills/document-to-narration
source tts/.venv/bin/activate
# 1. Split document into scenes (manual or scripted)
deno run --allow-read --allow-write scripts/split-to-scenes.ts input.md --output ./output/
# 2. Generate single audio file
python scripts/narrate-full.py ./output/scenes/
# 3. Transcribe with word-level timestamps
python scripts/transcribe-full.py ./output/full-narration.wav
# 4. Extract scene boundaries for video timing
python scripts/extract-scene-boundaries.py ./output/scenes/ ./output/full-narration.json --typescript
按场景处理流程(旧版)
# 1. Split document into scenes
deno run --allow-read --allow-write scripts/split-to-scenes.ts input.md --output ./output/
# 2. Generate audio per scene (may have volume inconsistencies)
source tts/.venv/bin/activate
python scripts/narrate-scenes.py ./output/scenes/
# 3. Transcribe (DEPRECATED: transcribe-scenes.ts requires whisper-cpp)
# Use transcribe-full.py instead after concatenating audio
说明
步骤 1:设置(仅首次需要)
创建 Python 虚拟环境
cd .claude/skills/document-to-narration/tts
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
TTS 模型设置
微调后的语音模型(约 7.8GB)因文件过大,未纳入 git。
将 Qwen3-TTS 模型文件放入 tts/model/:
tts/model/
├── config.json
├── generation_config.json
├── model.safetensors # Main model weights
├── tokenizer_config.json
├── vocab.json
├── merges.txt
└── speech_tokenizer/
└── ...
安装 Whisper(如果尚未安装)
@remotion/install-whisper-cpp 软件包会处理此步骤:
import { installWhisperCpp, downloadWhisperModel } from '@remotion/install-whisper-cpp';
await installWhisperCpp({ to: './whisper-cpp', version: '1.5.5' });
await downloadWhisperModel({ model: 'medium', folder: './whisper-cpp' });
步骤 2:准备文档
此技能最适用于以下内容:
- 结构清晰、包含标题层级(H1、H2)的 Markdown 文档
- 论点结构良好、章节分明的内容
- 朗读起来自然流畅的内容
步骤 3:运行流程
deno run -A scripts/full-pipeline.ts /path/to/essay.md --output ./output/essay-name/
步骤 4:检查输出
output/essay-name/
├── scenes/
│ ├── 01-opening-hook.txt # Scene script
│ ├── 01-opening-hook.wav # Generated audio
│ ├── 01-opening-hook.vtt # Word-level captions
│ ├── 02-core-argument.txt
│ ├── 02-core-argument.wav
│ ├── 02-core-argument.vtt
│ └── ...
└── manifest.json # Complete timing data
场景分界启发式规则
Agent 使用以下启发式规则来识别场景分界:
强分界(几乎总是应拆分)
- H2 标题发生变化
- “关键在于”/“问题是”等转折语句
- 引入重要隐喻
- 明确列举(“首先……”“其次……”)
- 视角发生显著变化
中等分界(可考虑拆分)
- 长段落紧接短段落(或反之)
- 从示例转向原则
- 段首出现“但是”/“然而”/“与此同时”
- 先提问再作答的结构
弱分界(通常应连在一起)
- 同一示例中的段落之间
- 支持同一观点的连续论据
- 为妙语/揭示逐步铺垫
场景长度指引
- 目标:每个场景 100-300 个词(30-90 秒音频)
- 最少:50 个词(避免过短场景)
- 最多:500 个词(避免认知负荷过重)
反面模式
段落切片器
模式: 机械地在每个段落或标题处拆分。 问题: 忽视论述脉络,导致场景零碎且缺乏连贯性。 改进: 寻找修辞单元,而非结构单元。多个段落往往构成一个场景。
大段文字
模式: 将整个章节保留为单个场景。 问题: 生成过长的 TTS 音频,失去自然停顿的空间。 改进: 以 100-300 个词为目标,在章节中找出自然的停顿点。
逐字转录者
模式: 原样照搬书面文本,不做口语化调整。 问题: 书面表达习惯不适用于口语。括号内容、复杂标点和多层从句会让 TTS 和听众感到困惑。 改进: 应用口语化调整规则。在脑海中大声读一遍。
过度改写者
模式: 大幅改写内容,以至于丢失作者的风格。 问题: 结果听起来不像原作者的作品。 改进: 保留风格,调整表达方式。如果作者使用了反问句,就保留它们。
可用脚本
scripts/split-to-scenes.ts
解析 Markdown 文档并输出场景文本文件。
deno run --allow-read --allow-write scripts/split-to-scenes.ts input.md --output ./output/
deno run --allow-read --allow-write scripts/split-to-scenes.ts input.md --output ./output/ --adapt
deno run --allow-read scripts/split-to-scenes.ts input.md --dry-run
选项:
--output- 场景文件的目录(如果不存在则创建)--adapt- 应用口语化调整规则--dry-run- 预览场景分段,不写入文件
输出: 编号 .txt 文件和初始 manifest.json
scripts/narrate-full.py(推荐)
根据所有场景文件生成单个 TTS 音频文件。音量和语速保持一致。
python scripts/narrate-full.py ./output/scenes/
python scripts/narrate-full.py ./output/scenes/ --force
python scripts/narrate-full.py ./output/scenes/ --speaker jwynia
python scripts/narrate-full.py ./output/scenes/ --output ./custom/path/audio.wav
选项:
--force- 即使输出已存在也重新生成--speaker- 说话人名称(默认值:jwynia)--output- 自定义输出路径(默认值:../full-narration.wav)
输出: 场景所在目录的上级目录中的单个 full-narration.wav
scripts/narrate-scenes.py(旧版)
分别为每个场景文件生成 TTS 音频。不推荐——拼接后可能导致音量不一致。
python scripts/narrate-scenes.py ./output/scenes/
python scripts/narrate-scenes.py ./output/scenes/ --force
python scripts/narrate-scenes.py ./output/scenes/ --speaker jwynia
选项:
--force- 即使输出已存在也重新生成--speaker- 说话人名称(默认值:jwynia)
输出: 每个 .txt 文件旁边的 .wav 文件
scripts/transcribe-full.py(推荐)
使用 Python 的 openai-whisper 转录音频,并生成词级时间戳。
python scripts/transcribe-full.py ./output/full-narration.wav
python scripts/transcribe-full.py ./output/full-narration.wav --model large-v3
python scripts/transcribe-full.py ./output/full-narration.wav --output-dir ./captions/
选项:
--model- Whisper 模型:tiny、base、small、medium、large、large-v2、large-v3(默认值:medium)--output-dir- 输出目录(默认值:与音频文件相同的目录)
输出:
- 带词级时间戳的
.vtt文件 - 包含 Remotion 字幕数组的
.json文件
依赖项: Python 环境中需要安装 openai-whisper:
pip install openai-whisper
scripts/extract-scene-boundaries.py
通过匹配场景开头短语,从转录文本中提取场景时间边界。
# Human-readable table
python scripts/extract-scene-boundaries.py ./output/scenes/ ./output/full-narration.json
# JSON output
python scripts/extract-scene-boundaries.py ./output/scenes/ ./output/full-narration.json --json
# TypeScript for Video.tsx
python scripts/extract-scene-boundaries.py ./output/scenes/ ./output/full-narration.json --typescript
选项:
--json- 以 JSON 数组形式输出--typescript- 输出为 Video.tsx 场景数组的 TypeScript 代码
输出: 场景编号、标识名、开始时间和时长
scripts/transcribe-scenes.ts(已弃用)
已弃用: 需要 whisper-cpp 二进制文件,该文件可能未安装。请改用
transcribe-full.py。
使用 whisper-cpp 转录各场景的音频文件。
deno run --allow-read --allow-write --allow-run scripts/transcribe-scenes.ts ./output/scenes/
输出: 带词级时间戳的 .vtt 文件
scripts/full-pipeline.ts
编排完整工作流。
deno run -A scripts/full-pipeline.ts input.md --output ./output/project-name/
选项:
--output- 输出目录(必需)--adapt- 应用口语化调整--skip-tts- 跳过音频生成(仅输出文本)--skip-transcribe- 跳过 Whisper 转录
输出格式
manifest.json
{
"source": "appliance-vs-trade-tool-draft.md",
"created_at": "2024-01-15T10:30:00Z",
"total_scenes": 9,
"total_duration_seconds": 420,
"scenes": [
{
"number": 1,
"slug": "popcorn-opening",
"word_count": 185,
"audio_duration_seconds": 55.2,
"files": {
"text": "scenes/01-popcorn-opening.txt",
"audio": "scenes/01-popcorn-opening.wav",
"captions": "scenes/01-popcorn-opening.vtt"
},
"captions": [
{ "text": "Two", "startMs": 0, "endMs": 180, "confidence": 0.98 },
{ "text": "people", "startMs": 180, "endMs": 450, "confidence": 0.97 }
]
}
]
}
VTT 格式
WEBVTT
00:00.000 --> 00:00.180
Two
00:00.180 --> 00:00.450
people
00:00.450 --> 00:00.720
walk
00:00.720 --> 00:01.100
into
口语化调整
启用 --adapt 时,此技能会将书面表达习惯转换为口语表达:
| 书面表达 | 口语表达 |
|---|---|
| 括号补充说明 | 破折号或单独成句 |
| “e.g.” | “for example” |
| “i.e.” | “that is” |
| 多层长从句 | 拆分为多个句子 |
| 分号 | 句号 |
*强调* | 根据语境调整重音 |
保留:
- 作者的风格和语气
- 反问句
- 刻意重复
- 关键短语和令人印象深刻的表达
集成
与 remotion-designer 集成
- 将 manifest 中的场景列表传递给 remotion-designer
- 每个场景都成为一个视觉设计单元
- 词级时间戳用于驱动文本动画
与 Remotion 合成集成
import { Audio, useCurrentFrame, Sequence } from 'remotion';
import manifest from './output/manifest.json';
// Use scene durations for Sequence timing
{manifest.scenes.map((scene, i) => (
<Sequence
from={accumulatedFrames}
durationInFrames={scene.audio_duration_seconds * fps}
>
<Audio src={staticFile(scene.files.audio)} />
<CaptionRenderer captions={scene.captions} />
</Sequence>
))}
技术说明
WAV 格式转换
Whisper 需要 16kHz 单声道 WAV。工作流会自动处理转换:
ffmpeg -i input.wav -ar 16000 -ac 1 output_16khz.wav
TTS 模型
微调后的语音模型(约 7.8GB)已打包在 tts/model/ 中。使用 Qwen3-TTS 和自定义说话人嵌入。
性能
- TTS:每句话约需 5-30 秒(Apple Silicon MPS 或 NVIDIA CUDA)
- Whisper:根据模型大小,速度约为实时的 0.5-2 倍
- 完整文章(约 2000 个词):总处理时间约为 10-20 分钟
此技能不会做什么
- 生成视频画面(请使用 remotion-designer)
- 实时语音合成
- 多说话人对话
- 编辑或改进内容论点
- 除机械性口语化调整外,不做编辑性修改