周末录了一段 107 分钟的音频,先是直接用 MiMo-v2.5-asr 的语音识别转成了文字。
转完结果一看,还有个很实际的需求:想把录音里的说话人识别出来,没自己上手做之前,还真意识不到这个细节。
下面说说怎么从调用 MiMo 模型,避免速率限制,到换成全本地的免费方案,再加上自动标注说话人的过程。
查官方文档发现 mimo-v2.5-asr 的上下文窗口是 8000 token。
按测试数据估算,1 秒音频约产生 14 个 token,8000 token 大约对应 9.5 分钟,单次请求最多处理约 10 分钟音频。
超过这个长度需要分片。
打开WorkBuddy, 让AI 写了一个分片处理模块,逻辑是:读取音频时长,超过 7 分钟就按时长切开,逐片调用 API,最后拼接结果。
用一个 10 分钟的音频测试,自动分成 2 个 5 分钟分片,分别识别后合并,结果正确。
分片方案遇到新问题。
107 分钟的 m4a 文件切片后逐个调用,API 返回 429:
429: Too many requestsmimo-v2.5-asr 的限制是 RPM=100(每分钟 100 次请求),遇到官方限流了。
调整完速率后,按AI给的脚本执行命令正确执行完。
为什么没有让AI帮我执行?因为让AI帮我执行(Mac 系统),它调用Bash 命令行工具,会遇到60秒超时的问题,从而让AI误以为是代码问题,反复改代码。
这是在Mimo-v2.5-pro 出现的情况,没试过别的大模型会不会避免这个超时问题。
打开转录好的文本后,发现一个问题:
是否可以区分音频文件中,根据声纹辨别音频文件中每个人说的话,并在转换成文字后标注。
需求拆成两步:说话人分离(谁在什么时候说话)和语音识别(把语音转成文字)。

我用的是Mac M1 ,于是采用了方案二。
说话人分离用 pyannote.audio,语音识别用 OpenAI Whisper,都是开源模型,本地运行。
流程:
m4a 音频
↓ ffmpeg
wav 音频 (16kHz, 单声道)
↓ pyannote.audio (分片 + 重叠窗口)
说话人分离结果 (tsv: 起始时间, 结束时间, 说话人)
↓ Whisper (逐片段转录)
带说话人标注的文本本地环境:Apple M1,16GB 内存,miniconda3 里有 PyTorch 2.8.0,支持 MPS 加速。
安装 pyannote.audio 后报错:
ModuleNotFoundError: No module named 'audioop'Python 3.13 移除了 audioop 模块。
装了 audioop-lts 兼容包又遇到代码签名问题,最后在 miniconda3 的 Python 3.12 环境里装好了。
全程AI干活,我监督,下指令。
pyannote.audio 的预训练模型托管在 Hugging Face Hub 上,需要注册账号、创建 Access Token。
光有 token 还不够。
pyannote 的模型是 gated repo,需要先去页面上点击"Agree and access repository"接受使用条件。
speaker-diarization-3.1 和 speaker-diarization-community-1 都要授权。
注意!Hugging Face 在国内访问不稳定,设置了本地代理才好下载。
模型加载成功,处理音频时因为 pyannote.audio 4.0 默认用 torchcodec 解码音频,但 torchcodec 和 PyTorch 2.8.0 不兼容。
装了 torchcodec 0.7.0,还是报 FFmpeg 库找不到的错。
解决方案:先用 ffmpeg 把 m4a 转成 wav,再用 scipy 直接读取 wav 文件,构造 pyannote 需要的输入格式:
import scipy.io.wavfile as wavfile
import torch
sample_rate, data = wavfile.read(audio_path)
data = data.astype(np.float32) / 32768.0
waveform = torch.from_numpy(data).float().unsqueeze(0)
diarization = pipeline({'waveform': waveform, 'sample_rate': sample_rate})完全不依赖 torchcodec。
直接处理整个 107 分钟音频,进程被 kill 了。
196MB 的 wav 文件加载到内存,加上模型推理的开销,16GB 内存扛不住。
改成分片处理。
分片带来的问题是:每个分片里的说话人标签独立,第一个分片的 SPEAKER_00 和第二个分片的 SPEAKER_00 可能不是同一个人。
导致程序跑完后,明明只有3个人说话的音频,它给识别出了5个人。
用重叠窗口解决:每段 300 秒,相邻段重叠 30 秒。
pyannote.audio 在重叠区域观察到相同的说话人,有助于保持标签一致性。
写了一个支持断点续传的脚本,手动执行:
export HF_TOKEN=hf_xxxxx
export https_proxy=http://127.0.0.1:7890
export http_proxy=http://127.0.0.1:7890
~/miniconda3/bin/python run_diarization_v2.py 6_11_xu_huang.m4a跑了大约 40 分钟,结果:
说话人分离完成!
总片段数: 443
说话人数量: 3
说话人统计:
SPEAKER_00: 190 个片段, 3026.3 秒 (50.4 分钟)
SPEAKER_01: 188 个片段, 2475.7 秒 (41.3 分钟)
SPEAKER_02: 65 个片段, 510.6 秒 (8.5 分钟)3 个说话人,和实际一致。
说话人分离的结果是一个 tsv 文件,每行是 起始时间\t结束时间\t说话人。
接下来用 Whisper 逐片段转录。
流程:
执行:
~/miniconda3/bin/python run_transcription.py 6_11_xu_huang.m4a \
--segments 6_11_xu_huang_segments_v2.txt \
--whisper-model medium \
-o 6_11_xu_huang_transcript.txt输出格式:
[00:00.01 - 00:05.23] SPEAKER_00: 你好,今天天气不错
[00:05.23 - 00:12.45] SPEAKER_01: 谢谢,确实挺好的
[00:12.45 - 00:18.67] SPEAKER_00: 不客气问题 | 原因 | 解决方案 |
|---|---|---|
audioop 缺失 | Python 3.13 移除了该模块 | 用 Python 3.12 环境 |
torchcodec 不兼容 | 和 PyTorch 2.8.0 版本冲突 | 用 scipy 读 wav 绕过 |
Hugging Face 超时 | 国内访问不稳定 | 设置代理 |
内存不足 | 196MB wav 文件太大 | 分段处理 |
说话人标签不一致 | 分片处理导致标签独立 | 重叠窗口 + 断点续传 |
整个流程在 Apple M1 上跑完大约 1-2 小时,完全本地完成,笔记本烧得发热。
之前种草了录音笔,看了一圈之后,感觉市面上的产品,卖点就是和硬件配套的语音转文字和内容的AI化处理。
咱是干啥的,手里有现成的AI工具,用手机录下来,传到云端,再加上这套代码,全免费,不香吗?
写完的时候,发现微软发布了一款通用的语音识别模型 VibeVoice ASR,单次转录可处理长达 60 分钟的连续音频,并能够可靠地生成丰富、结构化的输出,清晰地记录说话者是谁以及其说话时间。
如果想反转过来,想实现文字转语音的,可以看这篇:开源语音 AI:3 秒克隆声音,支持 9 种语言 — Voxtral TTS。
你会选录音笔还是会用AI自己开发?
欢迎评论区留言。
推荐阅读:
国产开源大模型 GLM-5.2 发布,能力又有突破还能免费用
Loop Engineering 如何使用AI编程智能体:构建可循环系统
40万播放的 Anthropic 价值$300的官方提示词课
Claude Fable 5 系统提示词曝光:Anthropic 为适应最强大模型做了哪些改动?
比 Superpowers 更贴近AI编程工程实践的51 个 Agent 和 35 个技能
给 AI 装上真实浏览器:camofox-browser 实战
没人整理过的 DeepSeek 进化史:25篇论文里的技术蜕变