视频转文本+LLM抽取+向量检索:搭建逐集对比流水线
发布时间:2026/9/28 20:19:24来源:尧图网络
这次我们直接拆一个很实际的场景把《三杰与四斯逐集对比》这类需要反复看片、逐集找差异的内容变成一条能批量执行、可以反复复用的本地技术流水线。标题里写着“至急镰仓VS不死的格罗扎姆”本质上是在赶内容越赶越不能靠手动回放、截图、记台词而是要用结构化工具把视频素材转成可检索、可对比的文本数据。这篇文章会按“视频转文本 → 提示词抽取 → 向量检索 → 批量生成对比表”的顺序展开。文中的命令和脚本都是通用模板不绑定具体作品。只要你有系列视频素材就能把“镰仓VS不死的格罗扎姆”这类对比需求抽象成字段提取和批量输出任务。整条链路支持 CPU也支持 GPU 加速支持本地模型也支持标准 OpenAI 兼容接口。对做逐集拆解、角色资料整理、系列作品排片和内容二创的人来说这套流程比手动整理稳定得多。1. 核心能力速览能力项说明项目类型系列视频逐集内容分析辅助流程输入素材视频文件、字幕文件、剧本、已有文稿核心功能音频转写、文本清洗、LLM 字段抽取、向量检索、批量报表输出硬件要求CPU 可完成基础转写GPU 可加速转写和本地大模型推理显存占用取决于具体模型版本不能用一个网传数字替代本机实测启动方式Python 脚本、命令行、本地 API 服务接口能力转写模型和语言模型均有 API 调用方式批量任务支持按集数循环失败写日志并继续适合场景逐集对比、角色能力复盘、剧情时间线整理、资料库建设使用边界需要确认素材授权不能直接搬运整集字幕或原片片段这套方案不是某个现成软件而是把多个开源组件组装在一起。核心组件包括 faster-whisper、OpenAI 兼容的语言模型接口、Chroma 向量库和 Python 批处理脚本。好处是每一环都可以替换文本转写不准就换模型抽取结果不满意就改提示词检索效果一般就换 embedding。2. 适用场景与使用边界适合这群人需要逐集统计角色出场、能力、胜负关系的内容编辑。正在做系列作品复盘、角色战力对比表的文案。想把大量视频素材沉淀成可检索文本库的团队。需要在短时间内输出“至急”对比稿的内容生产者。这些场景的共同点是输入是几十集甚至几百集视频输出不是一篇观后感而是一张能横向比较的表格或一套可查询的资料库。手动整理会因为个人记忆偏差、漏看、跳看导致结论不完整文本流水线至少能把“哪一集出现过”“对应时间点在哪”“原文说了什么”固定下来。但也要把边界说清楚转写出的完整台词只适合内部检索和摘要公开发布不能整段粘贴。涉及影视角色、演员肖像、声音素材时要确认授权范围。对比结论不要写成一锤定音的“必胜/必败”容易引发歧义也容易偏离事实。不要用这招做大段内容搬运、盗录、无授权二创。工具本身是中性的问题出在发布环节。批量跑完之后保留来源信息标注“个人整理”或“学习用途”并在发布前做一次人工复核。3. 环境准备与前置条件3.1 系统与运行环境推荐使用 Python 3.10 或更高版本。Windows、Linux、macOS 都可以但建议在 Linux 或 Windows WSL 里跑长任务稳定性更好。视频处理依赖 FFmpeg转写和检索依赖 Python 包接口服务依赖本地语言模型或远端 API。创建独立虚拟环境避免依赖冲突python -m venv venv # Windows venv\Scripts\activate # Linux/macOS source venv/bin/activate3.2 安装依赖pip install --upgrade pip pip install faster-whisper openai-whisper ffmpeg-python pip install chromadb sentence-transformers pip install openai pydantic tqdmfaster-whisper 负责音频转写Chroma 负责向量检索openai 库用于调用兼容接口。如果只需要最简单的文本对比不装 Chroma 和 sentence-transformers 也可以先用 JSONL 或 Excel 跑通流程。3.3 目录结构建议从一开始就按目录分好输入、输出和临时文件series-compare/ ├── episodes/ # 原视频按 01.mp4、02.mp4 命名 ├── audio/ # 抽出来的音频临时文件 ├── outputs/ │ ├── texts/ # 每集转写文本 │ ├── notes/ # LLM 抽取的结构化字段 │ └── tables/ # 最终对比表 ├── scripts/ # Python 脚本 └── logs/ # 任务日志和失败记录这样批量任务中断时可以避免重复跑已经完成的部分。4. 视频转逐集文本的完整流程4.1 用 FFmpeg 抽取音频视频直接喂给转写模型也可以但会消耗更多 CPU/GPU。更稳妥的做法是先把视频轨去掉统一转成 16kHz 单声道 wav。ffmpeg -i episodes/01.mp4 -ac 1 -ar 16000 -vn audio/01.wav如果只需要处理字幕文件可以跳过音频抽离。但很多旧片源没有外挂字幕音频转写仍然是更通用的方案。4.2 用 faster-whisper 转写用 small 模型做基础中文转写速度和准确度比较平衡。对术语和人名要求高时换成 medium 或 large-v3。from faster_whisper import WhisperModel model WhisperModel(small, deviceauto, compute_typeint8) segments, info model.transcribe( audio/01.wav, languagezh, vad_filterTrue, beam_size5 ) with open(outputs/texts/01.txt, w, encodingutf-8) as f: for seg in segments: line f[{seg.start:.1f} - {seg.end:.1f}] {seg.text} print(line) f.write(line \n)第一次跑的时候不要追求最大模型先用一个 3 到 5 分钟片段验证转写质量。如果模型把人名和专有名词转错了不要急着换大模型先检查音频采样率和 VAD 参数很多问题出在前处理。4.3 字幕对齐与人工修订faster-whisper 输出的时间戳可以直接用来做“某句话出现在第几秒”的定位。如果片源本身有字幕也可以用 Pysubs2 读取字幕文件然后按时间窗口把字幕和转写文本合并。合并结果尽量保留原始表达LLM 抽取阶段不要依赖记忆而是依赖这段带时间戳的原文。转写模型对中文特摄、动画、纪录片里的专有名词不一定准确。常见做法是准备一个替换词典不死的格罗扎姆 - 不死的格罗扎姆 镰仓 - 镰仓 三杰 - 三杰 四斯 - 四斯清理阶段用简单字符串替换能解决不少同音字问题。5. 用提示词模板抽取对比字段转写文本是长文本直接丢给 LLM 做全量总结容易超出上下文窗口也不利于后续按集检索。更合理的做法是先按集切段再让模型输出统一结构的 JSON 字段。5.1 字段设计对比“镰仓VS不死的格罗扎姆”这类需求时可以抽取这些字段字段说明episode集数或章节编号scene所在场景或地点character_a对比对象 Acharacter_b对比对象 Bconflict冲突时间、冲突原因abilities双方展示出的能力和限制outcome结果或观察战果quote适合引用的一句原文timeline与前后剧情相关的时间线线索字段不需要每次完全一致。见核对实际素材后可以增加“首登场”“武器”“队友”“情绪变化”等字段关键是要用 JSON 固定下来方便后续表格化。5.2 提示词模板你是影视内容对比助手。请基于下面这段逐集文本抽取与“镰仓 VS 不死的格罗扎姆”相关的信息输出 JSON。 字段要求 { episode: 集数或章节, scene: 地点或场景, character_a: 角色或阵营A, character_b: 角色或阵营B, conflict: 冲突点, abilities: 展示的能力与限制, outcome: 结果或观察战果, quote: 重要台词, timeline: 时间线线索 } 注意事项 1. 不要改写原文尽量使用原文表述。 2. 原文没有的字段填 null。 3. 不要补充文本中没有出现的信息。 4. 如果该段与对比无关输出 {empty: true}。 文本内容 {{TEXT}}先把模板放到系统提示词里再把一集文本放在用户消息里这样做比单纯拼接提示词更稳定。5.3 调用 OpenAI 兼容接口本地部署时可以启动 vLLM、Ollama 或 LM Studio它们通常提供/v1/chat/completions兼容接口。下面是一个调用示例import requests PROMPT 你是影视内容对比助手。请基于下面这段逐集文本抽取相关字段并输出 JSON。... def extract_note(text, modelqwen2.5-7b-instruct, urlhttp://127.0.0.1:8000/v1/chat/completions): payload { model: model, messages: [ {role: system, content: PROMPT}, {role: user, content: text[:3000]} ], temperature: 0.1, stream: False } resp requests.post(url, jsonpayload, timeout120) resp.raise_for_status() return resp.json()[choices][0][message][content] text open(outputs/texts/01.txt, encodingutf-8).read() print(extract_note(text))返回的字符串是 JSON 文本需要再用json.loads()解析。如果模型输出格式不稳定可以开启 request body 中的response_format{type: json_object}支持该参数的接口会显著减少解析报错。6. 向量检索与逐集对比当集数超过 10 集之后靠打开文本文件逐个看会很累。把结构化字段和原文文本写入向量库就能用自然语言查询做初步筛选。6.1 写入 Chromaimport chromadb client chromadb.PersistentClient(path./compare_db) col client.get_or_create_collection(episode_notes) notes [ { episode: 01, scene: 镰仓, conflict: 第一次交手, quote: 不死之身只是一个幌子 }, # 更多字段... ] documents [] ids [] metadatas [] for idx, n in enumerate(notes): documents.append(f{n[episode]} {n[scene]} {n[conflict]} {n[quote]}) ids.append(str(idx)) metadatas.append({episode: n[episode]}) col.add(idsids, documentsdocuments, metadatasmetadatas)6.2 查询相似片段results col.query( query_texts[不死的格罗扎姆第一次登场在哪一集], n_results5 ) print(results[documents])向量检索适合“快速定位可能相关的片段”不能替代精确字段对比。比如想统计“每集谁先出手”更可靠的方法是用 LLM 抽取字段再把字段写入 pandas 或 Excel 表格。6.3 生成逐集对比表最终输出用 pandas 最好处理import pandas as pd data [ {episode: 01, scene: 镰仓, result: 初次接触, quote: ...}, {episode: 02, scene: 海边, result: 能力暴露, quote: ...}, ] df pd.DataFrame(data) df.to_csv(outputs/tables/compare.csv, indexFalse, encodingutf-8-sig)CSV 直接用 Excel 打开方便快速核对和二次编辑。7. 批量任务与接口调用真正出效率的地方是批量处理。不要每集手动跑一次脚本用一个循环处理整个目录并且把失败任务记录到日志里。7.1 批量转写与抽取import os import json import subprocess import logging import time EPISODES_DIR ./episodes AUDIO_DIR ./audio TEXT_DIR ./outputs/texts NOTE_DIR ./outputs/notes LOG_FILE ./logs/batch.log logging.basicConfig( filenameLOG_FILE, levellogging.INFO, format%(asctime)s %(levelname)s %(message)s ) for file in sorted(os.listdir(EPISODES_DIR)): if not file.endswith(.mp4): continue base os.path.splitext(file)[0] audio_path os.path.join(AUDIO_DIR, base .wav) text_path os.path.join(TEXT_DIR, base .txt) note_path os.path.join(NOTE_DIR, base .json) if os.path.exists(note_path): logging.info(fskip {base}, already processed) continue try: subprocess.run( [ffmpeg, -y, -i, os.path.join(EPISODES_DIR, file), -ac, 1, -ar, 16000, -vn, audio_path], checkTrue, capture_outputTrue ) # 这里调用 faster-whisper 转写 # 再调用 LLM 抽取字段 # 写入 note_path logging.info(fok {base}) except Exception as e: logging.error(ffail {base}: {e}) time.sleep(1)日志里只需要两类信息哪些集跑完了、哪些集失败。不要用 print 满天飞长任务输出太多反而找不到问题。7.2 失败重试与断点续跑批量任务建议先检查输出文件是否已经存在存在就跳过。失败任务不要立即重试先把错误信息写到日志然后等待几秒再继续下一集。全部跑完后再单独看日志里的 fail 列表决定是换模型还是修音频。一个简单的延迟策略import time from urllib.error import URLError MAX_RETRY 3 def call_with_retry(func, *args, **kwargs): for attempt in range(MAX_RETRY): try: return func(*args, **kwargs) except (URLError, TimeoutError): wait 2 ** attempt time.sleep(wait) raise RuntimeError(max retry exceeded)接口服务如果高频调用可能触发限流。批量任务里加 sleep 和重试是基本操作不是可选优化。8. 资源占用与性能观察8.1 先看转写模型faster-whisper 的 small 模型在 CPU 上也能跑但长视频会很慢。有 NVIDIA 显卡时devicecuda会明显提速。不同 GPU 的显存占用差异很大不要只看别人帖子里的一个数字要自己在任务管理器里看当前进程占用。观察显存# Linux watch -n 5 nvidia-smi # Windows nvidia-smi -l 2如果整条流水线在同一个终端里同时跑转写和本地大模型显存可能不够。更稳妥的做法是先把所有集转写成文本再统一进入 LLM 抽取阶段。两个阶段错开能降低资源峰值。8.2 上下文长度对性能的影响LLM 抽取文本时不要一次性把整集文本全部塞进去。上下文越长内存占用越高输出速度也会变慢。建议按 3000 到 5000 字切段或者按转写时间戳分段。分段的好处还包括即使某一段抽取失败只会丢掉这一段不会影响整集结果。8.3 降低资源占用的方法转写用 int8 量化如compute_typeint8。本地大模型优先选择 4bit 量化版本。关闭不用的模型进程避免多个服务同时占显存。批量任务循环里不要每集都重新加载模型尽量常驻一个模型服务。长视频转写前先按音频时长切片避免一次性申请过多内存。性能不是一上来就能调好的。先用 1 集测试记录峰值显存和耗时再决定后续用多少并发。9. 常见问题与排查方法问题现象可能原因排查方式解决方案转写结果全是英文或乱码没有设置languagezh或音频采样率不对查看输入 wav 参数和转写配置重新采样为 16kHz显式指定中文专有名词转写错误模型太小没有术语词典打印原文确认错字换成 medium/large 模型或做文本替换LLM 返回的不是 JSON提示词不明确模型输出不稳定打印原始返回内容加入 few-shot 示例开启 json_object 模式批量任务跑到一半卡住接口超时或本地显存不足查看日志和 nvidia-smi增加超时时间降低并发恢复时跳过已处理文件本地接口 127.0.0.1 无法访问服务未启动或端口冲突先 curl 接口地址检查进程换端口重新启动向量查询结果不相关embedding 模型与文本语言/题材不匹配测试几条典型问题换中文 embedding 模型或加入更多原文字段对比表字段大量为空原文里确实没有这些内容或提示词要求太高抽样查看原文片段调整字段设计减少幻觉发布后被质疑截图来源没有保留素材路径和时间戳检查最终表格是否保留集数信息保留元数据字段如 input_file、start_time排查顺序记住一条先还原输入再看日志。转写文本有没有问题、提示词输出是什么、接口有没有报错三步下来基本能定位问题。10. 最佳实践与合规建议10.1 工程化建议第一次只跑 1 集不要直接全量跑 100 集。先把输出格式、提示词和字段结构定下来再批量扩展。保留一套最小可运行配置。脚本里不要写死路径用项目根目录的相对路径或用配置文件统一管理输入输出目录。{ episodes_dir: ./episodes, audio_dir: ./audio, text_dir: ./outputs/texts, note_dir: ./outputs/notes, model: qwen2.5-7b-instruct, api_url: http://127.0.0.1:8000/v1/chat/completions, batch_delay_seconds: 1 }配置和代码分离后面换模型、换路径都不用改主脚本。10.2 效果质量建议LLM 抽取结果必须留痕。每一条结构化记录都要带原文引用和时间戳方便回溯。最终发布前要人工复核几个高风险点人物关系是否写反。胜负结论是否过于绝对。台词引用是否和原片一致。有没有把“推测”写成“事实”。10.3 合规提醒使用视频片段、截图、台词进行公开分析时要特别注意授权边界。个人内部整理问题不大但要公开发布就需要避免整段搬运。推荐输出方式是自己的文字摘要 极短引用 来源标注。不要用 AI 批量改写原片字幕再伪装成原创。涉及演员肖像、声音克隆、角色形象的时候边界更严格。逐集对比只做文本分析不要无授权使用真实人物形象和声音也不要生成可能误导他人的换脸、配音内容。10.4 后续扩展方向这套流程基础版本跑通后还能继续扩展接入更多标注字段自动统计角色出场时长。用 OCR 识别视频内字幕和音频转写做交叉验证。把结果写入数据库做跨集关联查询。增加定时任务新视频一放进episodes/目录就自动处理。增加“指定集数导出 Markdown 对比稿”的模板减少排版工作量。11. 总结与下一步这篇内容的核心不是某个单一模型而是一条可组装的逐集对比流程FFmpeg 抽音频、faster-whisper 转写、LLM 抽取 JSON 字段、Chroma 做检索、pandas 输出表格。它适合处理大量系列视频也适合从零快速搭出“镰仓VS不死的格罗扎姆”这类对比稿。最值得先跑通的一环是“音频转文本 结构化输出”因为后面的表格、检索、批量任务全部依赖这一步。最容易踩的坑不是模型不够强而是没有统一字段结构就开始批量跑结果输出格式五花八门最后还得人工重排。下一步建议先找 1 集视频按文中脚本跑一遍确认转写质量和 JSON 输出稳定后再把其余集数加入批量队列。最终产出物不是一张简单截图而是带时间戳、带原文来源、可以被查询的对比数据库这样的结论才经得起复核。建议收藏备用后面做系列内容整理时可以直接照这套流程操作。
网站建设高端定制企业官网