原始文案摘要

我的项目有一个功能是利用AI对视频内容分析并进行概括,当然我只是做的是文本概括,所以我需要用ffmepg分离出视频的音频,音频要用wav格式,然后我找到一款可以自己部署的音频转字幕文本的项目和模型,我不想调api,AI分析才要调大模型,所以我就找到了也就是这个whisper,不过我看原本的项目是Python的,不利于生成环境和集成在我的Java项目,所以我又了解了一番有人把他改成了一个更精简的c++版 whisper.cpp,因为我的是用笔记本部署项目,我是轻薄本没有独立GPU,这个版本对CPU调用能力更强,我查找到了几种结合在我的项目的方法,第一种就是利用编译好的程序利用命令运行,第二种是利用dll文件,用java调用c++库的技术去实现,这种方法性能更好,但因为我的项目还没到抠性能的地步,我最后采用了第一种方法,我的ffmepg也是调指令的方法实现的。我下载的是一个最小的模型包,~488 MB,这个模型我实验下来发现,中文识别率还是可以的,但是对英文特别是技术英文的缩写,基本上是一窍不通。

正文

前言

事情是这样的。最近在做一个项目,需要对视频内容做分析概括。说白了就是:用户上传一个视频,后端提取视频里的文字(字幕),然后扔给大模型去总结。

这里有个关键环节:怎么把视频里的语音转成文字

调API当然是最简单的,但一来要钱,二来有网络依赖,三来数据还得上传到别人服务器。思来想去,还是本地部署一个语音识别模型靠谱。

于是就有了这篇文章——记录我作为一个Java后端,怎么用C++版本的whisper给视频加字幕,以及踩过的坑。

一、需求拆解

先理一下整个流程:

  1. 用户上传视频

  2. 后端用ffmpeg分离出音频

  3. 音频转成wav格式(whisper要吃wav)

  4. 用whisper把音频转成字幕文本

  5. 把文本扔给大模型做分析

今天主要说第2-4步,核心就是:怎么在Java项目里调用whisper

二、选型:为什么是whisper.cpp

原始项目:openai/whisper

OpenAI官方出的whisper,Python写的,效果确实好。但问题也明显:

  • Python环境部署麻烦(虚拟环境、依赖包)

  • 内存占用大

  • 在无GPU的机器上跑起来吃力

  • 和Java项目集成需要起Python服务

转机:whisper.cpp

有个大佬把whisper用C++重写了,就是 ggerganov/whisper.cpp

优点:

  • 零依赖:编译出来就是一个可执行文件

  • CPU优化好:在无GPU的轻薄本上也能跑

  • 内存占用低:官方说比Python版省很多

  • 集成简单:Java直接调命令行,或者用JNI调dll

缺点:

  • 配置编译稍微有点门槛

  • 英文缩写的识别确实差点意思(后面细说)

三、部署过程(参考掘金那篇文章)

我在掘金看到一篇教程:零依赖、高效率的语音转文字c++版 whisper.cpp,基本就是按这个来的。

1. 下载whisper.cpp

bash

git clone https://github.com/ggerganov/whisper.cpp
cd whisper.cpp

2. 编译

bash

# 先下载模型(我选的是最小的tiny模型)
bash ./models/download-ggml-model.sh tiny

# 编译主程序
make

编译完会生成一个 main 可执行文件,这就是核心了。

3. 模型选择

whisper有多个模型,从tiny到large,体积和准确率递增。我用的是tiny模型,488MB左右。

模型 大小 中文识别 速度 英文缩写识别
tiny 488MB 还行
base 1.4GB 不错 中等 一般
small 4.6GB 较好

我最后选tiny,因为项目对速度有要求,而且主要识别中文。但后面发现一个问题:英文技术缩写基本识别不出来

比如"API"会变成"阿皮"或"a p i","CPU"变成"西皮优"。这个后面再说。

四、集成到Java项目:我选的是命令行方案

方案一:命令行调用(我用的)

java

ProcessBuilder pb = new ProcessBuilder(
    "/path/to/whisper.cpp/main",
    "-m", "/path/to/models/ggml-tiny.bin",
    "-f", "/path/to/audio.wav",
    "-osrt", // 输出srt字幕文件
    "-of", "/path/to/output"
);
Process process = pb.start();
int exitCode = process.waitFor();

优点:实现简单,几分钟搞定。
缺点:每次都要启动进程,有额外开销。

方案二:JNI调用dll(没采用)

把whisper.cpp编译成dll,用JNI调用。性能更好,但需要写C++胶水代码,我懒得折腾。

方案三:起个Python服务(没采用)

用Flask包装官方whisper,Java调HTTP接口。简单但多了网络开销,还得维护Python环境。

目前暂时用方案二顶着,等需求更强烈了再换大模型。

五、ffmpeg处理音频

音频处理也是调命令行:

java

ProcessBuilder pb = new ProcessBuilder(
    "ffmpeg",
    "-i", videoPath,
    "-ar", "16000", // 采样率16000,whisper推荐
    "-ac", "1",     // 单声道
    "-c:a", "pcm_s16le", // wav格式
    audioPath
);

这一步没啥坑,ffmpeg稳定得很。

六、遇到的问题和解决

1. 英文缩写识别问题(未完全解决)

tiny模型对英文技术词汇识别确实差。试了几个方案:

方案一:换大模型
换base模型好一些,但速度慢了,体积也大了。

方案二:后处理替换
在Java里做正则替换,把常见的"阿皮"替换回"API"。这个可以解决部分问题,但不可能穷举所有缩写。

方案三:热词增强(whisper.cpp支持)
whisper.cpp支持用 --prompt 参数提示,效果有限。

目前暂时用方案二顶着,等需求更强烈了再换大模型。

2. 启动速度

每次调用都要加载模型,488MB加载到内存要一两秒。如果频繁调用,可以考虑:

  • 把main做成常驻服务

  • 用方案二的dll方式

但我的场景是用户上传视频,频率不高,所以无所谓。

3. 内存占用

tiny模型运行时占用内存约500MB,轻薄本8GB内存,完全扛得住。large模型就够呛了。

七、最终效果

整套流程跑下来:

  1. 上传一个10分钟的视频

  2. ffmpeg处理音频(几秒)

  3. whisper转字幕(small模型约3-5分钟)

  4. 得到srt字幕文件

  5. 扔给大模型分析

中文识别率80%左右,英文缩写得靠后处理。对于内部项目来说,够用了。

八、总结

步骤 工具 耗时 备注
音频分离 ffmpeg 几秒 稳定
语音转文字 whisper.cpp 3-5分钟/10分钟视频 small模型
文本后处理 Java正则 瞬间 补英文缩写

一点建议

  • 如果是Java项目,命令行调用whisper.cpp是最快的集成方式

  • 模型别贪大,够用就行(我的教训)

  • 英文缩写识别不行,要么换大模型,要么后处理

  • 轻薄本无压力,内存占用可控

成本统计

项目 价格 备注
whisper.cpp 0元 开源
模型文件 0元 免费下载
ffmpeg 0元 开源
总计 0元 白嫖真香

最后问一句:你的项目也需要本地语音识别吗?用的什么方案?评论区聊聊。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐