如何结合speech_recognition与pyannote.audio实现实时说话人识别及语音转写匹配
如何结合speech_recognition与pyannote.audio实现实时说话人识别及语音转写匹配
我来帮你梳理问题根源,再给出针对性的解决方案——你的核心需求是实时获取麦克风音频的说话人嵌入,和预存的WAV文件嵌入对比,同时完成语音转写,还要避免临时存文件占用SD卡空间对吧?咱们一步一步来解决:
先搞清楚你遇到的两个核心问题:
官方示例报错
ValueError: XA must be a 2-dimensional array
这是因为部分版本的pyannote.audio返回的embedding是一维数组(形状为(D,),D是嵌入维度),而cdist要求输入必须是二维数组。解决方法很简单:把每个embedding用reshape(1, -1)转换成二维形状(1, D)就行。实时音频的余弦距离总是接近1,完全不匹配实际说话人
这个问题的核心原因是麦克风采样率和pyannote模型要求的采样率不匹配!pyannote/embedding模型是基于16kHz采样率训练的,而speech_recognition的Microphone默认采样率通常不是16kHz(比如常见的44.1kHz或48kHz),这会导致实时音频的时域数据变形,生成的embedding和预存的完全不相关,自然距离异常。
修正后的完整实现代码
我把你的代码做了针对性修改,同时加入多说话人匹配的逻辑,注释里写清了关键要点:
import speech_recognition as sr from pyannote.audio import Model, Inference from scipy.spatial.distance import cdist import torch import numpy as np # 修正:统一用np作为numpy别名 # 1. 初始化语音识别器 recognizer = sr.Recognizer() recognizer.dynamic_energy_threshold = False recognizer.energy_threshold = 1100 recognizer.pause_threshold = 3 # 2. 加载pyannote说话人嵌入模型(确保和模型要求的采样率一致:16kHz) embedding_model = Model.from_pretrained( "pyannote/embedding", use_auth_token="你的授权令牌", device="cpu" if not torch.cuda.is_available() else "cuda" ) # 全局设置device,避免重复指定 inference_device = torch.device("cuda" if torch.cuda.is_available() else "cpu") inference = Inference(embedding_model, device=inference_device, window="whole") # 3. 预加载所有说话人的嵌入(用字典存储,方便后续匹配) # 替换成你的实际WAV文件路径 speaker_embeddings = { "Speaker_A": inference("voice_sample_A.wav").reshape(1, -1), "Speaker_B": inference("voice_sample_B.wav").reshape(1, -1) } # 4. 初始化麦克风:强制设置采样率为16kHz,和模型要求一致! # 这是解决距离异常的关键 with sr.Microphone(sample_rate=16000) as source: print("请说话...") # 获取实时音频 audio = recognizer.listen(source, timeout=10) # 语音转写 try: recognized_text = recognizer.recognize_google(audio, language="en") print(f"转写结果:{recognized_text}") except sr.UnknownValueError: print("无法识别语音") recognized_text = "" except sr.RequestError as e: print(f"Google语音识别服务出错:{e}") recognized_text = "" # 处理实时音频生成嵌入(不存文件,直接处理内存数据) if recognized_text: # 把AudioData的原始字节转换成模型要求的格式:float32,范围[-1, 1] audio_data = np.frombuffer(audio.get_raw_data(), dtype=np.int16).astype(np.float32) / 32768.0 # 转换成模型需要的张量形状:(通道数, 采样点数),单通道就是(1, N) live_audio = { "waveform": torch.tensor(audio_data).unsqueeze(0).to(inference_device), "sample_rate": 16000 } # 生成实时嵌入并转成二维数组 live_embedding = inference(live_audio).reshape(1, -1) # 计算和每个预存说话人的余弦距离,找出最匹配的 min_distance = float("inf") matched_speaker = "未知说话人" for speaker, embedding in speaker_embeddings.items(): distance = cdist(live_embedding, embedding, metric="cosine")[0, 0] print(f"与{speaker}的余弦距离:{distance:.4f}") if distance < min_distance: min_distance = distance matched_speaker = speaker # 输出最终匹配结果 print(f"===== 匹配结果:{matched_speaker} =====") print(f"{matched_speaker}:{recognized_text}")
额外注意事项
- 授权令牌:确保你的
use_auth_token是有效的,需要在Hugging Face平台申请pyannote的访问权限。 - 预存样本质量:每个说话人的预存WAV文件建议时长3-5秒,包含清晰的语音,避免背景噪音,这样嵌入的准确性更高。
- SD卡内存优化:代码全程都是内存处理,没有生成临时文件,完全符合你的需求。
- 余弦距离的意义:余弦距离范围是0到2,值越小表示两个嵌入越相似(0是完全匹配,2是完全不匹配)。你可以根据实际测试结果设置一个阈值(比如0.5),当距离小于阈值时才认定为匹配,避免误判。
备注:内容来源于stack exchange,提问作者Flamethrower




