1、实时ASR就没有准确的,只要是流式的,就准确不了,基本上都是一边说一边改,你要是急着往LLM里面塞,LLM必然混乱。
2、目前实时最好的办法依然是VAD+ASR
3、Onnx比PT快的不是一星半点,但是modelscope上那个玩意iic/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-online-onnx在我的机器上就是跑不了,输出是乱码。我怀疑和numpy的版本有关系,哪个numpy导出的,推理也必须用这个numpy版本。
4、不要相信网络API的stream模式,哪怕是Qwen的付费API,效果都不咋地。这不难理解,chunk的上下文不足,处理不好就容易崩。
5、不要害怕参数,ASR这个级别全文预算速度非常快,但是不要用.pt的版本,一定要转onnx来运行,效果会好非常多。用pt的情况下,CPU是2s音频7s推理,慢的和乌龟一样。用onnx,1s转录大概只需要0.25秒。
6、做实时你必须考虑用户的感受,你这边还在BBBBB的说话,那边你就送ASR是没有意义的,LLM又没有实时推理功能。这点理论上是可以做的,因为LLM的确是因果推理。理论上可以一边输入文字,一边处理。但我还不知道谁能这么玩的。

给一个onnx的asr推理案例,这玩意funasr自己的github上没有,在funasr-onnx的pypi里面有。

首先得把funasr从torch转为onnx

# modelscope download --model iic/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch --local_dir ./paraformer
# 命令行先执行这个指令,把paraformer的pt文件拉到本地。

from funasr import AutoModel
ASR_MODEL_PATH = "./paraformer"
model_asr = AutoModel(model=ASR_MODEL_PATH, disable_update=True)
export_dir = model_asr.export(quantize=False)
print(f"ONNX model exported to: {export_dir}")
#onnx会保存在原来的文件夹下,这里也打印了,自己看一下就行

然后开始推理

from funasr_onnx import Paraformer
import wave
import sys
import soundfile as sf
import logging
import numpy as np
import time
import re

def check_wav_info(wav_path):
    """检查 WAV 文件信息"""
    flag=False
    try:
        with wave.open(wav_path, 'rb') as wf:
            n_channels = wf.getnchannels()
            sample_width = wf.getsampwidth()
            framerate = wf.getframerate()
            n_frames = wf.getnframes()
            duration = n_frames / framerate
            
            print(f"WAV 文件:{wav_path}")
            print(f"  声道数:{n_channels}")
            print(f"  采样位深:{sample_width} 字节 ({sample_width * 8}-bit)")
            print(f"  采样率:{framerate} Hz")
            print(f"  总帧数:{n_frames}")
            print(f"  总时长:{duration:.2f} 秒")
            print(f"  文件大小:{n_channels * sample_width * n_frames} 字节 (音频数据)")
            
            # 检查是否符合 ASR 模型要求
            print("\n格式检查:")
            if n_channels != 1:
                print(f"  ❌ 错误:需要单声道,当前为 {n_channels} 声道")
            else:
                print(f"  ✓ 声道数正确(单声道)")
                
            if framerate != 16000:
                print(f"  ❌ 错误:需要 16000Hz 采样率,当前为 {framerate}Hz")
            else:
                print(f"  ✓ 采样率正确(16000Hz)")
                
            if sample_width != 2:
                print(f"  ❌ 错误:需要 16-bit (2 字节),当前为 {sample_width * 8}-bit")
            else:
                print(f"  ✓ 位深正确(16-bit)")
                return True
                
    except FileNotFoundError:
        print(f"错误:文件不存在:{wav_path}")
        return flag
    except Exception as e:
        print(f"错误:{e}")
        return flag

def clean_asr_text(text):
    # 1. 把中文和中文之间的空格去掉
    text = re.sub(r'(?<=[\u4e00-\u9fa5])\s+(?=[\u4e00-\u9fa5])', '', text)
    # 2. 把中文和英文、英文和中文之间的空格也去掉
    text = re.sub(r'(?<=[\u4e00-\u9fa5])\s+(?=[a-zA-Z])', '', text)
    text = re.sub(r'(?<=[a-zA-Z])\s+(?=[\u4e00-\u9fa5])', '', text)
    return text


if __name__ == "__main__":
    asr_model_dir = "./paraformer
    #此处放你的asr模型地址,可以用modelscope去下载。
    # 这里要提前转换为onnx格式,代码在上面
    asr_model = Paraformer(asr_model_dir, batch_size=1, quantize=False)
    wav_path = "./test.wav"
    flag=check_wav_info(wav_path)
    if flag:
        start_time = time.perf_counter()
        result = asr_model(wav_path)
        end_time = time.perf_counter()
        print(f"识别耗时:{end_time - start_time:.2f} 秒")
        raw_text = result[0]['preds']
        cleaned_text = clean_asr_text(raw_text)
        print(cleaned_text)

WAV 文件:D:\Python_Project\recorded_sentences\sentence_0002_121128.wav
  声道数:1
  采样位深:2 字节 (16-bit)
  采样率:16000 Hz
  总帧数:31680
  总时长:1.98 秒
  文件大小:63360 字节 (音频数据)

格式检查:
  ✓ 声道数正确(单声道)
  ✓ 采样率正确(16000Hz)
  ✓ 位深正确(16-bit)
识别耗时:0.16 秒
你在干什么你跟我说说话

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐