You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何结合speech_recognition与pyannote.audio实现实时说话人识别及语音转写匹配

如何结合speech_recognition与pyannote.audio实现实时说话人识别及语音转写匹配

我来帮你梳理问题根源,再给出针对性的解决方案——你的核心需求是实时获取麦克风音频的说话人嵌入,和预存的WAV文件嵌入对比,同时完成语音转写,还要避免临时存文件占用SD卡空间对吧?咱们一步一步来解决:

先搞清楚你遇到的两个核心问题:

  1. 官方示例报错ValueError: XA must be a 2-dimensional array
    这是因为部分版本的pyannote.audio返回的embedding是一维数组(形状为(D,),D是嵌入维度),而cdist要求输入必须是二维数组。解决方法很简单:把每个embedding用reshape(1, -1)转换成二维形状(1, D)就行。

  2. 实时音频的余弦距离总是接近1,完全不匹配实际说话人
    这个问题的核心原因是麦克风采样率和pyannote模型要求的采样率不匹配!pyannote/embedding模型是基于16kHz采样率训练的,而speech_recognitionMicrophone默认采样率通常不是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

火山引擎 最新活动