关于 papercut-voice
papercut-voice 是 Papercut 视频流程中的旁白制作技能,面向制作短视频的创作者。它支持本地 Qwen3-TTS、自有录音或其他 TTS,以及占位音频,并生成词级时间、字幕和场景计划。
主要功能
- 01支持三种旁白制作路径
- 02生成并筛选逐行旁白 WAV
- 03通过 ASR 生成词级时间戳
- 04构建字幕和场景计划
- 05支持占位音频后续替换
适用场景
- 01为脚本生成并整理旁白音频
- 02为旁白字幕校准词级时间
- 03先用占位音频搭建视频,再替换配音
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ 0xs4n4tg/ papercut-explainer --skill papercut-voice安装后在 Claude Code 中输入/papercut-voice确认已加载。
详细介绍
Papercut 语音
后续每个阶段都需要叙述文件夹中包含两项内容:voice/final_narrator/<id>.wav(每行脚本对应一个 WAV)和 timing_narrator.js(每个词的起止时间)。此技能通过三种路径之一生成这些文件,然后构建字幕和场景计划。脚本的完整参考文档见 library/voice/README.md。
预检
- 库路径:使用
$PAPERCUT_LIB;否则使用~/.config/papercut-explainer/config.env中的PAPERCUT_LIB=行;再否则询问一次。导出该路径,然后执行. "$PAPERCUT_LIB/env.sh",将ASR_PY、QWEN_TTS_PY和其他配置值加载到 shell 中。 - 已搭建脚手架的项目(
papercut-build,步骤 1),其中包含narration/script.json和含有scenes的papercut/episode.json。new_episode.sh会将build_timing.py复制到narration/。 - 如果用户已经安装了 TTS,请直接使用,不要重装(路径 B;如果是 Qwen3-TTS,则使用路径 A)。询问一次 TTS 是什么,以及在哪里运行。否则询问要使用哪条路径,并说明所需条件:
| 路径 | 所需条件 | 安装模式 |
|---|---|---|
| A. 本地 Qwen3-TTS | library/voice/setup_tts.sh 中的语音 venv(模型下载量为 2.3-4.2 GB) | 完整 |
| B. 自行录音或其他 TTS | 一个 ASR 后端(mlx-whisper 或 faster-whisper),以及 ASR_PY 和 QWEN_TTS_PY 所指向的 Python 中的 librosa + numpy,用于音高处理 | 完整安装,或手动安装这些软件包 |
| C. 占位音频 | ffmpeg;使用 --say 需 macOS | 标准 |
如果所选路径需要的内容超出当前安装范围,请运行 ./install.sh --doctor,然后交由 papercut-setup 处理。没有 ASR 时,build_timing.py 只会按每秒 2.75 个词估算,因此字幕会与实际音频错位。
路径 A:本地 Qwen3-TTS
在系列文件夹中运行:
cp $PAPERCUT_LIB/voice/voice.example.json voice/voice.json # once per series; edit it
$PAPERCUT_LIB/voice/narrate.sh voice/voice.json episodes/NN-slug/narration
$PAPERCUT_LIB/voice/finalize.sh voice/voice.json episodes/NN-slug/narration episodes/NN-slug/narration/voice/takes/narrator [num.json]
voice.json:包含speaker(CustomVoice:Aiden、Dylan、Eric、Ryan、Serena、Vivian、Sohee、Ono_anna、Uncle_fu)和instruct。推荐设置:CustomVoice 1.7B,Ryan 或 Aiden;instruct 使用 "友好、自然、口语化,像在给朋友讲述;句子之间停顿清晰;强调每行的关键词"。takes_per_line默认为 3。tempo保持 1.0(其他值需要rubberband)。qa_targets用于设置音高范围和 ASR 匹配度(0.9)。- 脚本行可以包含
tts(用于改善发音的改写文本;字幕仍使用text)和单独的instruct。num.json将数字映射为读出的词语({"13,000": "thirteen thousand"}),避免 ASR 匹配数字失败。 - 一次只运行一个 TTS 进程;1.7B 模型非常占用内存。
finalize.sh会对每条候选音频运行 ASR 和音高检测,每行选取一条,进行裁剪、响度归一化至 -16 LUFS,在最终音频上重新运行 ASR,并写入timing_narrator.js。试听后,将修正内容写入voice/picks_override.json({"l3_name": 2}),然后使用SKIP_PICK=1重新运行。- Voice Design(用文字描述声音)是 Qwen3-TTS 的一种模式,
narrate.py不会调用此模式。请在其他地方使用该模式生成音频,然后采用路径 B。
路径 B:自行录音或使用其他 TTS
- 每行录制一个 WAV 文件,放入
voice/final_narrator/<id>.wav;或者将原始录音放入voice/takes/narrator/<id>_<k>.wav,然后按上述方式运行finalize.sh。 - 对于已完成的台词,先转录,再将
voice/chosen_narrator.json写为{id: "voice/final_narrator/<id>.wav"},然后在narration/中运行:
$ASR_PY $PAPERCUT_LIB/voice/asr.py voice/final_narrator/*.wav > voice/asr_narrator_final.json
CHOSEN=voice/chosen_narrator.json TIMING_OUT=timing_narrator.js python3 build_timing.py voice/asr_narrator_final.json
路径 C:占位音频
在 narration/ 文件夹中运行:
python3 $PAPERCUT_LIB/tools/placeholder_vo.py [--wps 3.0] [--say [VOICE]]
此命令仅根据 script.json 生成无声 WAV 文件(或使用 --say 生成 macOS say 语音)和 timing_narrator.js,并按词长分配每个词的时间。使用 --wps 3.5 到 4 可近似达到目标语速(默认为 3.0)。可以先构建并调整视频节奏,之后再重新录制语音:替换 WAV 文件,重新运行 finalize.sh,再运行 build_vo.py,词级提示点会随之更新。
交付规则
朗读要自然、从容,并有所强调。观众必须第一次听就能跟上每一句。
- 留出呼吸空间。 每句结束时,以及列表各项之间(“Fine. Fine. Fine.”)都要有明显停顿。先将每行之间的间隔设为 0.3-0.4 s(
episode.json中的gap,默认值为 0.22;gaps会在指定行后额外增加一个节拍),再听效果判断。停顿只放在句子或分句边界:在短语中间停 0.2 s,例如 “copied it, | by taking...”,听起来会像卡顿。宁可利用 30 s 的时长上限留出空隙,也不要删减停顿;绝不要通过放慢语速来实现。 - 强调。 每行着重强调的一两个词(数字、转折词、结论)来自脚本的舞台调度表。将它们作为每行单独的
instruct传入。 - 语气。 像日常交谈,略带笑意,不要像播音员。疑问句听起来要像真实提问,点睛句要带有好奇感,CTA 要温暖。旁白仍然不讲笑话;画面才负责逗趣。
- 克隆模型(无指令)。 使用克隆音色(
ref_audio+ref_text,Base 模型)时,可调节的手段是文本和录制效果。通过标点写出停顿(列表项之间用句号,简短问句单独成句)。使用多个种子生成一条连续录音(SEED_BASE、takes_per_line),选出目标词语音调变化最明显且 ASR 达到 0.9 或更高的一条;若某行听起来平淡,就单独重录(ONLY=l4_peak),并在句子边界处拼接。只克隆你有权使用的音色。 - 一次性生成整篇脚本能保持韵律一致:生成一条录音,用
split_take.py按行切分,然后在episode.json中将"gap": 0。如果用户更喜欢按场景生成,也可以。 - 完整录制前,先向用户播放前三行:
ONLY=l1_hook,l2_...,l3_... narrate.sh ...。
字幕和时间安排
在 papercut/ 中,episode.json 包含 scenes 后:
python3 $PAPERCUT_LIB/tools/build_vo.py # public/vo/voiceover.wav, public/vo/captions.json, src/plan.json
python3 $PAPERCUT_LIB/tools/timing_md.py # Timing section of STORYBOARD.md
captions.json 是 Remotion 的 Caption[];场景边界取自单词时间戳;合成时长为 plan.json 的 durationInFrames。build_vo.py 会标记时长不足 1.2 s 的场景。如果没有库,请使用 Remotion 字幕技能(whisper.cpp)或任何能返回单词时间戳的语音转文本工具转写 WAV。
字幕要像撕下来的标签一样,每个词一张;每页 1-3 个词,语速为每秒 3.5-4 个词(../papercut-explainer/references/style-guide.md,第 11 和第 13 节)。
交接
接下来是 papercut-build(占位内容、场景、声音、渲染)。它会读取 src/plan.json 和 papercut/STORYBOARD.md 的 Timing 部分。之后若更改任何语音,都要重新运行 build_vo.py 和 timing_md.py;随后场景缓存会重新渲染所有内容。