简介
AssemblyAI 的 speaker_labels=True 开关加自动说话人分离 —— 转录拆成 utterance,每个标 Speaker A / Speaker B / Speaker C,不用注册或已知嗓音库。单声道或立体声都行,2-10 个说话人稳定。适合会议转录、播客分离、多方通话分析、证人访谈索引。任何 AssemblyAI 能转的音频 —— 文件 URL、上传、实时 WebSocket。装机时间 1 分钟(加这一个 flag)。
基础分离
import assemblyai as aai
aai.settings.api_key = ASSEMBLYAI_KEY
config = aai.TranscriptionConfig(
speaker_labels=True,
speakers_expected=4, # 可选提示;说话人间有静音时帮忙
)
transcript = aai.Transcriber(config=config).transcribe("meeting.mp3")
for u in transcript.utterances:
print(f"{u.start//1000:>5}s Speaker {u.speaker}: {u.text}")输出结构
0s Speaker A: 欢迎参加 5 月产品评审。
8s Speaker B: 谢谢。我来共享屏幕。
14s Speaker A: 好的,开始吧。
16s Speaker C: 开始前我们能定一下议程吗?
22s Speaker B: 行 —— 我想过 Q2 发布,然后讲 open 问题。把 Speaker 字母映射到真名
第一遍结束后说话人标签是匿名 A/B/C。映射到人靠:
- 手动标注 —— UI 给每个说话人 30 秒片段,问用户「这是谁?」
- 嗓音注册 —— 已知重复出现的呼叫者,先算 embedding,新转录匹配。用单独的库(pyannote / NVIDIA NeMo)因为 AssemblyAI 不暴露 embedding。
- 基于上下文 —— 把前 60 秒带与会者名单喂给 Claude:「每个 speaker 可能是谁?」
def map_speakers(transcript, attendees: list[str]) -> dict[str, str]:
sample = "\n".join(f"Speaker {u.speaker}: {u.text}" for u in transcript.utterances[:8])
prompt = f"与会者:{', '.join(attendees)}。\n对话开头:\n{sample}\n返回 JSON:{{'A': name, 'B': name, ...}}"
# ... 用 prompt 调 Claude ...
return {"A": "Jane", "B": "Bob", "C": "Carlos"}提高准确度的 tip
- 更高信噪比 —— 干净麦克风让分离提升 5-10 个百分点
- 避免大量重叠 —— 重叠说话最难;AssemblyAI 处理 1-2 秒重叠,>3 秒退化
speakers_expected—— 知道人数就传;模型当先验用- 每声道一人 —— 立体声每声道一人,改设
dual_channel=True;声道即标签,准确度跳到 ~99%
实时分离?
实时 WebSocket 流式 2026 年不支持 speaker labels —— 只批量转录支持。实时说话人 ID 用立体声(每人一支麦克风)+ dual_channel=True。
FAQ
Q: 电话音频分离效果如何?
A: 支持 8kHz 音频。质量比录音棚略降。Twilio 录的双方通话设 dual_channel=True(来电左声道、接听右声道)—— 准确度跳到 ~99%。
Q: 非英语音频准吗? A: 分离跟语言无关 —— 用声学特征不是词。法语 / 普通话 / 阿拉伯语效果同样。底层转录的 WER 因语言而异,但说话人边界不变。
Q: 能注册特定已知说话人吗? A: 不能直接通过 AssemblyAI。变通:跑 AssemblyAI 拿匿名标签,用 pyannote.audio(开源)算 embedding 匹配你注册的嗓音库。生产通话分析产品通常两个一起用。