所有项目

2024.10 - 2025.03 / 核心全栈开发

离线语音转录系统

面向本地音频转录场景的 Web 应用,支持转写、热词配置、任务追踪、文本优化与 DOCX 导出。

ReactFastAPICeleryRedisSQLiteFunASRfaster-whisperOllama
离线语音转录系统 预览

背景与约束

部分会议录音与校内音频数据不适合上传至在线服务,且使用环境可能没有稳定网络,因此需要开发可在本地运行的语音转录系统,支持长音频与会议录音的转写、热词配置、任务追踪、文本优化及 DOCX 导出。部署目标是一般笔记本电脑,GPU 显存与整体算力有限,无法直接使用大型模型处理完整长音频,因此选用更适合本地部署的小型 ASR 与 3B 级语言模型。

系统架构

flowchart LR
  UI[前端\nReact / TypeScript] --> API[FastAPI\n上传、任务、导出]
  API <--> DB[(SQLite\n任务与文件数据)]
  API --> Queue[(Redis\nCelery broker)]
  Queue --> ASR[ASR worker]
  ASR --> DB
  ASR -->|提交文本优化任务| Queue
  Queue --> Text[文本优化 worker]
  Text -->|调用| Ollama[Ollama service\n本地 3B LLM]
  Text --> DB

后端以 FastAPI 提供文件上传、任务查询、重试与 DOCX 导出 API,并使用 SQLite 保存文件、任务状态、原始结果、优化结果、热词及说话者信息。Redis 作为 Celery broker 接收任务,再由 ASR worker 执行初步转录。ASR 完成后会回写结果并提交文本优化任务,文本优化 worker 再调用 Ollama 上的本地 3B 模型;前端通过 API 查询每个阶段的状态与结果。上图只描述任务调度与数据流;音频前处理、模型选择和初步分段的细节如下。

ASR pipeline

flowchart LR
  Input[音频 / 视频] --> Pre[ffmpeg 解码、重采样\nTorch 加载 waveform]

  Pre -->|中文| VAD[FSMN-VAD\n切段]
  VAD --> Mode{使用场景}
  Mode -->|会议| PF[Paraformer]
  Mode -->|单人语音| SV[SenseVoice]

  Pre -->|法语| WH[faster-whisper]

  PF --> Punc[CT-Punc]
  Punc --> Post[初步清理 + 分段]
  SV --> Post
  WH --> Post

  Post --> Next[送入文本优化任务]

前处理将多种音频 / 视频格式经 ffmpeg 解码、重采样为统一格式,再由 torchaudio 加载 waveform。中文路径接著使用 FSMN-VAD 进行语音端点检测,依静音切段并限制单段最长 30 秒。转录模型无法稳定承受过长输入,直接处理长音频容易占满 GPU 显存并造成 OOM;VAD 因此同时减少无声计算,也将推理控制在可预期的显存范围。

模型选择经过前期测试,依语言与使用场景分流:中文会议使用 Paraformer,并接 CT-Punc 补全标点与说话者模型;单人语音使用 SenseVoice;中法学院有法语转录需求,因此法语使用 faster-whisper。服务层再将各模型的输出统一为包含文本与时间信息的 sentence blocks,让前端、文本优化与 DOCX 导出使用同一份数据结构。

会议转录详情,按发言人与时间码呈现多段逐字稿,并可切换 AI 优化结果

文本后处理

初步清理后才进行段落划分。切分不只受最大长度限制,还需要保留说话者边界,并优先选择句末标点和自然语义停顿作为切点,避免将一句话或一段发言从中间截断。本地部署受限于算力,因此文本后处理通过 Ollama 运行 3B 级语言模型;每个文本块会连同前文上下文套入 prompt,要求模型校正错字与同音字、补足标点并输出可读段落。原始结果和优化结果分开保存,保留回溯与重试空间。

性能分析与优化

性能分析从一个反常现象开始:通过 top 观察长音频转录过程时,单个 CPU 核心持续占满 100%,但 GPU 推理本应是主要耗时环节。这说明 GPU 在等待一段串行的 CPU 前处理,而不是单纯受限于模型推理速度。

接著以 cProfile 对固定音频和相同配置采样,分别查看累积耗时与函数自身耗时。结果定位到 VAD 的 ComputeDecibel:它以 Python 循环逐帧切片,反覆执行张量平方、求和与对数运算,将大量时间耗在 CPU 前处理,拖慢后续 GPU 推理。

优化将逐帧循环改为 NumPy 批量索引与向量化计算,一次建立所有 frame、计算能量与分贝值,再回写结果。这减少了 Python 解释器与小型张量操作的开销,并将数值运算交由底层原生实现,以利用 CPU 的向量化 / SIMD 能力。改动后以相同音频、模型与参数重新执行 cProfile,比较 ComputeDecibel 的耗时和端到端转录时间,确认收益来自 VAD 前处理而非测试条件差异。相关改进已提交并合并为 FunASR PR #2174