ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

FrameFetch:开源视频剧本对齐与AI分析报告工具

FrameFetch:开源视频剧本对齐与AI分析报告工具

1. 为什么我要做 FrameFetch 这个开源工具

做视频内容这行的朋友应该都有体会:一条片子剪完,最耗时间的往往不是剪辑本身,而是反复回看素材、对剧本、写分析报告。尤其是团队协作的时候,导演、编剧、剪辑、运营各看各的,每个人对同一条片子的理解都不一样,最后开会扯皮两小时,结论还是"再改改"。

我去年帮几个做短剧和知识类视频的团队做流程梳理,发现一个共性问题:视频和剧本是割裂的。剧本躺在飞书文档里,成片躺在网盘里,中间没有任何结构化的对应关系。你想知道"第 3 集第 12 分钟那句台词到底有没有按剧本拍",只能人肉拖进度条。这种低效在批量生产内容时会被无限放大。

FrameFetch 就是冲着这个痛点去的。它的核心逻辑很朴素:你把视频文件和剧本一起丢进去,它自动做时间轴对齐、台词比对、画面节奏分析,最后吐出一份可复核的 AI 分析报告。注意"可复核"这三个字,这是它和市面上那些"AI 一键出结论"工具最大的区别——报告里每一条结论都带时间戳和原文引用,你能点回去验证,而不是盲信一个黑盒。

这个项目适合谁?我列一下:做短剧/网剧的编剧和制片、做知识付费课程的教研、做企业宣传片的策划、以及任何需要"视频内容结构化"的团队。哪怕你只是个人 UP 主,想复盘自己哪期视频节奏拖了,它也能用。技术栈上它是开源的,Python 为主,前端轻量,部署门槛不高,一台带显卡的机器或者云上租个实例就能跑。

下面我把整个项目的设计思路、核心实现、实操流程和踩过的坑,完整拆一遍。内容会比较长,但都是能直接抄作业的东西。

2. 整体架构设计与技术选型思路

2.1 为什么是"视频+剧本"双输入,而不是只喂视频

很多人第一反应是:现在多模态大模型这么强,直接喂视频让它分析不就行了?我试过,结论是不靠谱。原因有三个。

第一,纯视频分析拿不到"意图"。AI 能看出画面里两个人在吵架,但它不知道剧本里写的是"表面争吵实则试探",这种潜台词只有剧本能给。第二,纯视频分析的时间精度差。大模型对长视频的时间定位经常漂移,说"第 5 分钟有个冲突",实际可能在 7 分半。第三,也是最关键的,没有参照系就无法复核。剧本是"预期",视频是"实际",分析报告的价值在于呈现两者的差异,而不是单方面描述视频。

所以 FrameFetch 的架构从一开始就是双轨的:一条轨道解析剧本,产出结构化的场景-台词-情绪标注;另一条轨道解析视频,产出镜头切分、语音转写、时间戳。两条轨道在"对齐层"汇合,做时间轴匹配和差异计算。这个设计决定了后面所有的技术选型。

2.2 核心模块拆解与数据流

整个系统我拆成了五个模块,数据流是单向的,方便调试和替换:

  • 剧本解析器(Script Parser):把各种格式的剧本(纯文本、Word、Final Draft 的 .fdx)统一转成 JSON 结构,字段包括场景号、场景描述、角色、台词、括号内的动作提示。
  • 视频解析器(Video Parser):抽音频做 ASR 转写,同时做镜头边界检测(shot detection),产出带时间戳的语音片段和镜头列表。
  • 对齐引擎(Alignment Engine):核心中的核心,把剧本台词和 ASR 转写做文本对齐,输出每句台词的"预期时间 vs 实际时间"。
  • 分析器(Analyzer):基于对齐结果算指标,比如台词覆盖率、节奏密度、情绪曲线偏差。
  • 报告生成器(Reporter):把分析结果渲染成 HTML 报告,每条结论带可点击的时间戳。

数据流用一句话概括:剧本 → JSON,视频 → 转写+镜头,两者 → 对齐表 → 指标 → 报告。每个模块之间用 JSON 文件通信,不搞内存里传大对象,这样任何一步崩了都能从中间重跑,省时间。

2.3 技术选型背后的取舍

选型这块我踩过不少坑,说几个关键决策。

ASR 用 Whisper 系列而不是商用 API。商用 API 按分钟计费,一个 40 集的短剧跑下来成本不低,而且数据要传到别人服务器,很多剧组对素材保密有要求。Whisper 本地跑,faster-whisper 的 large-v3 模型在消费级显卡上实时率能到 10 倍以上,40 集也就一两个小时。代价是首次要下模型,大概 3GB。

对齐算法用动态规划而不是简单字符串匹配。剧本台词和实际说的经常有出入,演员会改词、会加语气词。简单匹配对不上就断了。我用的是基于编辑距离的序列对齐(类似 difflib 的思路但做了时间约束),允许一定比例的增删改,同时用时间单调性做剪枝,避免把后面的台词错误地对到前面。

报告用静态 HTML 而不是 Web 服务。一开始我想做个在线看板,后来发现没必要。报告是给人看的、要能转发、要能存档,静态 HTML 单文件最合适,双击就能开,还能直接发微信。前端就用原生 JS 加一点 CSS,不引框架,加载快。

存储用 SQLite 而不是 Postgres。单机工具,数据量不大,SQLite 零配置,一个文件带走所有中间结果,迁移和备份都省事。

3. 核心细节解析与实操要点

3.1 剧本解析:格式统一是第一道坎

剧本格式的混乱程度超出想象。有人用 Word 手打,有人用 Final Draft,有人直接微信发一段文字。解析器要做的第一件事是归一化。

我定义了一个中间 JSON schema,核心字段长这样:

{ "scene_id": 12, "scene_heading": "内景 咖啡馆 夜", "elements": [ {"type": "action", "text": "林夏推门进来,环顾四周。"}, {"type": "dialogue", "character": "林夏", "text": "你等很久了吗?", "parenthetical": "试探地"}, {"type": "dialogue", "character": "陈默", "text": "刚到。", "parenthetical": null} ] }

解析纯文本剧本时,靠的是缩进和角色名大写这两个特征。中文剧本里角色名不一定大写,所以我加了一个角色词典:先从剧本里统计高频出现的短行(长度小于 6 字、后面紧跟冒号或独立成行),人工确认一次角色列表,后续就按这个列表匹配。这个"人工确认一次"很关键,全自动识别角色名准确率只有七八成,确认一次能到 99%。

注意:解析 .fdx 文件时不要自己写 XML parser,直接用fdx-reader这类现成库,Final Draft 的 schema 有坑,自己解析容易漏字段。

实操心得:剧本里最容易被忽略的是括号内的动作提示(parenthetical),比如"(冷笑)""(停顿三秒)"。这些恰恰是分析表演还原度的关键。我在解析时把它们单独存字段,后面分析器会专门统计"有多少括号提示在成片里被体现了"。

3.2 视频解析:ASR 和镜头检测的配合

视频解析分两条线并行。

音频线:用 ffmpeg 抽 16kHz 单声道 wav,喂给 faster-whisper。这里有个参数很关键——vad_filter=True,开启语音活动检测,能过滤掉纯音乐和环境音段落,减少幻觉转写。Whisper 在没有语音的地方容易瞎编,开了 VAD 就老实了。转写结果带词级时间戳,我用word_timestamps=True拿到每个词的起止时间,后面做精细对齐全靠它。

画面线:镜头边界检测我用的是 PySceneDetect 的 ContentDetector,阈值设 27 左右。这个值是我在几十条片子上调出来的:太低会把镜头内的运镜误判成切镜,太高会漏掉快切。短剧的快切多,可以调到 22;纪录片长镜头多,调到 32 更稳。

两条线的结果按时间戳合并成一条时间轴:

时间区间类型内容
00:00:12.3 - 00:00:15.8镜头shot_004
00:00:12.5 - 00:00:14.9语音"你等很久了吗"
00:00:15.0 - 00:00:15.6语音"(停顿)"

这张表是后面所有分析的底座。

3.3 对齐引擎:让剧本和视频"对上号"

对齐是整个项目最难的部分,我单独拎出来讲。

核心问题是:剧本有 N 句台词,ASR 转写有 M 个语音片段,N 和 M 不一定相等(演员可能漏词、加词、改词)。我要找的是最优匹配。

算法思路是带时间约束的序列对齐:

  1. 先把剧本台词按顺序排好,ASR 片段也按时间排好。
  2. 用动态规划算对齐代价,代价函数 = 文本编辑距离 + 时间惩罚项。
  3. 时间惩罚项的作用是:如果剧本第 5 句被对到了视频很靠后的位置,而第 6 句又对到很前面,这种"时间倒挂"要重罚,因为台词顺序基本不会乱。

代价函数大概长这样:

def cost(script_line, asr_seg, prev_time): text_cost = edit_distance(script_line.text, asr_seg.text) / max(len(script_line.text), 1) time_cost = 0.0 if asr_seg.start < prev_time: time_cost = 10.0 # 时间倒挂,重罚 else: time_cost = abs(asr_seg.start - prev_time) / 60.0 # 归一化到分钟 return text_cost + 0.3 * time_cost

那个 0.3 的权重是调出来的。文本相似度是主信号,时间只是辅助约束,权重太大会让对齐被时间带偏。

对齐完输出一张表,每行是"剧本台词 → 匹配到的 ASR 片段 → 相似度 → 时间偏差"。相似度低于 0.6 的标红,这些就是"演员改词或漏词"的候选,需要人工复核。

提示:对齐前一定要把 ASR 转写里的语气词(嗯、啊、那个)先去掉,否则会干扰文本相似度计算。但去掉的不能扔,单独存起来,后面分析"口语化程度"要用。

3.4 分析指标:报告里到底该放什么

报告不是越长越好,我最后收敛到六个核心指标,每个都能直接指导创作:

  • 台词覆盖率:剧本里有几句台词在成片里出现了。低于 85% 说明删改较多,要核对是不是有意为之。
  • 台词还原度:出现的台词里,有多少是原样说的。这个指标低说明演员即兴多,可能是好事也可能是失控。
  • 节奏密度:每分钟的镜头数和台词数。短剧一般每分钟 8-15 个镜头,太低会显得拖。
  • 情绪曲线偏差:剧本标注的情绪走向 vs ASR 文本情感分析出的走向,两条曲线叠一起看。
  • 括号提示体现率:前面提到的 parenthetical 有多少被表演出来了。
  • 时间偏差分布:整体是"前紧后松"还是"前松后紧",能看出剪辑节奏问题。

每个指标在报告里都配一个可展开的明细表,点开能看到具体是哪些台词、哪个时间点。这就是"可复核"的落地方式。

4. 完整实操流程与关键环节实现

4.1 环境准备与依赖安装

先把环境搭起来。我推荐用 conda 建独立环境,避免和系统 Python 打架。

conda create -n framefetch python=3.10 conda activate framefetch # 核心依赖 pip install faster-whisper pip install scenedetect[opencv] pip install ffmpeg-python pip install python-docx pip install fdx-reader pip install jieba pip install snownlp

ffmpeg 要单独装,Windows 下建议下静态编译版,把 bin 目录加进 PATH。Linux 直接apt install ffmpeg。

注意:faster-whisper 依赖 CUDA 和 cuDNN,版本要对上。我踩过的坑是 cuDNN 8 和 9 的 API 不兼容,装之前先确认显卡驱动支持的 CUDA 版本,再选对应的 cuDNN。没显卡也能跑,用 CPU 模式,就是慢,40 集大概要跑一整天。

4.2 剧本预处理实操

假设你拿到一个 Word 剧本,第一步是转成结构化 JSON。

python -m framefetch.script_parser \ --input ./scripts/ep01.docx \ --output ./work/ep01_script.json \ --character-confirm

--character-confirm会触发交互式角色确认:程序列出它识别到的角色名,你确认或修正。这一步花两分钟,能省后面几小时的排查。

解析完检查一下 JSON,重点看三个地方:场景切分对不对、角色名有没有串、括号提示有没有丢。我一般会写个小脚本统计一下台词总数,和剧本原文对一下,数量对得上基本就没问题。

4.3 视频解析与转写

python -m framefetch.video_parser \ --input ./videos/ep01.mp4 \ --output ./work/ep01_video.json \ --whisper-model large-v3 \ --language zh \ --vad-filter

这一步最耗时。large-v3 模型首次运行会自动下载,约 3GB。转写速度取决于显卡,RTX 3060 上大概 8-10 倍实时,一集 30 分钟的视频 3-4 分钟跑完。

跑完检查转写质量,重点看人名和专有名词。Whisper 对中文人名的识别经常出错,比如"林夏"转成"林下"。解决办法是给它一个 initial_prompt,把主要角色名塞进去:

--initial-prompt "本视频角色:林夏、陈默、苏晚。"

这个技巧实测能把人名准确率从 70% 提到 95% 以上。

4.4 对齐与报告生成

两个 JSON 都准备好后,跑对齐:

python -m framefetch.aligner \ --script ./work/ep01_script.json \ --video ./work/ep01_video.json \ --output ./work/ep01_aligned.json \ --similarity-threshold 0.6

然后生成报告:

python -m framefetch.reporter \ --aligned ./work/ep01_aligned.json \ --output ./reports/ep01_report.html \ --title "第 1 集分析报告"

打开 HTML,你会看到左侧是剧本台词列表,右侧是视频时间轴,中间用连线表示匹配关系。相似度低的用黄色标出,点击能跳到对应视频时间点(报告里嵌了视频播放器,本地打开时能直接播放)。

4.5 批量处理与自动化

单集跑通后,批量处理用个 shell 脚本就行:

#!/bin/bash for ep in ./scripts/*.docx; do name=$(basename "$ep" .docx) python -m framefetch.script_parser --input "$ep" --output "./work/${name}_script.json" --no-confirm python -m framefetch.video_parser --input "./videos/${name}.mp4" --output "./work/${name}_video.json" python -m framefetch.aligner --script "./work/${name}_script.json" --video "./work/${name}_video.json" --output "./work/${name}_aligned.json" python -m framefetch.reporter --aligned "./work/${name}_aligned.json" --output "./reports/${name}_report.html" done

--no-confirm是给批量用的,跳过角色确认,用第一次确认好的角色词典。所以建议第一集手动确认一次,把角色词典存下来,后面复用。

5. 常见问题与排查技巧实录

5.1 转写质量差怎么办

这是问得最多的问题。排查顺序如下:

现象可能原因解决
大量幻觉文本没开 VAD加--vad-filter
人名全错缺 initial_prompt加角色名提示
背景音乐被转成词音频混音太重用 ffmpeg 做人生分离再转写
方言识别差模型不匹配换 large-v3,或微调
时间戳漂移音频采样率不对统一转 16kHz

人声分离我用的是 Demucs,虽然多一步,但对音乐多的片子效果提升明显。命令是demucs --two-stems=vocals input.mp4,产出的 vocals.wav 再喂给 Whisper。

5.2 对齐错位怎么修

对齐错位通常有两种:整体偏移和局部错乱。

整体偏移一般是片头片尾的问题。比如视频前面有 30 秒片头,剧本里没有,那所有台词都会往后偏 30 秒。解决办法是在对齐前手动指定一个时间偏移量,或者让程序自动检测第一句台词的匹配位置来校准。

局部错乱多半是重复台词导致的。剧本里"好的"出现了 20 次,ASR 里也有 20 个"好的",动态规划可能对错位置。我的处理是给每句台词加一个"上下文指纹"——把前一句和后一句拼起来算相似度,用上下文来消歧。这个改动让重复台词的对齐准确率提升了一大截。

提示:对齐结果里相似度在 0.5-0.7 之间的,建议全部人工过一遍。这个区间是"可能是改词也可能是错配"的模糊地带,机器判断不可靠。

5.3 报告打不开或视频不播放

报告是单 HTML 文件,但视频是外链的。如果你把 HTML 发给别人,对方没有视频文件,播放器就是黑的。两个方案:一是把视频转成低码率预览版嵌进报告(文件会变大),二是报告里只放时间戳,对方自己在本地播放器里跳转。

我一般用第二个方案,报告文件小,方便传。时间戳格式统一用HH:MM:SS.mmm,方便复制到任何播放器。

5.4 性能优化经验

跑批量的时候性能很关键。几个实测有效的优化:

  • ASR 用 batch 模式:faster-whisper 支持batched=True,配合batch_size=8,速度能再快 2-3 倍。
  • 镜头检测降分辨率:PySceneDetect 不需要全分辨率,先缩到 480p 再检测,速度快很多,准确率几乎不变。
  • 对齐用多进程:每集独立,用multiprocessing.Pool并行跑,核多的话线性加速。
  • 中间结果缓存:转写结果存下来,改对齐参数时不用重跑 ASR,这个省的时间最多。

5.5 几个容易忽略的细节

最后分享几个我踩坑踩出来的细节。

剧本里的省略号和破折号要统一处理。有的剧本用"……",有的用"...",ASR 转写里根本没有。对齐前统一替换成空,否则相似度会被拉低。

中英文混排的台词,比如"OK,没问题",Whisper 可能转成"ok 没问题"。做相似度计算前要统一大小写和全半角。

时间戳精度别用秒,用毫秒。短剧快切多,秒级精度不够用,对齐时会发现好几句台词挤在同一秒里。

报告里的颜色别用红绿,用蓝橙。红绿色盲比例不低,而且红绿在投影仪上对比度差,开会看不清。

这个项目我还在持续迭代,最近在加的一个功能是"多集趋势分析"——把 40 集的指标画成折线图,一眼看出哪几集节奏掉了。等稳定了再单独写一篇。如果你也在做视频内容结构化,欢迎拿这个思路去改,核心的对齐逻辑其实可以复用到播客、会议记录、课程字幕等很多场景。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进