项目已开源到 GitHub,项目地址:HiMeditator/auto-captionhttps://github.com/HiMeditator/auto-caption
软件下载(Windows平台):Releases · HiMeditator/auto-captionhttps://github.com/HiMeditator/auto-caption/releases
你是否遇到过看外语视频却没有字幕的情况,或者环境嘈杂需要实时字幕来获取信息。这时候一个能实时将系统音频转换为字幕和翻译并显示的软件就能派上用场了。下面就介绍一下我最近开发的一个实时字幕软件。
项目简介

Auto Caption 是一个跨平台的字幕显示软件,能够实时获取系统音频输入(录音)或输出(播放声音)的流式数据,并调用音频转文字的模型生成对应音频的字幕。软件提供的默认字幕引擎(使用阿里云 Gummy 模型)支持九种语言(中英日韩德法俄西意)的识别与翻译。目前软件提供的自带字幕引擎使用了阿里云的模型服务,所以要使用该字幕引擎需要获取阿里云的 API KEY。
目前软件默认字幕引擎只有在 Windows 平台下才拥有完整功能。在 Linux 平台下只能生成音频输入(麦克风)的字幕,还不支持音频输出(播放声音)的字幕生成。
我还为项目制作了一个视频,想了解项目的同学可以去看看:
开源字幕软件Auto Caption:项目介绍与展示,捕捉音频秒变文字,打造你的专属字幕系统https://www.bilibili.com/video/BV1DCKiznENJ
整个项目可以分为四个部分:前端、后端、客户端集成和字幕引擎。

前端开发
通过 Electron 框架,可以使用 Web 前端开发的技术栈来开发桌面软件。我使用 Vue3 来开发该软件的用户界面,这部分开发和 Web 前端开发差不多,唯一不同的就是用 IPC 和后端通信。这部分 Electron 提供了很好的封装,直接调方法就可以了。
前端的主要功能就是提供字幕引擎和字幕样式的管理界面、提供字幕记录的展示,以及提供另一个实时字幕显示的窗口。

另一个问题就是该软件需要两个不同的窗口,那前端是否要为两个窗口分别写各种的前端项目呢?我使用路由(Vue Router)来载入不同的窗口,这样就只需要一个前端项目就可以表示两个窗口。需要注意的是,打开的两个窗口处于不同的运行环境,因此它们的数据是不互通的,需要通过后端来交换数据。
后端开发
后端使用 Node.js 开发,主要用于管理字幕引擎和字幕样式的设置以及字幕记录。要实现系统音频的实时获取和字幕生成,使用 Node.js 会非常难实现,所以我把那部分剥离了出去,使用其他技术进行单独开发,那部分也被称为字幕引擎。因此后端还需要实现字幕引擎的调用,我使用的是 child_process 模块下的 spawn 方法来调用字幕引擎。
客户端集成
项目使用 Electron 框架开发。Electron 是一个用于构建跨平台桌面应用程序的开源框架。它结合了 Chromium 渲染引擎和 Node.js 运行时环境,允许开发者使用前端技术 + Node.js 来创建原生的应用程序。而且通过Electron,可以一次性编写代码,然后在多个操作系统上运行,包括Windows、macOS和Linux。
选择 Electron 开发的原因主要就是对我来说学习成本较小,因为我之前主要在做前端开发和 VS Code 插件开发,对前端和 Node.js 都有了解,学习使用 Electron 开发桌面软件就能很快入门。Electron 开发的缺点是每个应用都得打包自己的 Chromium 和 Node.js 副本,因此开发的桌面软件占用空间较大,不太适合开发小工具。
项目开发使用了 Electron Vite 作为构建工具,通过 Electron Vite 可以快速生成初始项目模板,主进程和渲染进行的通信接口也进行了很好的封装。Electron Vite 提供的便捷可以让我更专注于项目的开发而不是环境的配置。
字幕引擎开发
所谓的字幕引擎实际上是一个子程序,它会实时获取系统音频输入(录音)或输出(播放声音)的流式数据,并调用音频转文字的模型生成对应音频的字幕。生成的字幕转换为 JSON 格式的字符串数据,并通过 IPC 传递给主程序。主程序读取字幕引擎的数据,处理后显示在窗口上。
字幕引擎的设计是模块化的,因此如果了解了字幕引擎的工作原理和数据传递规范,其他开发者也可以开发自定义的字幕引擎。字幕引擎部分我写了一个文档介绍其工作原理和数据规范,感兴趣的开发者可以去看看,在项目 GitHub 仓库的 assets 文件夹下。

下面说说我自己开发的字幕引擎。要开发字幕引擎,首先就是系统音频数据流的获取。要获取麦克风的输入音频比较容易,很多语言都有对应的库。但是要获取系统音频的输出流就比较麻烦了,这部分我查了很多资料,没有找到合适的跨平台解决方案。
最后我找到了一个适合 Windows 的 Python 库 PyAudioWPatch,这个库允许使用 WASAPI 设备作为环回使用 PyAudio。PyAudio 是 Python 中一个跨平台的音频库,可以获取系统录音。而 PyAudio 使得在 Windows 平台获取系统音频输出也成为了可能。在 Linux 平台我还没有找到类似的库,加上我现在配置的 Linux 虚拟机在开发字幕引擎时遇到了问题,因此该项目的字幕引擎在 Linux 上功能还不完整。

获取到系统音频流后还可能需要对系统音频流进行处理。我使用的阿里云 Gummy 模型只能识别单通道的音频流,但我获取的是双通道的音频流。因此刚开始模型输出的全是和原文不相关毫无逻辑的内容,后面摸索了很久我才发现问题。我使用了 NumPy 库来进行音频流的通道数转换。代码如下:
def mergeStreamChannels(data, channels):"""将当前多通道流数据合并为单通道流数据Args:data: 多通道数据channels: 通道数Returns:mono_data_bytes: 单通道数据"""# (length * channels,)data_np = np.frombuffer(data, dtype=np.int16)# (length, channels)data_np_r = data_np.reshape(-1, channels)# (length,)mono_data = np.mean(data_np_r.astype(np.float32), axis=1)mono_data = mono_data.astype(np.int16)mono_data_bytes = mono_data.tobytes()return mono_data_bytes
另一个问题是每次读取的数据块的大小。所谓的音频流事实上是一个个被切分成的音频数据块。切分的音频块不宜过大或过小,经过我的尝试,我编写的字幕引擎将音频块切分为 50ms 每块,识别效果比较好。
得到了处理好的音频流后就是模型调用了,这部分参考使用的模型的接口文档即可。在编写完整的字幕引擎前可以先在 Jupyter Notebook 中编写一个简单的原型,确保方案可行。最后将模型返回的字幕和翻译结果按接口规范,包装为 JSON 格式的字符串,通过 IPC 传递给调用程序。
开发的 Python 程序通过命令行参数获取字幕配置,在我的程序有三个命令行参数,分别表示:源语言、翻译语言、音频类型(如下图)。开发完成后,使用 PyInstaller 将该 Python 程序打包为可执行文件,确保在不同用户电脑上都可直接运行,这样一个字幕引擎就做好了。

后续计划
这个项目目前初步具有了实用价值,但是还有很大的改进空间。目前的改进计划如下:
- 添加更多自带字幕引擎。目前的字幕引擎只有 Gummy,而要使用该引擎需要申请阿里云百炼平台的API KEY,对于普通用户来说比较麻烦。之后考虑添加更多方便使用的字幕引擎,尤其是可以直接本地部署的模型。
- 添加多语言支持。目前软件只支持中文,可以考虑添加英语和日语支持。
- 添加暗色主题,对于习惯使用暗色主题的用户友好。
- 优化页面样式。