mcpField
D
document-to-narration

document-to-narration

github.com/jwynia创意与媒体179976 次安装35 周前更新
代码仓库

关于 document-to-narration

document-to-narration 可将书面文档转换为视频旁白脚本、音频和逐词时间字幕,适合将长文制作成视频内容。它依据文章的论述脉络划分场景,而非机械套用固定分段。

主要功能

  1. 01将文档拆分为场景
  2. 02改写为适合口述的文本
  3. 03生成旁白音频
  4. 04创建逐词时间字幕
  5. 05提取场景时间点

适用场景

  1. 01将文章转换为视频旁白
  2. 02为 TTS 音频准备文本
  3. 03制作同步视频字幕
  4. 04为 Remotion 规划场景时间

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jwynia/agent-skills --skill document-to-narration

安装后在 Claude Code 中输入/document-to-narration确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

.gitignore
data/
adaptation-rules.json
references/
spoken-adaptation-guide.md
scripts/
extract-scene-boundaries.py
full-pipeline.ts
narrate-full.py
narrate-scenes.py
split-to-scenes.ts
transcribe-full.py
transcribe-scenes.ts
tts/
requirements.txt
setup-venv.sh
tts/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)
  • 实时语音合成
  • 多说话人对话
  • 编辑或改进内容论点
  • 除机械性口语化调整外,不做编辑性修改

评论

支持 Markdown