首页
/ MoneyPrinterTurbo 字幕生成机制详解:edge 与 whisper 双引擎的配置切换与源码实现

MoneyPrinterTurbo 字幕生成机制详解:edge 与 whisper 双引擎的配置切换与源码实现

2026-09-03 19:56:19作者:明树来

MoneyPrinterTurbo 的视频流水线中,字幕是从"配音音频"到"成片合成"之间承上启下的一环:它既要为视频合成提供带时间轴的 SRT 文本,又要保证每句字幕与 AI 生成的视频文案逐字对应。本篇以仓库文档 subtitle-generation 为主线,讲清楚 edge 与 whisper 两种字幕生成方案的取舍与切换方式,并深入到 app/services/subtitle.pyapp/services/voice.pyapp/services/task.py 的源码,解析两种方案的真实调用链、whisper 本地模型部署路径以及字幕纠错算法的实现细节。

两种字幕生成方案:edge 与 whisper

MoneyPrinterTurbo 当前支持 2 种字幕生成方式:

  • edge:生成速度快,性能更好,对电脑配置没有要求,但是质量可能不稳定;
  • whisper:生成速度慢,性能较差,对电脑配置有一定要求,但是质量更可靠。

官方建议优先使用 edge 模式,只有在生成的字幕质量不好时,再切换到 whisper 模式。这个建议背后有源码依据:从 app/services/task.pygenerate_subtitle 调用链可以看到,edge 方案本质上是"复用 TTS 引擎返回的逐词时间戳"来反推字幕,不做任何音频识别,因此快且零硬件门槛;而 whisper 方案则需要对整个音频做一次完整的语音识别,成本明显更高。

切换方式只需修改 config.toml 配置文件中的 subtitle_provider 项。示例配置位于 config.example.toml

# Subtitle Provider, "edge" or "whisper"
# If empty, the subtitle will not be generated
subtitle_provider = "edge"

两个注意事项:

  1. whisper 模式下需要到 HuggingFace 下载一个模型文件,大约 3GB 左右,请确保网络通畅;
  2. 如果 subtitle_provider 留空,表示不生成字幕。

app/services/task.py 的源码看,这一"留空即关闭"的行为与实现完全对应:generate_subtitle 中只有当 subtitle_provider 等于 "edge""whisper" 时才会进入生成分支,留空时两条分支都不会执行,最终 file_to_subtitles 读不到有效内容,函数返回空字符串,字幕流程被整体跳过。此外还有一个文档未强调但源码可见的行为:当 subtitle_provider = "edge" 时,若 edge 方案未能写出字幕文件(os.path.exists(subtitle_path) 为 False),任务会自动回退(fallback)到 whisper 重新生成,日志中会打印 subtitle file not found, fallback to whisper

whisper 本地模型部署

由于国内网络环境可能无法直接访问 HuggingFace,使用 whisper 方案前需要手动部署模型文件。文档给出的下载地址:

  • 百度网盘: https://pan.baidu.com/s/11h3Q6tsDtjQKTjUu3sc5cA?pwd=xjs9
  • 夸克网盘:https://pan.quark.cn/s/3ee3d991d64b

模型下载后解压,将整个目录放到项目根目录下的 models 文件夹里,最终路径应为 MoneyPrinterTurbo/models/whisper-large-v3,目录结构如下:

MoneyPrinterTurbo
  ├─models
  │   └─whisper-large-v3
  │          config.json
  │          model.bin
  │          preprocessor_config.json
  │          tokenizer.json
  │          vocabulary.json

这个路径约定不是约定俗成,而是写死在源码里的:app/services/subtitle.pycreate 函数在首次加载模型时,优先查找 {项目根目录}/models/whisper-{model_size},并校验目录内是否存在 model.bin;只有当本地目录或 model.bin 缺失时,才会把 model_size 原样传给 faster_whisper,由它尝试联网从 HuggingFace 下载:

model_path = f"{utils.root_dir()}/models/whisper-{model_size}"
model_bin_file = f"{model_path}/model.bin"
if not os.path.isdir(model_path) or not os.path.isfile(model_bin_file):
    model_path = model_size

如果联网下载失败,日志会给出明确指引(见 app/services/subtitle.py):please download the model manually and put it in the 'models' folder

whisper 运行参数配置

除了 subtitle_providerconfig.toml 中还有一个 [whisper] 配置段,仅在 subtitle_providerwhisper 时生效,示例见 config.example.toml

[whisper]
    # Only effective when subtitle_provider is "whisper"

    # Run on GPU with FP16
    # model = WhisperModel(model_size, device="cuda", compute_type="float16")

    # Run on GPU with INT8
    # model = WhisperModel(model_size, device="cuda", compute_type="int8_float16")

    # Run on CPU with INT8
    # model = WhisperModel(model_size, device="cpu", compute_type="int8")

    # recommended model_size: "large-v3"
    model_size="large-v3"
    # if you want to use GPU, set device="cuda"
    device="CPU"
    compute_type="int8"

这三个参数在 app/services/subtitle.py 的模块加载阶段被读取,并带有默认值:model_size 默认 large-v3device 默认 cpucompute_type 默认 int8,与示例配置一致。值得注意的是模型实例是模块级单例(global model),进程内只在第一次调用时加载一次,后续任务复用,这解释了文档中"whisper 对电脑配置有一定要求"——large-v3 级别的模型在纯 CPU + INT8 下推理一次完整音频耗时较长,而 cuda + float16 的组合则要求本机具备 NVIDIA GPU。

edge 模式实现原理:用 TTS 词边界反推字幕

edge 模式不走音频识别,而是"搭" TTS 合成的便车。调用链为:generate_subtitleapp/services/task.py)→ voice.create_subtitle(text=video_script, sub_maker=..., subtitle_file=...)app/services/voice.py)。

其核心机制有三点:

  1. 词级时间戳来源:TTS 引擎(如 Azure Speech SDK 分支)在合成时会请求 RequestWordBoundary 事件,每个词回调中携带 evt.audio_offset(起始偏移)与 evt.duration(持续时长)。这些事件被累积到 sub_maker.offset / sub_maker.subs 中,字幕的起止时间直接来自 TTS 音频的偏移量,天然与音画同步;
  2. 逐行匹配脚本create_subtitle 先把视频文案用 utils.split_string_by_punctuationsapp/utils/utils.py)按标点拆分成句子数组 script_lines,再依次累加 TTS 词文本,通过三级 match_line 判定累加结果是否"命中"当前脚本行——先做完全相等,再去掉非单词字符后比较,最后去掉所有 \W 字符后比较。命中即输出一条带时间戳的 SRT 条目,并把起始时间重置;
  3. 全量校验后才落盘:只有当生成的字幕条数与脚本句数完全相等(len(sub_items) == len(script_lines))时才写入 SRT 文件;否则仅打印 warning 并丢弃结果。这就是 edge 模式"质量可能不稳定"的具体表现——只要 TTS 的分句与文案标点切句有一处对不齐,整个 edge 结果作废,随后由 task.py 中的回退逻辑接管,改用 whisper 重新生成。

whisper 模式实现原理:识别、切句与 SRT 输出

whisper 方案的入口是 app/services/subtitle.pycreate(audio_file, subtitle_file),它基于 faster_whisper 库加载本地模型并转写音频:

segments, info = model.transcribe(
    audio_file,
    beam_size=5,
    word_timestamps=True,
    vad_filter=True,
    vad_parameters=dict(min_silence_duration_ms=500),
)

参数含义:beam_size=5 使用 5 束搜索提升识别准确率;word_timestamps=True 要求模型输出逐词时间戳——这是后续"按标点切句"的前提;vad_filter=True 开启语音活动检测过滤静音段,min_silence_duration_ms=500 表示不足 500ms 的静音不会触发分段。识别完成后会打印检测到的语言及其置信度(info.language / info.language_probability)。

拿到逐词时间戳后,代码并不直接使用 whisper 原始的分段,而是按标点重新切句app/services/subtitle.py):逐词累加文本,一旦某个词包含标点(utils.str_contains_punctuation 会检查 app/models/const.py 定义的标点集合),就把当前片段定稿为一条字幕 {msg, start_time, end_time}。这保证了每条字幕以完整句子为单位显示,与 edge 模式和文案脚本的切句逻辑保持一致。

最终,每条字幕经 app/utils/utils.pytext_to_srt 格式化为标准 SRT 结构(序号、HH:MM:SS,mmm --> HH:MM:SS,mmm 时间轴、文本行),写入任务目录下的 subtitle.srtfile_to_subtitlesapp/services/subtitle.py)则提供反向解析能力,用正则 ([0-9]*:[0-9]*:[0-9]*,[0-9]*) 提取时间轴行,供后续纠错与视频渲染使用。

字幕纠错:基于编辑距离对齐视频文案

whisper 识别出的字幕在文字内容上可能与 AI 生成的视频文案存在差异(识别错误、空格、标点)。为此 app/services/subtitle.py 实现了 correct(subtitle_file, video_script),在识别后对字幕文件做原地修正,流程如下:

  1. 解析 SRT 为 (序号, 时间轴, 文本) 列表,同时把视频文案按标点拆成 script_lines
  2. 双指针顺序对齐:脚本行与字幕行完全一致则直接通过;
  3. 不一致时做跨行合并——从当前字幕行开始向后拼接后续字幕行,只要拼接后与脚本行的相似度提升就继续合并(同时把时间轴的结束时间延长到最后一行的结束时间),以处理"一句话被 whisper 切成多条字幕"的情况;
  4. 相似度基于编辑距离计算:levenshtein_distanceapp/services/subtitle.py)实现经典的 DP 算法,similarity = 1 - 距离/最长文本长度,不区分大小写;
  5. 合并后与脚本行相似度超过 0.8 时记为 Merged/Corrected,否则记为 Mismatch——但两种情况下都会用脚本行文本替换字幕内容并保留时间轴,确保成片字幕逐字与配音文案一致;
  6. 若脚本行有剩余而字幕已耗尽,剩余行会借用现有字幕时间轴或写入零时间轴占位;仅当发生任何修正时才重写文件,否则打印 Subtitle is correct

该函数由 app/services/task.py 在 whisper 生成字幕后立即调用;app/services/subtitle.py 底部的 __main__ 入口则提供了一个独立调试方式:指定 task_id,读取任务目录中的 subtitle.srtscript.json,单独运行纠错与重新生成。

字幕在流水线中的位置与后续渲染

app/services/task.py 的主流程看,字幕是任务的第四阶段:生成脚本 → 生成音频(TTS,产出 sub_makeraudio.mp3)→ 生成字幕generate_subtitle)→ 下载素材与合成视频。generate_subtitle 还支持 stop_at = "subtitle" 的调试模式,即任务到字幕为止直接返回 subtitle_path,便于单独验证字幕产物。

字幕生成后,app/services/video.pygenerate_video 使用 moviepy 的 SubtitlesClip 解析 subtitle.srt,再为每条字幕构建 TextClip 叠加到视频上:默认字体 STHeitiMedium.ttc,位置支持 bottom(默认,距底部约 5% 高度)、topcentercustom(按百分比 Y 坐标并约束在屏幕安全区内),这些外观参数在请求模型 app/models/schema.py 中定义为 subtitle_enabled(默认 True)与 subtitle_position(默认 "bottom")等字段,可通过 API 或 WebUI 请求逐项控制。

实践建议与故障排查

结合文档与源码,整理出以下可操作的结论:

场景 建议
日常生成、无 GPU subtitle_provider = "edge",速度快、零硬件要求
edge 字幕质量不佳(句数对不齐导致回退) 切换 subtitle_provider = "whisper"
国内环境使用 whisper 按文档网盘地址下载 whisper-large-v3,解压至 models/whisper-large-v3,确保其中存在 model.bin
有 NVIDIA GPU [whisper] 段配置为 device="cuda"compute_type="float16"(或 int8_float16
不需要字幕 subtitle_provider 留空,或请求参数中关闭 subtitle_enabled

常见故障可对照源码日志定位:模型加载失败会打印 failed to load model 并提示检查 models 目录(网络不通导致 HuggingFace 下载失败是最常见原因);edge 匹配失败会打印 failed, sub_items len: X, script_lines len: Y,此时任务自动回退 whisper;whisper 生成后会依次出现 correcting subtitleMerged/Corrected / Mismatch / Subtitle is correct 日志,可据此判断纠错是否实际生效。

适用前提:以上行为基于当前仓库代码(faster_whisper 依赖、默认 large-v3 + CPU + int8),修改 [whisper] 配置后需重启服务才会生效,因为模型参数在模块导入时读取且模型实例在进程内复用。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384