Dev Spec v2 · ← 返回文档首页

05 说话模式:剪辑与字幕

v2 说明:本文沿用 v1 已设计好的自动剪辑与字幕方案,去掉了人工审听和服务线。说话模式是 03 的次线(对应原始命题 ② 降噪修复),第 17~24 周上线;其中的**字幕模块**唱歌模式也会用到(歌词字幕见 06 文档)。

1. 回答:剪口误、去"嗯啊"、收紧停顿能不能全自动?

能,全部全自动。 三件事的区别只在误剪风险:

剪辑类型 全自动的可靠程度 原因
收紧停顿 ✅ 很可靠 只是缩短静音,不删任何字
去"嗯、啊、呃、um、uh" ✅ 可靠 这些词几乎从来不承载意思
去结巴重复("我我我觉得") ✅ 可靠 规则就能判断
去"那个、就是、然后、like、you know" ⚠️ 有风险 这些词有时是口头禅,有时是正常用法("那个人"、"I like it"),要靠上下文判断
剪口误和重录(说错后重说) ⚠️ 有风险 要判断哪一遍是"作废的",大模型能判断大部分,但偶尔会剪掉有意义的内容
删跑题段落 ❌ 不自动 这是编辑判断,不是技术问题。任何档位都只提示、不自动删

所以设计成三档力度,让用户自己选风险:

档位 自动剪掉 适合
轻 light 停顿收紧(> 1.5 秒缩到 0.8 秒)+ 嗯/啊/um/uh 访谈、需要保留自然感
标准 standard(默认) 停顿收紧(> 1.0 秒缩到 0.5 秒)+ 嗯啊类 + 结巴重复 大多数播客
深度 deep 停顿收紧(> 0.7 秒缩到 0.35 秒)+ 上面全部 + 上下文口头禅 + 口误和重录 追求紧凑;接受少量误剪

所有档位都生成剪辑表,用户事后仍可以在网页编辑器里把任何一刀恢复回来(非破坏性剪辑)。编辑器是给用户自己用的可选功能,交付不依赖任何人工审核。

2. 转写

语言 引擎 要求
英文 faster-whisper(large-v3 或同级),word_timestamps=True 词级时间戳
中文 FunASR(Paraformer 一类,带时间戳和标点模型) 字级时间戳;支持热词
说话人 说话人分离模型(pyannote 一类,许可证核查);多轨录音时直接用轨道当说话人

关键陷阱:语音识别模型会"自动美化"口语。 Whisper 一类模型经常把"嗯、呃"直接省略、把结巴合并掉,所以不能只靠转写文字找口头禅。解决办法(两者都要做):

  1. 引导逐字转写:Whisper 用带口头禅的 initial_prompt(例如 "Um, so, uh, I was like, you know..."),FunASR 关闭口语规整
  2. "有声无字"检测:用语音活动检测(VAD)找出"明明有人声、但没有任何词覆盖"的片段,时长 150~800ms、能量低于前后语句的,标为疑似口头禅(kind=filler_gap)

自定义词表(人名、节目名、专业术语):用户在作品设置(settings)里填,转写时作为热词/提示词,转写后再做一遍替换纠正。

3. 剪辑检测

kind 检测方法 默认置信度 light standard deep
pause 词间静音 > 阈值 1.0 ✅ ✅ ✅
filler 词表命中(嗯/啊/呃/额/唔/um/uh/erm/hmm) 0.95 ✅ ✅ ✅
filler_gap 有声无字(见上) 0.6~0.9 ❌ conf ≥ 0.85 conf ≥ 0.7
stutter 连续重复的字/词("我我我"、"the the") 0.9 ❌ ✅ ✅
filler_ctx 上下文口头禅(那个/就是/然后/like/you know/I mean),大模型逐句判断 大模型给出 ❌ ❌ conf ≥ 0.8
retake 口误与重录:大模型判断"前一段是否被后一段替代",辅以文本相似度 大模型给出 ❌ ❌ conf ≥ 0.85
false_start 说半句就停、重新开始 大模型给出 ❌ ❌ conf ≥ 0.85
tangent 跑题 大模型给出 ❌ ❌ ❌(只提示)

3.1 大模型调用规格

  • 输入:带编号和时间戳的句子列表,按 3~5 分钟切块,前后各重叠 30 秒
  • 输出(JSON):[{"kind": "retake", "remove": [12, 13], "keep": [14], "conf": 0.9, "reason": "第12-13句说错,第14句重说"}]
  • 大模型只能引用句子/词的编号,不能自己编时间戳;时间由编号换算,防止幻觉
  • 重叠区域两个块结论冲突时,取置信度高的
  • keep_words(用户指定不删的词)在交给大模型之前就排除

3.2 安全护栏(全自动时强制执行)

规则 说明
不切在词中间 剪点吸附到词边界,再吸附到前后 30ms 内能量最低点
保留最小间隔 剪完后两句之间至少留 120ms
交叉淡化 每个剪点 15ms 等功率交叉淡化,防止爆音
不剪音乐 音乐检测命中的片段(片头曲、插曲)不做任何剪辑
不剪笑声 非语音但能量高的片段(笑声、掌声)不当作停顿压缩
删除比例上限 除 pause 外,删除总时长 > 节目时长 15% → 视为异常
单处上限 单个 retake 删除 > 60 秒 → 不自动删,降级为提示

4. 剪辑表(EDL)

{
  "source_media": "med_01J...",
  "duration": 3605.42,
  "level": "standard",
  "version": 3,
  "ops": [
    {"id": "o1", "kind": "pause",  "start": 12.48, "end": 13.91, "keep": 0.5, "conf": 1.0,  "by": "rule", "status": "accepted"},
    {"id": "o2", "kind": "filler", "start": 20.10, "end": 20.42, "text": "嗯", "conf": 0.95, "by": "rule", "status": "accepted"},
    {"id": "o3", "kind": "retake", "start": 95.20, "end": 101.75, "text": "我们刚才…不对,我重说", "conf": 0.9, "by": "llm", "status": "pending"},
    {"id": "o4", "kind": "manual", "start": 300.00, "end": 312.50, "by": "user", "status": "accepted"}
  ]
}
  • pause 类用 keep 表示保留多少秒静音,实际删除 [start + keep/2, end - keep/2]
  • status: pending / accepted / rejected
  • 渲染时只处理 accepted,重叠的区间先合并

4.1 时间换算

edl.map_time(t_original) -> t_edited:原时间减去它之前所有已接受删除段的总长;落在删除段内的时间点映射到删除段起点。字幕、章节、show notes 的时间全部用这个函数换算,不对成品重新转写。

5. 渲染

输出 做法
纯音频 Python 内按剪辑表拼接(numpy),剪点做 15ms 交叉淡化;之后再走 loudnorm
视频 剪点先吸附到视频帧边界(例如 30fps 就是 1/30 秒);视频用 ffmpeg select + setpts 按保留区间取帧;音频用同一组帧对齐的区间在 Python 里拼接并交叉淡化;最后合并音视频流

性能目标:60 分钟音频渲染 ≤ 1 分钟;60 分钟 1080p 视频 ≤ 10 分钟(CPU 编码,-preset veryfast)。

5.1 交付前自检

渲染完自动检查以下项,任何一项异常 → 自动降一档力度重新渲染,并在交付说明里写明实际用的档位:

  • 删除比例超过上限
  • 每分钟剪点数 > 20(剪得太碎,听感会跳)
  • 成品响度或真峰值不达标
  • 成品时长 < 原时长的 60%

6. 字幕

6.1 切分规则

规则 中文 英文
每行最多 16 字 42 字符
每条最多行数 1 行(横屏)/ 1 行(竖屏每行 12 字) 2 行
每条时长 1~7 秒 1~7 秒
阅读速度上限 9 字/秒 20 字符/秒
条间最小间隔 80ms 80ms
断句优先级 标点 > 停顿 > 说话人切换 > 语法边界 同左;不拆开单词
  • 口头禅和被剪掉的内容不出现在字幕里(字幕由剪后的词序列生成)
  • 中文样式默认句末不加句号、句中逗号换成空格(可在样式里关闭)
  • 可选说话人前缀(例如 Amy:),用户在作品设置里填写名字

6.2 格式与样式

格式 用途
SRT 通用
VTT 网页播放器、YouTube
ASS 带样式,用于烧录
TXT 纯文字稿(带或不带时间戳)

样式模板(ASS):clean_white(白字黑描边)、boxed(半透明底框)、bold_center(竖屏短视频大字)。字体使用开源可商用字体(思源黑体 / Noto Sans CJK,OFL 许可),随镜像打包,不依赖系统字体。

6.3 双语字幕

  • 大模型逐条翻译,输入输出条数严格 1:1(带编号的 JSON 数组),前后各带 5 条上下文
  • 译文超长时让模型缩写,仍超长则该条允许 2 行
  • 烧录时原文在上、译文在下(样式可调)
  • 术语表(作品设置里的自定义词)一并传给模型

6.4 烧录

ffmpeg -i edited.mp4 -vf "ass=subs.ass:fontsdir=/fonts" -c:v libx264 -crf 20 -preset veryfast -c:a copy out.mp4

6.5 验收

指标 目标
字幕与成品的时间误差 ≤ 100ms(开发阶段抽 20 处核对)
违反切分规则的条数 0(自动检查)
中文字错率(清晰录音) ≤ 5%;带术语表时专有名词正确率 ≥ 95%

7. 视频播客

项 说明
输入 单个视频文件;或视频 + 单独录的高质量音频(按音频互相关自动对齐,误差 ≤ 1 帧)
处理 音质处理只作用于音频流;剪辑同时作用于音视频
输出 MP4(H.264 / AAC 192kbps),保持原分辨率和帧率;可选烧录字幕
P3 竖屏短视频切片:按大模型给出的高光片段,裁成 9:16,烧录大字幕

8. 用户编辑器(前端,可选)

用户可以在交付后打开编辑器微调(恢复某一刀、手动加一刀、改错别字),保存后自动重新渲染。

区域 功能
文字稿 按说话人分段;被剪部分划线并按类型着色;点击任意词从该处播放
波形 wavesurfer.js 一类组件;剪辑区间以色块显示;可拖动边界微调
建议列表 按类型、置信度筛选;批量接受/拒绝
播放模式 "原始" / "剪后":剪后模式在浏览器里直接跳过已接受的区间,不需要先渲染
快捷键 空格 播放/暂停;J/K 上一条/下一条建议;A 接受;R 拒绝;E 在当前选区新建剪辑
文字修改 可改错别字(影响字幕,不影响剪辑)

音频在编辑器里使用代理文件(64kbps mp3),加载快;渲染时用原始无损文件。