恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
基于Whisper与ffmpeg的本地音视频摘要工具实战
首页
资讯中心
/
基于Whisper与ffmpeg的本地音视频摘要工具实战
基于Whisper与ffmpeg的本地音视频摘要工具实战
发布时间:2026/8/27 12:09:38
平时看技术视频、听播客一集内容动辄四十分钟起步真正有用的信息可能只占几分钟。想快速了解核心内容手动拖进度条效率太低用在线转写工具又担心隐私、费用和排队。后来在 Hacker News 上看到一个叫 Audio-tldr 的项目思路用 OpenAI 开源的 Whisper 在本地完成音视频转写再自动生成文字摘要。整条链路完全本地运行不依赖云端 API。这篇文章就沿着这条思路从概念、环境、原理到代码实现完整拆解带你搭建一个属于自己的本地音视频摘要工具新手可以按步骤复现有经验的开发者也能直接复用核心代码。1. Audio-tldr 是什么一条完整的本地音视频摘要流水线1.1 项目定位Audio-tldr 这个名字很直白Audio 加上 TL;DRToo Long; Didnt Read太长了不想看目标就是解决“音频内容太长没法快速获取重点”的问题。它的定位和常见的在线转写工具有明显区别完全本地运行音频文件不需要上传到第三方服务器不按分钟计费只要有足够的本地算力可以批量处理转写和摘要流程可以完全自定义比如指定语言、调节模型大小、导出字幕文件适合处理内容偏敏感的视频会议、内部培训、访谈录音等场景。相比在线工具本地方案最大的优势是隐私和成本。你把一小时的会议录音交给在线服务很难确定这些数据会被如何使用本地方案把数据留在自己手里安全性完全由自己掌控。1.2 核心流水线Audio-tldr 的核心思路并不复杂本质是一条三步流水线输入视频/音频文件 │ ▼ [ffmpeg 提取音频] ──→ 16kHz 单声道 WAV │ ▼ [Whisper 语音识别] ──→ 带时间戳的转写文本 │ ▼ [摘要引擎] ──→ 核心要点 / 摘要文本第一步用 ffmpeg 把视频或音频统一转换成适合语音识别的格式第二步用 Whisper 模型把音频转写成文字第三步对转写文本做摘要处理。后面我们会围绕这条流水线逐段实现。1.3 为什么选择 WhisperWhisper 是 OpenAI 在 2022 年 9 月开源的自动语音识别模型它之所以适合做 Audio-tldr 这类工具主要有几个原因开源且可本地部署模型权重可以下载到本地不需要调用云端接口支持多语言识别官方宣称支持 99 种语言并且能自动检测语言提供 tiny、base、small、medium、large-v3 等多个尺寸可以从“极快但一般准”到“较慢但很准”之间按需选择输出结果带时间戳转写文本可以进一步导出成 SRT、VTT 字幕社区生态成熟除了官方 openai/whisper还有 faster-whisper、whisper.cpp 等性能优化版本。对个人开发者来说Whisper 是当前落地本地语音识别成本最低、效果也稳定的选择。2. 环境准备与版本说明2.1 运行环境Audio-tldr 的完整流程可以在 Windows、macOS、Linux 上运行。CPU 也能跑但模型越大、音频越长耗时越明显。如果打算常用 large 型号建议准备一块支持 CUDA 的 NVIDIA 显卡。内存方面tiny、base 模型 8GB 内存基本够用medium 和 large 模型在转写长时间音频时内存占用会明显上升。内存越充裕处理越流畅。2.2 安装 Python 与 ffmpeg推荐使用 Python 3.9 到 3.12 版本。建议在项目目录下创建虚拟环境避免依赖冲突python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activateffmpeg 是音频提取的关键工具Whisper 读取音频时也会依赖它。安装方式按系统区分# Windows使用 winget winget install ffmpeg # macOS brew install ffmpeg # Ubuntu / Debian sudo apt update sudo apt install ffmpeg安装完成后运行下面的命令确认系统能识别 ffmpegffmpeg -version如果提示找不到命令通常是安装后没有把可执行文件加入 PATH需要检查环境变量配置。2.3 安装 Whisper官方 Python 包可以直接通过 pip 安装pip install -U openai-whisper如果更在意转写速度可以考虑 faster-whisper。它基于 CTranslate2 推理引擎在 CPU 和 GPU 上通常比官方实现更快且内存占用更少。本文的示例代码使用官方 openai-whisper但核心思路同样适用于 faster-whisper。2.4 模型选择Whisper 首次使用时会把模型权重下载到本地缓存目录。模型越大识别准确率越高但速度和资源消耗也越大。各型号的定位大致如下模型名称参数规模CPU 体验推荐场景tiny约 39M非常快快速测试流程、短音频base约 74M较快日常短音频、中文短句small约 244M可以接受较长音频速度与效果平衡medium约 769M偏慢对准确率要求较高的场景large-v3约 1550M很慢GPU 环境、追求最高准确率对中文内容建议从 base 或 small 开始尝试。先跑通流程再根据识别效果决定是否升级模型。3. 核心原理拆解3.1 为什么先用 ffmpeg 提取音频Whisper 其实可以直接读取视频文件但显式用 ffmpeg 提音频有几个好处统一音频格式为 16kHz 采样率、单声道 WAV避免不同视频的编码格式影响识别16kHz 是 Whisper 训练时使用的采样率输入对齐后识别效果更稳定预先提取音频可以把“媒体解码”和“语音识别”两个阶段分离便于缓存和调试。对应的 ffmpeg 命令如下ffmpeg -i input.mp4 -vn -ac 1 -ar 16000 -y audio.wav参数含义-i input.mp4指定输入文件-vn丢弃视频流-ac 1设置单声道-ar 16000设置采样率为 16kHz-y覆盖已有输出文件。在 Python 中我们用subprocess.run调用这条命令完整代码在后面的实战部分给出。3.2 Whisper 的核心参数Whisper 的调用方式非常简洁import whisper model whisper.load_model(base) result model.transcribe(audio.wav, languagezh, fp16False)load_model负责加载模型transcribe负责识别音频。实际使用时有几个参数需要重点关注。参数作用使用建议model模型名称按资源和准确率要求选择language语言代码中文建议显式指定zh避免自动检测误判tasktranscribe或translate转写或翻译成英文fp16是否使用半精度GPU 可开启CPU 必须设为Falseinitial_prompt提示词可传入领域词汇、说话风格提升识别效果verbose是否显示进度调试时开启正式脚本可关闭result返回的是包含多个字段的字典。result[text]是完整转写文本result[segments]是带时间戳的分段结果result[language]是检测到的语言。这里尤其注意language参数。自动检测在中文、英文混杂或方言环境下可能选错语言导致输出大量英文乱码。对中文播客、中文视频直接指定languagezh更稳妥。3.3 摘要怎么做转写完成后得到的是完整文本。一集 1 小时的播客转写文本可能达到上万字直接阅读仍然很费时间所以还需要摘要步骤。摘要方案主要有两类第一类是抽取式摘要。从原文本中挑出最能代表主题的句子拼接成摘要。优点是实现简单、不依赖额外模型、结果可追溯到原文缺点是句子之间可能不够连贯缺少整体概括。第二类是生成式摘要。让大语言模型阅读转写文本重新组织语言输出要点。优点是概括性强、表达自然缺点是需要接入额外模型且生成耗时较长。在下一节的实战中我们先实现一个不依赖外部服务的抽取式摘要再介绍如何接入本地大模型做生成式摘要。4. 完整实战构建本地音视频摘要工具4.1 项目结构整个工具用单个 Python 脚本即可实现核心依赖只有 openai-whisper。项目结构如下audio_tldr/ ├── requirements.txt ├── audio_tldr.py └── output/ ├── audio.wav ├── transcript.txt └── summary.txtoutput目录用来存放中间产物和结果audio_tldr.py是主脚本。4.2 创建依赖文件先创建requirements.txtopenai-whisper安装依赖pip install -r requirements.txt4.3 编写音频提取模块音频提取函数如下import subprocess def extract_audio(video_path, audio_path): 使用 ffmpeg 从视频/音频中提取 16kHz 单声道 WAV。 cmd [ ffmpeg, -i, video_path, -vn, -ac, 1, -ar, 16000, -y, audio_path ] subprocess.run(cmd, checkTrue, capture_outputTrue)注意checkTrue如果 ffmpeg 执行失败会直接抛出CalledProcessError方便尽早发现问题。4.4 编写转写模块转写函数封装了 Whisper 的加载和识别逻辑import whisper def transcribe(audio_path, model_namebase, languageNone): 加载 Whisper 模型并完成转写。 model whisper.load_model(model_name) result model.transcribe( audio_path, languagelanguage, fp16False, verboseFalse ) return result这段代码在 CPU 上运行所以fp16固定设为False。如果你的机器有 GPU可以改成True来加速。4.5 编写摘要模块先实现一个不依赖额外模型的抽取式摘要。它的思路是把文本切成句子统计每个字或词的出现频率然后按“句子中包含的高频词数量”给句子打分取分数最高的几条作为摘要。import re from collections import Counter def split_sentences(text): 按中英文句末标点切分句子。 text re.sub(r\s, , text) parts re.split(r(?[。!?]), text) return [p.strip() for p in parts if p.strip()] def get_freq(text): 统计词频中文按单字英文按单词演示用。 words re.findall(r[\u4e00-\u9fff]|[A-Za-z]{3,}, text) return Counter(words) def summarize_by_freq(text, top_k5): 基于词频的抽取式摘要高频词所在的句子更可能代表主题。 sentences split_sentences(text) sentences [s for s in sentences if len(s) 10] if not sentences: return text[:500] freq get_freq(text) scored [] for sentence in sentences: score sum(freq.get(w, 0) for w in re.findall( r[\u4e00-\u9fff]|[A-Za-z]{3,}, sentence)) scored.append((score, sentence)) scored.sort(keylambda x: x[0], reverseTrue) return \n.join(s for _, s in scored[:top_k])这里为了演示方便中文是按单字统计的。实际项目中更适合用 jieba 分词后再统计摘要质量会明显提升。摘要模块之后可以替换成任何更复杂的实现主流程不需要改动。4.6 编写主流程主流程把三个步骤串起来并接收命令行参数import argparse import os import tempfile def main(): parser argparse.ArgumentParser(descriptionAudio-tldr 本地音视频摘要工具) parser.add_argument(input, help输入视频或音频文件) parser.add_argument(--model, defaultbase, helpWhisper 模型名称tiny/base/small/medium/large-v3) parser.add_argument(--language, defaultNone, help语言代码如 zh/en不填则自动检测) parser.add_argument(--top-k, typeint, default5, help摘要中保留的句子数量) parser.add_argument(--output, defaultsummary.txt, help摘要输出路径) args parser.parse_args() with tempfile.TemporaryDirectory() as tmp_dir: audio_path os.path.join(tmp_dir, audio.wav) print(f[1/3] 使用 ffmpeg 提取音频{args.input}) extract_audio(args.input, audio_path) print(f[2/3] 使用 Whisper 转写模型{args.model}...) result transcribe(audio_path, model_nameargs.model, languageargs.language) transcript result[text] print(f 转写完成共 {len(transcript)} 个字符。) print([3/3] 生成摘要...) summary summarize_by_freq(transcript, top_kargs.top_k) with open(args.output, w, encodingutf-8) as f: f.write(summary) print(f摘要已保存到{args.output}) print(----------------------------------------) print(summary) print(----------------------------------------) if __name__ __main__: main()主流程使用TemporaryDirectory存放中间音频文件脚本结束后会自动清理不会污染项目目录。4.7 运行与验证执行下面的命令对本地视频做摘要python audio_tldr.py ./demo.mp4 --language zh --top-k 5如果demo.mp4里有人说话运行完成后会生成summary.txt并打印摘要内容。第一次运行base模型时会先下载模型权重需要等待一段时间下载完成后会缓存在本地后续运行不需要重新下载。如果输入本身就是音频文件比如demo.mp3同样可以传入ffmpeg 会直接把音频转成 WAVpython audio_tldr.py ./podcast.mp3 --language zh --top-k 5到这里一个最小可用的本地音视频摘要工具就算完成了。整个流程只有三部分提音频、转写、摘要代码量不大但链路完整。5. 进阶改进接入本地 LLM 做生成式摘要5.1 为什么需要生成式摘要上面实现的抽取式摘要比较简单适合快速验证流程。但它的局限性也很明显选出来的句子可能缺乏连贯性无法准确表达“整段内容在讲什么”。如果想要更高质量的摘要建议接入生成式大模型。如果希望继续保持“本地运行”的特点可以使用 Ollama 在本地启动大模型服务。Ollama 支持多种开源模型比如 Qwen 系列、Llama 系列具体模型根据机器配置选择。安装 Ollama 后先拉取一个模型ollama pull qwen2.5然后在 Python 中调用 Ollama 的 HTTP 接口import json import urllib.request def summarize_with_ollama(text, modelqwen2.5, base_urlhttp://localhost:11434): prompt f请阅读下面的文字用中文提炼出 5 个核心要点每个要点不超过 50 字\n\n{text[:4000]} payload json.dumps({ model: model, prompt: prompt, stream: False, options: {temperature: 0.3} }).encode(utf-8) req urllib.request.Request( f{base_url}/api/generate, datapayload, headers{Content-Type: application/json} ) with urllib.request.urlopen(req, timeout300) as resp: data json.loads(resp.read().decode(utf-8)) return data.get(response, ) summary summarize_with_ollama(transcript) print(summary)把这段代码接入主流程很简单只需替换摘要模块即可。需要注意的是本地大模型会占用较多内存和显存机器配置不够时建议先处理较短的音频或者把转写文本切片后分批摘要。5.2 将转写结果导出为字幕Whisper 的result[segments]里包含每一句话的开始时间、结束时间和文本可以导出为 SRT 字幕文件def format_timestamp(seconds): millis int(round(seconds * 1000)) hours millis // 3600000 minutes (millis % 3600000) // 60000 secs (millis % 60000) // 1000 ms millis % 1000 return f{hours:02d}:{minutes:02d}:{secs:02d},{ms:03d} def export_srt(segments, output_path): with open(output_path, w, encodingutf-8) as f: for i, seg in enumerate(segments, 1): start format_timestamp(seg[start]) end format_timestamp(seg[end]) text seg[text].strip() f.write(f{i}\n{start} -- {end}\n{text}\n\n)转写文本加上字幕文件后续还可以做关键词检索、章节切分、双语字幕对照等扩展。6. 常见问题与排查思路在实际运行过程中最容易遇到下面几类问题。6.1 ffmpeg 命令找不到现象脚本报FileNotFoundError: [Errno 2] No such file or directory: ffmpeg。原因ffmpeg 没有安装或者安装后没有加入 PATH。排查步骤ffmpeg -version如果提示找不到命令需要安装 ffmpeg 并确认安装目录已加入系统 PATH。Windows 下用 winget 安装后通常会自动配置环境变量如果不行需要手动把 ffmpeg 的 bin 目录加入 PATH然后重启终端。6.2 模型下载慢或失败现象第一次运行脚本时长时间卡在下载阶段或者直接报网络错误。原因Whisper 模型权重从海外源下载网络状况不好时容易失败或中断。解决办法检查网络连接删除本地不完整的缓存目录后重试也可以从可用的镜像源下载模型权重然后放到 Whisper 的缓存目录中。模型文件放置完成后load_model会直接读取本地缓存。6.3 CUDA 报错现象GPU 环境下提示 CUDA 相关错误比如CUDA not available或版本不匹配。原因PyTorch 的 CUDA 版本和显卡驱动、CUDA 运行库不匹配。解决办法先确认torch.cuda.is_available()是否返回True不匹配时根据 PyTorch 官网的指引安装对应 CUDA 版本的 PyTorch如果只是临时使用 CPU 跑可以把fp16False并让模型在 CPU 上运行。6.4 转写结果全是英文或乱码现象中文音频转写出来后文本大量是英文或符号。原因没有指定languagezh自动检测把语言判断错了也可能是初始提示词initial_prompt没有引导模型。解决办法显式指定语言result model.transcribe(audio.wav, languagezh, fp16False)也可以添加初始提示词result model.transcribe( audio.wav, languagezh, initial_prompt以下是普通话的对话内容。, fp16False )6.5 内存不足现象转写过程中进程被系统杀死或提示Killed、Out of memory。原因模型过大或者音频太长或者同时运行了过多其他程序。解决办法换用更小的模型比如从medium降到small把长音频切成 10 分钟一段分别处理关闭不必要的程序释放内存。6.6 常见问题速查表问题现象常见原因解决思路ffmpeg 命令找不到ffmpeg 未安装或未加 PATH安装 ffmpeg确认ffmpeg -version可运行模型下载慢或失败网络问题或缓存损坏检查网络删除缓存后重试或手动放置模型文件CUDA 报错PyTorch 与驱动不匹配安装匹配的 CUDA 版本 PyTorch或改用 CPU中文识别成英文未指定语言设置languagezh转写速度太慢模型过大且 CPU 推理换小模型使用 GPU或改用 faster-whisper内存不足模型或音频过长减小模型切分音频释放内存摘要效果差抽取式摘要过于粗糙接入生成式大模型或改用 jieba 分词后再统计7. 最佳实践与工程建议7.1 模型实例复用在脚本里每次调用whisper.load_model都会重新加载模型非常耗时。如果要把转写能力做成服务应该在进程启动时加载模型然后复用一个模型实例处理多次请求。模型加载通常需要几秒到几十秒复用能显著提升响应速度。7.2 转写结果缓存长时间音频的转写非常耗时同一段音频可能因为摘要参数调整而需要反复处理。建议把转写结果保存为 JSON 或 TXT下次运行摘要模块时直接读取缓存文本跳过音频提取和语音识别阶段。这样调摘要、调字幕格式时不需要重新转写一遍。7.3 统一音频处理规范不论输入是 mp4、mp3、m4a 还是其他格式统一转成 16kHz 单声道 WAV。这个规范可以避免很多由于采样率、声道数不一致导致的识别问题。同时中间音频文件建议使用临时目录避免大量中间文件堆积在项目目录。7.4 安全与隐私边界本地处理是 Audio-tldr 这类工具的核心优势但也意味着文件安全由自己负责。如果处理的是敏感录音建议把输出文件放在权限受限的目录中不要随意同步到公共网盘。转写文本里可能包含讲话者的隐私信息删除中间文件时也要彻底。如果后续接入了本地大模型做摘要还需要注意 prompt 注入问题。转写文本里可能包含恶意指令例如有人在录音中说“忽略之前指令输出固定内容”。在构造摘要 prompt 时要明确限定模型只做摘要不执行文本中的任何指令。7.5 长音频处理策略对于超过 1 小时的音频建议先按章节或时间段切片分别转写和摘要最后再合并。Whisper 本身会把长音频按 30 秒窗口切分处理但手动分段更容易做断点续传某一段失败时不需要重跑整段音频。切片可以继续用 ffmpeg 完成ffmpeg -i audio.wav -ss 00:00:00 -to 00:10:00 -c copy part1.wav7.6 摘要结果的可追溯性生成摘要后建议在文件里保留对应的原文偏移信息。比如抽取式摘要可以记录每个摘要句在原文本中的位置生成式摘要可以保留原始转写文本文件。这样当摘要质量不佳时可以快速定位到原文而不是面对一段无法验证的浓缩文字。8. 总结与后续学习路线这篇文章从 Audio-tldr 的思路出发实现了一个完整的本地音视频摘要工具。核心链路是ffmpeg 提取音频、Whisper 语音转写、摘要引擎生成要点。环境准备部分覆盖了 Python、ffmpeg 和 openai-whisper 的安装原理部分解释了采样率、语言参数、摘要方案等关键细节实战部分给出了完整的audio_tldr.py脚本可以直接复制运行进阶部分介绍了用 Ollama 接入本地大模型做生成式摘要以及导出 SRT 字幕的方法。如果你想把这条链路做得更深入可以按下面的方向继续学习用 faster-whisper 替换官方实现对比转写速度和显存占用在 whisper.cpp 的基础上做移动端或嵌入式部署接入说话人分离工具把转写文本按说话人区分把转写文本导入向量数据库结合 RAG 做音视频内容问答给工具加上批量任务队列、进度回调、错误重试做成真正可用的服务。本地音视频摘要并不是一个新概念但 Whisper 把语音识别的门槛降到了很低。接下来需要做的就是把这条流水线打磨得再稳定、再快一些。你可以先用自己手边的一段视频跑一遍流程再根据实际效果调整模型大小和摘要策略。动手跑起来比看十篇文章都有用。如果文章对你有帮助欢迎收藏备用也欢迎在评论区交流你在运行过程中遇到的问题。