FunASR识别独立的语音文件问题

之前我实现了在本地部署FunASR并调用,还是比较成功。当我想在OpenClaw中用FunASR识别收到的音频文件时,发现调用还是不顺,所以就记录下来。

2种调用方式

调用FunASR服务有2种方式,

  • funasr_client_api.py
  • funasr_wss_client.py
    没有深入看代码,我直觉先用funasr_wss_client.py调用,解决基本问题后,就可以轻松识别。问题解决见我之前的文章:

识别模式mode

我先用funasr_wss_client.py跑了一下,感觉效果还可以。

就写了一段代码,实现在Android手机上进行语音识别。

但用着就发现,还有mode的区别:

  • online:只用online模式,精准度较低,实时返回给客户端。
  • offline:用offline模式识别,精准度较高,且有标点符号,延迟相对高一点。在funasr_wss_client.py有BUG,直接会识别不了。
  • 2pass:2阶段模式,先用online模式快速识别,并返回客户端。当VAD识别中断后,调用offline模式,进行精准识别。返回给客户端是先返回online,几个字一返回,速度快,实时。然后会返回一段offline的识别结果。

这就导致程序必须要做特殊处理:

  • 实时解析online的结果,并显示,但不作为最终的结果

  • 如果收到offline的结果,就将最近收到的online结果替换成offline的结果,可以作为最终结果

  • 这样循环往复处理

  • 最后,如果没有收到offline就结束了,最后一部分的online结果要追加到最终识别结果中。
    这对实时语音识别还好。

    实时识别结果

    [2026-03-14 20:42:35.756] online, {'key': 'rand_key_dckfdL0z5uIAy', 'text': '嗯'}
    [2026-03-14 20:42:36.568] online, {'key': 'rand_key_urlorDGzrgpk3', 'text': '是一'}
    [2026-03-14 20:42:37.385] online, {'key': 'rand_key_dpM7tpTqiDexO', 'text': '测试的音'}
    [2026-03-14 20:42:38.195] online, {'key': 'rand_key_q6xD6tpBm9BYs', 'text': '频收'}
    [2026-03-14 20:42:38.978] online, {'key': 'rand_key_FcINSJXFHGrvM', 'text': '到之后将'}
    [2026-03-14 20:42:39.853] online, {'key': 'rand_key_tMMVyu8TmB0DH', 'text': '文字转'}
    [2026-03-14 20:42:40.701] online, {'key': 'rand_key_1IUqHgBE2NwYt', 'text': ''}
    [2026-03-14 20:42:41.485] online, {'key': 'rand_key_KEkjm94BRNriX', 'text': '将音频转'}
    [2026-03-14 20:42:42.295] online, {'key': 'rand_key_BOKlofaf5Vvc9', 'text': '成文字'}
    [2026-03-14 20:42:43.203] online, {'key': 'rand_key_9l4CcBt08p9Hp', 'text': '并且发给'}
    [2026-03-14 20:42:44.103] online, {'key': 'rand_key_Kd840v2DL8WJF', 'text': '我'}
    [2026-03-14 20:42:45.260] offline_asr, raw: {'key': 'rand_key_Jc1g3yNq14ScG', 'text': '这 是 一 条 测 试 的 音 频 收 到 之 后 将 文 字 转 将 音 频 转 成 文 字 并 且 发 给 我', 'timestamp': [[250, 390], [390, 510], [510, 590], [590, 730], [730, 870], [870, 1050], [1050, 1170], [1170, 1330], [1330, 1570], [1730, 1870], [1870, 2010], [2010, 2110], [2110, 2310], [2310, 2530], [2530, 2690], [2690, 2830], [2830, 3070], [3590, 3830], [3850, 3950], [3950, 4150], [4150, 4250], [4250, 4390], [4390, 4530], [4530, 4770], [4790, 4890], [4890, 5050], [5050, 5190], [5190, 5430], [5430, 6055]]}
    [2026-03-14 20:42:45.260] offline_asr, keys: dict_keys(['key', 'text', 'timestamp'])
    [2026-03-14 20:42:46.237] offline, after punc {'key': 'rand_key_amHImDZF510iK', 'text': '这是一条测试的音频,收到之后将文字转将音频转成文字并且发给我', 'punc_array': tensor([1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 3], device='cuda:0')}

    offline的结果,看起来更准确,且有标点符号

    [2026-03-14 20:42:46.238] ======offline final text: 这是一条测试的音频,收到之后将文字转将音频转成文字并且发给我

FunASR识别一个文件

当我想用FunASR识别一个文件的时候,就遇到无法完整识别的问题。

按理应该是用offline模式,但是会失败。所以还是用2pass模式。

  • 按照流程,会先用online识别,然后静音后用offline识别
  • 最后一段没有用offline,只有online结果,导致识别准确率不高。
    就如上面的日志显示那样。

funasr_client_api调用方式

最开始没有注意到这个,当我注意它的时候,以为它能用来识别一个文件。但看了代码还是和funasr_wss_client类似。

想要正确调用,需要修改funasr_client_api.py,将文件路径直接填进源码,其他信息如服务器、端口都要进行调整。

复制代码
python ./funasr_client_api.py

提示缺少:websocket。安装

复制代码
pip install websocket
# 如果不安会有新的报错
pip install websocket-client

提示新的错误,需要安装websocket-client

复制代码
ImportError: cannot import name 'ABNF' from 'websocket' (/home/band/anaconda3/envs/faenv/lib/python3.12/site-packages/websocket/__init__.py)

这是直接调用会报新的错误:

复制代码
connect to url wss://127.0.0.1:10095
Exception: Handshake status 400 Bad Request -+-+- {'date': 'Sat, 14 Mar 2026 13:37:22 GMT', 'connection': 'close', 'content-length': '60', 'content-type': 'text/plain; charset=utf-8', 'server': 'Python/3.12 websockets/16.0'} -+-+- b'Failed to open a WebSocket connection: missing subprotocol.\n'

解决方案是改funasr_client_api.py

复制代码
# 修改前
self.websocket = create_connection(uri, ssl=ssl_context, sslopt=ssl_opt)
# 修改后
self.websocket = create_connection(uri, ssl=ssl_context, sslopt=ssl_opt, subprotocols=["binary"])

单文件调用的正确方式

上述的websocket调用方式,对于单文件都有不好的地方。最终找到最佳的使用方式是使用代码调用:

复制代码
# 
from funasr.auto.auto_model import AutoModel

model_dir = "FunAudioLLM/Fun-ASR-Nano-2512"

model = AutoModel(
    model=model_dir,
    vad_model="fsmn-vad",
    vad_kwargs={"max_single_segment_time": 30000},
    device="cuda:0",
)

wav_path = f"filepath.wav"

res = model.generate(input=[wav_path], cache={}, batch_size_s=0)
text = res[0]["text"]
print(text)

(faenv) PS D:\workspace\FunASR\tests> python .\test_single_wav.py
funasr version: 1.3.1.
Check update of funasr, and it would cost few times. You may disable it by set `disable_update=True` in AutoModel
You are using the latest version of funasr-1.3.1
Downloading Model from https://www.modelscope.cn to directory: D:\ProgramData\modelscope\models\FunAudioLLM\Fun-ASR-Nano-2512
WARNING:root:trust_remote_code: False
Downloading Model from https://www.modelscope.cn to directory: D:\ProgramData\modelscope\models\iic\speech_fsmn_vad_zh-cn-16k-common-pytorch
WARNING:root:trust_remote_code: False
rtf_avg: 0.022: 100%| 略
Okay。 收到这条语音,这是一条测试音频,收到之后将这个音频 转成文字,并且发给我,把文字的内容发给我。

总结及最终选择

第一次使用FunASR,对于它的原理、用法还不熟,借用AI,只是提高效率,对于我不熟、AI也不熟的地方,实在没有好的方法,只能一步一个脚印、走一步踩一坑地走下去。

对于单文件语音识别,使用WebSocket服务器和本地直接调用的对比,在同一模型、同一台机器上:

维度 WebSocket服务器 本地直接调用
正确率 大部分一样,最后一段差
加载速度 优,免加载 差,耗时
识别速度
性能消耗 差,不用也会消耗 优,按需调用
内存占用 差,持续占用内存 优,按需调用

由于我是要在OpenClaw中使用飞书调用FunASR识别我发的语音,两种方案都差不多。我就暂时先按照WebSocket服务器来用。

相关推荐
Qt学视觉2 小时前
AI3-PaddleOCR搭建环境1
c++·人工智能·opencv·ocr·paddlepaddle
nix.gnehc2 小时前
OpenClaw 天气查询Skill开发Demo
人工智能·skill·openclaw
黑客说2 小时前
无限流:从网文想象到AI赋能的沉浸式娱乐新生态
人工智能·娱乐
AI_Auto2 小时前
【人工智能】- OpenClaw本地化安装
大数据·人工智能·机器学习·数据挖掘
RuiBo_Qiu2 小时前
【LLM进阶-Agent】3.ReAct Agent 进阶--如何解决幻觉输出工具调用结果
人工智能·ai-native
skywalk81632 小时前
看到有人提到:有网站使用分解质因数来区分人和机器,一种新兴的“反向CAPTCHA”策略
人工智能
陈天伟教授2 小时前
人工智能应用- 机器做梦:03.回顾卷积神经网络
人工智能·神经网络·cnn
Lw中2 小时前
模型忽略关键实体怎么办?
人工智能·大模型应用基础
致Great2 小时前
AI Harness 工程:Agent 能跑起来的那一层到底是什么?
人工智能