用本地AI工具链打造COC跑团视频字幕工作流:语音识别到压制全指南
“神话与科学 part1”这个标题看起来像是一期普通的 COC 跑团熟肉但它背后的制作链路其实很不普通。馒馒来风格的跑团视频素材长、人物多、台词密还要保留原片里“bug 一样鬼畜”的节奏感。手剪字幕的传统做法一条条打轴、翻译、统一术语半小时素材往往要搭进去三五个晚上。所以这次我们换一个思路用本地 AI 工具链把“语音转写 — 台词翻译 — 字幕打轴 — 压制导出”做成一条可复用的工作流顺便把过程中最容易出问题的几个“bug 点”一起讲清楚。这篇文章不介绍某一个具体开源仓库而是给出一套适合 COC 跑团熟肉、番剧切片、鬼畜视频二创的字幕生产方案。核心内容包括环境准备、语音识别与说话人分离、LLM 翻译、ASS 字幕生成、ffmpeg 压制、批量任务与 API 服务化以及常见问题的排查清单。如果你正在处理“素材很长、台词很密、要出多语言字幕”的视频这篇可以直接参考。1. 核心能力速览能力项说明项目类型本地字幕生产与视频压制工作流适用素材COC 跑团录像、桌游视频、长对话视频、二创鬼畜素材语音识别Faster-Whisper / Whisper支持日文、英文、中文等多语言说话人分离可选 pyannote.audio用于区分角色台词字幕翻译本地 LLM 或翻译 API支持术语表约束字幕输出SRT / ASS / VTT视频压制ffmpeg libx264 / libx265硬字幕或软字幕批量任务可按目录批量处理多个视频文件API 接口可选 FastAPI 封装支持远程调用硬件要求建议 NVIDIA GPU 8GB 显存起CPU 可跑但速度较慢启动方式命令行 虚拟环境可自定义服务端口需要说明的是这套流程不是某个“一键启动整合包”而是由若干个成熟工具组合而成。首次搭建大概需要半小时后面就可以反复复用。2. 适用场景与使用边界这套流程适合以下几类场景字幕组或个人 UP 主制作长视频熟肉尤其是台词密集、角色多的跑团视频。需要把同一个视频快速导出中文、英文、日文字幕的海外内容团队。做鬼畜二创时需要在原片对话基础上重新组织字幕文案和节奏。研究本地 AI 推理、语音识别、LLM API 的开发者需要一套可运行案例。同时也要说清楚边界。这套流程是“辅助生产”不是“全自动生成成品”。跑团视频有很多特殊内容骰点音效、念规则书、玩家插科打诨、NPC 名字和神话生物名这些都不是纯转写 翻译能搞定的后面需要人工校对。千万不要把自动生成的字幕直接发布尤其是涉及盈利和公开传播时。版权和隐私方面同样需要注意只处理你有权翻译、剪辑和传播的素材涉及真人声音、人脸、角色形象时要确认授权不允许拿别人的付费内容做无授权二创。模型文件和视频素材也不要随意上传到第三方服务尽量在本地完成处理。3. 本地环境准备与软硬件清单3.1 硬件要求语音识别是这套流程里最吃资源的环节。以 Faster-Whisper 为例8GB 显存推荐使用 small / medium 模型处理 16kHz 单声道音频足够。16GB 及以上显存可以用 large-v3识别准确率更高但速度会慢一些。CPU 也能跑但半小时音频可能需要十几分钟到半小时具体取决于 CPU 核心数和模型大小。内存建议 16GB 起步转写长视频时音频会被分块加载。显存占用这里不给一个写死的数字因为跟音频长度、batch size、beam size 都有关系。实际观察方法后面单独讲。3.2 软件依赖建议使用 Python 3.10 或 3.11不要用太新的 3.13部分音频和机器学习依赖可能还没跟上。需要安装的基础工具如下# 虚拟环境 python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate # 基础依赖 pip install faster-whisper pip install openai-whisper pip install pyannote.audio pip install fastapi uvicorn pip install pydub srt系统层面需要安装 ffmpeg。Windows 用户可以直接下载 ffmpeg 可执行文件并加入 PATHLinux 用户使用 apt 或 dnf 安装macOS 用户建议用 Homebrew。# Ubuntu / Debian sudo apt update sudo apt install ffmpeg # macOS brew install ffmpeg检查 ffmpeg 是否可用ffmpeg -version如果输出正常环境准备这步就完成了。4. 字幕转录与翻译流程4.1 从视频中提取音频COC 跑团视频通常是录像加游戏画面音频里可能混着人声、BGM、音效。为了减少识别干扰先转成 16kHz 的 WAV 文件ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -c:a pcm_s16le audio.wav参数说明-vn表示丢弃视频流。-ac 1把声道合并为单声道。-ar 16000是 Whisper 常用的采样率。-c:a pcm_s16le输出无损 WAV确保识别时没有二次压缩损失。4.2 用 Faster-Whisper 转写台词Faster-Whisper 是 CTranslate2 实现的 Whisper 加速版本在 GPU 和 CPU 上都有不错的表现。下面是一个可直接运行的转写脚本from faster_whisper import WhisperModel model WhisperModel(small, devicecuda, compute_typefloat16) segments, info model.transcribe( audio.wav, languageja, vad_filterTrue, vad_parameters{min_silence_duration_ms: 500}, beam_size5, ) for segment in segments: start segment.start end segment.end text segment.text.strip() if text: print(f{start:.2f} - {end:.2f}: {text})这里有几个参数值得注意devicecuda使用 GPUCPU 推理时改成devicecpu。vad_filterTrue会自动过滤纯静音片段对跑团视频录播很有用。languageja指定语言可以显著提高日文识别准确率也能减少错误的时间戳。beam_size5是一个兼顾准确度和速度的默认值。如果识别结果大量出现重复字或时间戳错位可以把vad_filter关掉测试或者换成compute_typeint8。这个问题在长视频里很常见原因和处理方式后面排查表中专门写。4.3 说话人分离跑团视频里角色多台词混在一起单纯转写出来的文本很难区分谁说的。这时候可以用 pyannote.audio它能把音频按说话人切分并打标签。from pyannote.audio import Pipeline pipeline Pipeline.from_pretrained( pyannote/speaker-diarization-3.1, use_auth_tokenYOUR_HF_TOKEN ) diarization pipeline(audio.wav) for turn, _, speaker in diarization.itertracks(yield_labelTrue): print(f{turn.start:.2f} - {turn.end:.2f}: {speaker}: {turn})使用 pyannote 需要先在 Hugging Face 上申请模型访问权限并在本地配置 token。这里的YOUR_HF_TOKEN要替换成你自己的 token。如果不想用云端鉴权也可以使用其他本地说话人聚类算法但准确率会低一些。说话人分离结果和 Whisper 时间戳需要做对齐原理是取两个结果的时间区间交集把台词归属到对应说话人身上。这个逻辑可以写成一个脚本但跑团视频里经常出现多人同时讲话、耳语、怪物音效对齐后还是要人工检查。4.4 用 LLM 翻译台词翻译环节可以用本地 LLM也可以调用翻译 API。本地 LLM 的优势是隐私安全、不依赖外部网络但需要额外显存API 翻译更快但要处理数据外传的合规风险。下面是一个调用通用 OpenAI 兼容接口的翻译函数实际项目里需要根据你的 API 地址、Key、模型名替换配置import openai client openai.OpenAI( base_urlhttp://127.0.0.1:11434/v1, api_keynot-needed, ) prompt_template 你是一个字幕翻译助手。 请将下面的日文台词翻译成中文要求口语自然、不要逐字直译。 保留游戏术语、角色名和语气词没有把握的专有名词直接保留原文。 只输出翻译结果不要输出解释。 原文 {text} def translate(text: str) - str: response client.chat.completions.create( modelqwen2.5:7b, messages[ {role: system, content: 你是一个专业的字幕翻译工具。}, {role: user, content: prompt_template.format(texttext)} ], temperature0.3, ) return response.choices[0].message.content.strip()这里有两个细节temperature0.3避免翻译结果过度发散。提示词里要求“没把握的专有名词直接保留原文”对克苏鲁跑团里的旧神名、NPC 名特别重要。比如“阿撒托斯”“奈亚拉托提普”这类术语翻译错了会严重影响观众理解。实际批量翻译时按段落合并后的文本块逐段翻译比逐句翻译更连贯。每段长度控制在 200 字符以内既能保持上下文又不会让 LLM 处理太长导致截断。5. 打轴与 ASS 字幕处理5.1 生成 SRT / ASS 文件把 Whisper 输出的时间戳和翻译结果合并就可以生成字幕文件。下面是一个简单的 SRT 生成脚本import srt from datetime import timedelta entries [] for idx, (start, end, text) in enumerate(translated_segments, start1): entries.append(srt.Subtitle( indexidx, starttimedelta(secondsstart), endtimedelta(secondsend), contenttext, )) with open(output.srt, w, encodingutf-8) as f: f.write(srt.compose(entries))如果要做 ASS 字幕需要额外定义样式比如字号、描边、字体以及把不同角色的台词染成不同颜色。跑团熟肉里常见做法是主持人、玩家、NPC 使用不同颜色的字幕方便观众区分。5.2 调整字幕节奏自动化生成的字幕往往和口语节奏不完全匹配。常见问题包括台词太长一行放不下。时间轴比说话内容长很多。因为是“鬼畜风格”的剪辑原片台词和画面错位是故意为之字幕打轴时如果强行对齐嘴型反而会显得突兀。处理方式是“分段粒度”和“最短显示时长”两个策略。把单行字幕最多限制在 14 个中文字符以内超过就拆成两行每句字幕最短显示 0.8 秒避免一闪而过。这个逻辑写进脚本里能减少后期手工调整量。def split_line(text, max_chars14): if len(text) max_chars: return [text] lines [] while len(text) max_chars: lines.append(text[:max_chars]) text text[max_chars:] lines.append(text) return lines5.3 压制字幕到视频字幕文件生成后有两种处理方式硬字幕直接烧录到视频画面里输出后任何播放器都能显示适合最终发布。软字幕封装成 mkv 文件里的字幕轨道方便切换多语言适合存档和后续修改。硬字幕命令ffmpeg -i input.mp4 -vf assoutput.ass -c:v libx264 -crf 18 -c:a copy output_hardsub.mp4注意assoutput.ass在 Windows 下路径里有反斜杠可能需要转义或使用相对路径。如果显示“No such filter: ass”说明 ffmpeg 编译时没有包含 libass需要重新安装完整版 ffmpeg。6. 批量任务与 API 服务化6.1 批量处理视频目录跑团三部曲这种系列视频通常一次要处理多个 Part不可能每次都手动改文件名。可以把输入目录、输出目录、模型名都提取成配置参数然后批量处理。import os import subprocess INPUT_DIR ./videos OUTPUT_DIR ./outputs EXTENSIONS (.mp4, .mkv, .mov) for filename in sorted(os.listdir(INPUT_DIR)): if not filename.endswith(EXTENSIONS): continue input_path os.path.join(INPUT_DIR, filename) output_path os.path.join(OUTPUT_DIR, filename.rsplit(., 1)[0] _sub.mp4) subprocess.run( [ffmpeg, -y, -i, input_path, -vf, assoutput.ass, -c:v, libx264, -crf, 18, -c:a, copy, output_path], checkTrue, )批量任务一定要加日志。每个文件处理完成或失败时把文件名、耗时、错误信息写进result.log。不做日志的批量任务一旦跑到第 20 个文件突然出错排查会非常痛苦。6.2 用 FastAPI 封装字幕服务如果要做成一个内部服务让组员提交视频后自动出字幕可以用 FastAPI 包一层。接口设计可以简单一点from fastapi import FastAPI, UploadFile, File from pathlib import Path app FastAPI() app.post(/transcribe) async def transcribe(file: UploadFile File(...), language: str ja): temp_path Path(uploads) / file.filename temp_path.write_bytes(await file.read()) # 这里调用第 4 节的转写函数 segments run_transcribe(temp_path, languagelanguage) return { filename: file.filename, segments: segments, }启动服务uvicorn main:app --host 127.0.0.1 --port 8000注意接口服务要限制访问范围不要在公网裸奔。最简单的做法是只监听127.0.0.1或者放在内网再通过反向代理加鉴权。调用接口的测试脚本curl -X POST http://127.0.0.1:8000/transcribe \ -H Content-Type: multipart/form-data \ -F fileinput.mp4 \ -F languageja如果接口返回正常整个字幕生产链路就可以接到自己的工具或者压测脚本里了。7. 资源占用与性能观察7.1 怎么看显存占用建议使用nvidia-smi实时观察显存watch -n 1 nvidia-smiWindows 下用nvidia-smi -l 1Whisper 推理时显存占用主要集中在音频特征计算和解码阶段。batch size 越大显存占用越高速度也越快。显存不够时报错通常是CUDA out of memory处理方式是调小 batch_size或者切换模型到 small / base。7.2 CPU 与 GPU 推理差异CPU 推理适合没有 GPU 的机器但速度差异明显。同样是 30 分钟音频GPU8GB 显存、small 模型几分钟内完成。CPU现代 8 核、small 模型可能 15 到 40 分钟。GPU16GB 显存、large-v3准确率更高但解码更慢。实际速度还要看音频里人声密度。跑团视频属于“人声密集”素材比普通播客的转写时间更长。如果你经常处理这类素材建议优先选带 GPU 的设备。7.3 降低资源占用的技巧用int8量化替代float16显存占用明显下降准确率损失在可接受范围。开启 VAD 过滤静音片段减少无效计算。把 30 分钟音频切成 5 分钟一段分别转写再合并结果可以避免长音频引发的显存波动。翻译服务单独部署在另一台机器或容器里避免和转写任务争抢 GPU 显存。8. 常见问题与排查方法这里列出这套工作流里最容易踩的几个坑每一项都是从实际使用中总结出来的方向但不代表你的环境一定会遇到。问题现象可能原因排查方式解决方案Whisper 转写结果大量重复VAD 参数过激或采样率不对关闭 VAD 对比测试调整min_silence_duration_ms换成 16kHz WAV时间长轴偏移越来越严重音频处理有丢帧或视频编辑后时间线变化检查音频总时长和视频总时长是否一致用 ffmpeg 重新抽取完整音频避免剪辑拼接字幕中文乱码或显示为方框SRT/ASS 文件编码不是 UTF-8查看文件编码格式保存为 UTF-8 with BOMCUDA out of memory显存不够或 batch size 过大观察 nvidia-smi降低 batch size改用 small 模型或使用 int8翻译结果把角色名和怪物名乱译LLM 提示词没有术语约束查看翻译日志在提示词里加入“保留专有名词”约束并维护术语表ffmpeg 没有 ass 滤镜安装的是精简版 ffmpeg执行 ffmpeg -filtersgrep ass批量任务中途卡住某个文件解码失败或接口超时查看 result.log增加超时重试对失败文件单跑API 服务调用失败请求体格式不对或端口未对外开放curl 测试 查看服务日志确认multipart/form-data字段名与后端一致如果遇到问题第一反应不是重装环境而是先看日志。不管是 Whisper 的 stderr、LLM API 的返回信息还是 ffmpeg 的错误管道都会给出明确的定位线索。9. 最佳实践与使用建议第一次跑通时先只处理 1 分钟的测试片段确认转写、翻译、压制全链路正常再处理完整视频。维护一份“术语表”把角色名、地名、怪物名固定下来翻译提示词里直接引用能避免大量返工。为不同项目建立独立目录input/、audio/、subtitle/、output/分开管理不要混在一起。批量任务必须写日志和失败重试。比较稳妥的做法是每处理完一个文件就写一条进度记录程序崩溃后可以根据记录续跑。接口服务要考虑并发限制。如果是上传长视频建议同步转码改成任务队列避免长时间阻塞 HTTP 连接。涉及真人声音、人脸、版权素材时一定要确认授权。跑团视频里的角色立绘、BGM、录音素材都不能默认可以自由传播。公开或商用前至少做一遍人工校对。机器生成的翻译再快也替代不了对剧情和角色关系的理解。10. 总结与下一步这套“本地字幕生产工作流”最值得试的点是把重复劳动压到了最低语音识别自动出词轴LLM 翻译自动出中文脚本批量合并出字幕ffmpeg 一次性压制输出。对于“神话与科学”这种信息密度高、连载多 Part 的 COC 跑团视频它非常合适。第一次实践时建议先跑通“单视频转写 单句翻译 SRT 输出”三步确认每一步的输出格式都符合预期。最容易踩的坑在时间轴偏移和术语翻译这两步要多花时间调参和校对。后续可以继续扩展的方向包括接入本地说话人识别区分角色台词用术语表实现中、英、日多语言同时导出把 FastAPI 服务接到剪辑软件自动上传或者加入基于台词情绪的鬼畜特效标记辅助二创剪辑。先把基础链路跑通后面每一步都是增量收益。