掘金 人工智能 4小时前
用 Tauri + FFmpeg + Whisper.cpp 从零打造本地字幕生成器
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文作者分享了如何使用Tauri、Rust、FFmpeg和Whisper.cpp构建一个名为SubGen的字幕生成工具。该工具能够一键将视频转换为SRT字幕文件。文章详细介绍了项目架构设计,解释了为何选择Tauri而非Electron,并阐述了FFmpeg在音频提取和格式统一方面的作用,以及Whisper.cpp在离线语音识别中的优势,特别是其CPU运行能力。文章还展示了代码结构和前后端交互方式,并分享了使用中的良好体验和对未来的展望,如支持批量处理和GPU加速。

💡 **Tauri框架的优势**:相比Electron,Tauri利用Rust作为后端,前端可使用React等Web技术,显著减小了打包体积(十几MB),并实现了跨平台支持(Windows/macOS/Linux),同时方便Rust调用本地二进制文件,为开发桌面应用提供了高效轻量的解决方案。

🎵 **FFmpeg的音频处理能力**:FFmpeg作为强大的音视频处理工具,在此项目中被用于从视频文件中提取音频,并将其统一为16kHz单声道WAV格式,以适配Whisper.cpp的输入要求,这一过程通过简单的Rust命令行调用即可完成。

💬 **Whisper.cpp的离线语音识别**:Whisper.cpp提供了轻量级的离线语音识别方案,无需额外依赖,且支持CPU运行,即使是大型模型也能在普通硬件上获得不错的识别效果。通过命令行调用,即可将音频文件转换为SRT字幕,支持中文等多种语言。

🏗️ **项目架构与流程**:SubGen采用了分层架构,前端(React+TypeScript)负责用户界面交互,通过Tauri的invoke API调用Rust后端。Rust后端则负责协调FFmpeg提取音频和Whisper.cpp进行语音识别,最终生成SRT文件,实现了“拖入视频、等待片刻、生成字幕”的流畅用户体验。

🚀 **实际使用体验与未来展望**:作者认为Tauri框架非常适合此类底层调用任务,FFmpeg和Whisper.cpp的组合提供了高效且准确的字幕生成能力,且无需联网。未来计划增加批量处理、字幕编辑功能以及探索GPU加速以进一步提升性能。

背景:

最近开始尝试做自媒体,录点视频。刚开始就遇到了字幕的问题,于是想先搞个字幕生成工具(为了这点醋才包的这顿饺子😄):SubGen

这个工具用 Tauri + Rust 做外壳,把 FFmpegWhisper.cpp 集成进去,能一键把视频转成 SRT 字幕
这篇文章记录下笔者做这个工具的过程,也分享下用到的核心组件和代码结构。


架构设计

SubGen 采用分层架构,核心组件的交互关系如下:

┌─────────────┐        ┌──────────────┐│   React UI  │        │   Rust Core  ││ (TypeScript)│ <----> │  (Tauri API) │└─────────────┘        └─────┬────────┘                              │                ┌─────────────┴───────────────┐                │                             │           ┌────▼────┐                   ┌────▼────┐           │ FFmpeg  │                   │Whisper  │           │ 提取音频 │                   │ 离线识别 │           └─────────┘                   └─────────┘

为什么用 Tauri?

最开始笔者也考虑过 Electron,但它打包太大了(动辄 100MB 起步),而且资源占用高。后来发现 Tauri,它用 Rust 做后端,前端还是用 React 或者任意 Web 技术,这样:

笔者主要是用 React + TypeScript 写了一个简单的 UI,用户选视频、点按钮,剩下的活就交给 Rust。


FFmpeg:用它来“扒”音频

FFmpeg 是老牌的音视频处理工具了,笔者直接内置了一个编译好的 ffmpeg.exe/ffmpeg 到资源目录,调用它来:

    从视频里抽出音频。统一格式(16kHz,单声道 WAV),让 Whisper 可以直接处理。

Rust 这边的调用很简单:

use std::process::Command;Command::new("resources/ffmpeg")    .args(["-i", &video_path, "-ar", "16000", "-ac", "1", "audio.wav"])    .status()    .expect("FFmpeg 执行失败");

这样一行命令就能把视频转成标准 WAV。


Whisper.cpp:核心的离线识别

笔者选的是 Whisper.cpp,因为它比 Python 版 Whisper 更轻量,直接编译一个 whisper-cli 就能用,不需要装乱七八糟的依赖。

更重要的一点是支持CPU运行,默认4个线程,即使用 ggml-large-v3 也可以跑出来结果,只是稍微慢点。这对于没有好的显卡的童鞋很有用!

调用命令大概是这样:

whisper-cli -m ggml-small.bin -f audio.wav -osrt -otxt

最后会输出一个 output.srt,直接能用。

Rust 里调用也是 Command::new() 一把梭:

Command::new("resources/whisper-cli")    .args(["-m", "resources/models/ggml-small.bin", "-f", "audio.wav", "-l", "zh", "--output-srt"])    .status()    .expect("Whisper 执行失败");

代码结构和流程

笔者的项目大概是这样分层的:

subgen/├── src/                     # 前端 React + TypeScript│   └── main.tsx             # UI入口├── src-tauri/               # Tauri + Rust│   ├── commands.rs          # Rust命令逻辑│   ├── resources/           # ffmpeg、whisper二进制、模型文件│   └── main.rs              # 程序入口

前端用 @tauri-apps/apiinvoke 调 Rust:

import { invoke } from '@tauri-apps/api';async function handleGenerate(videoPath: string) {  const result = await invoke<string>('extract_subtitles', { videoPath });  console.log('字幕生成完成:', result);}

Rust 后端的核心命令:

#[tauri::command]fn extract_subtitles(video_path: String) -> Result<String, String> {    // 1. 调 FFmpeg    // 2. 调 Whisper.cpp    // 3. 返回 SRT 路径    Ok("output.srt".to_string())}

用下来的感受

整个工具现在已经能做到“拖进视频 → 等几十秒 → 出字幕”这种体验了。
几个感受:


后续想做的事


截图

主界面:

生成的 SRT:


如果你也想做个自己的字幕工具,可以直接参考 SubGen 的架构,自己改改就能用。

代码已开源:github.com/byteroycai/…

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Tauri Rust FFmpeg Whisper.cpp 字幕生成
相关文章