语音识别应用在现在的客服呼叫中心行业已经不是什么新的技术。媒体服务器通过和第三方语音识别引擎集成实现客服机器人,对话机器人等业务场景。
所谓语音,核心就是指人说的话,在人类自然语言交互中,我们通过聆听与阅读 收集数据,通过进一步的语言处理获得语义信息,再依靠文字、声音等方式表达 出来,而智能语音发展的意义则存在于实现机器“听说读写”的过程中。进一步说,现在我们讨论的语音绝大部分是来自于语音通话中的RTP语音流。
所以,智能语音应用场景基本上都是通过呼叫通话中的RTP语音采集,通过和语音识别引擎的交互获得语音或者文本的生成。在当前异常火爆的语音识别平台的争夺战中,绝大部分厂家都是互联网行业的头部厂家,它们的服务成本也非常昂贵,并且可能还存在数据安全的问题。Kaldi是语音识别平台中一个开源的语音识别引擎,很多厂家通过Kaldi对自己的业务系统进行训练,实现其灵活性支持和需求的二次开发。Daniel Povey也是Kaldi之父前几年加入了小米,采访新闻也是轰动一时。小米给了他产学研结合的环境平台,它希望通过小米验证其技术的可行性,小米可能是Daniel Povey梦想起飞的地方。笔者以前介绍过Vosk开源项目和MRCP协议,读者有兴趣的话,可以查看历史文档也可以学习MRCP协议。
MRCP协议中文详解:
https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzA4NjU0NTIwNQ==&action=getalbum&album_id=2623742447495626754#wechat_redirect
因为最近一个客户的项目中使用了Vosk和Kaldi,而且当前的集成成熟度也得到了提升,在商业应用场景中应该有所突破,所以重新再归纳整理和大家分享。因为Vosk是基于Kaldi集成的一个轻量级平台服务器,它可以实现和多种服务器端协议集成,包括MQTT, GRPC, WebRTC和Websocket。Vosk支持支持离线语音识别引擎,支持20多种语言,其中也包括了对中文的支持。一些主要的基础语料系统会默认安装。
我们这里仅介绍通过Websocket API(ws接口配置文件)方式实现的Asterisk媒体服务器集成。如果用户使用FreeSWITCH的话,安装方式和Asterisk基本上是一致的,可以参考官方文档来实现。这里,我们主要介绍Vosk/Kaldi和Asterisk的集成。集成部署包括Asterisk安装,Vosk-asterisk模块安装配置Vosk服务器端容器安装等主要步骤。
1)安装Asterisk或者FreeSWITCH媒体引擎
安装asterisk前需要用户安装各种环境支持包,这是非常关键的一步,或者执行以下命令。
// 在Asterisk 源代码下找到以下路径,执行安装前检查,系统会自动安装必要的支持包。
contrib/scripts/install_prereq install
如果支持包成功安装以后,绝大部分的安装应该不会出现问题,这里不再讨论。笔者是下载的Asterisk-20 tar文件,然后解压安装就可以实现。这里不再介绍关于Asterisk安装。
2)安装Vosk-asterisk支持包
安装好asterisk以后,用户需要再安装Vosk模块。下载Vosk-asterisk模块,执行安装编译。
root@iZj6c1a8vgbkumvc45lcr8Z:/usr/src/vosk/vosk-asterisk# ./bootstrap
+ libtoolize --force --automake --copy
+ autoheader
+ aclocal -I m4
+ automake --foreign --add-missing --copy
configure.ac:5: installing './compile'
configure.ac:2: installing './missing'
res-speech-vosk/Makefile.am: installing './depcomp'
+ autoconf
+ rm -rf autom4te.cache
root@iZj6c1a8vgbkumvc45lcr8Z:/usr/src/vosk/vosk-asterisk# ./configure --with-asterisk=/usr/src/asterisk-20.5.2/ --prefix=/usr
checking for a BSD-compatible install... /usr/bin/install -c
按照以上命令进行编译。
执行安装后支持包查询命令,确保在指定的安装路径。
root@iZj6c1a8vgbkumvc45lcr8Z:/usr/src/vosk/vosk-asterisk# find / -name res_speech_vosk.so -print
/usr/src/vosk/vosk-asterisk/res-speech-vosk/.libs/res_speech_vosk.so
/usr/lib/asterisk/modules/res_speech_vosk.so
这里读者要注意, 原始安装代码指向了错误的配置路径,需要手动拷贝到正确的路径中。如果熟悉asterisk的读者应该知道这个默认的配置路径。
test -d /usr/etc/asterisk || /bin/bash /usr/src/vosk/vosk-asterisk/install-sh -d /usr/etc/asterisk
// 应该是/etc/asterisk
cp res_speech_vosk.conf /etc/asterisk
拷贝配置文件到/etc/asterisk环境下:
root@iZj6c1a8vgbkumvc45lcr8Z:/usr/src/vosk/vosk-asterisk/conf# ls
res_speech_vosk.conf
root@iZj6c1a8vgbkumvc45lcr8Z:/usr/src/vosk/vosk-asterisk/conf# cp res_speech_vosk.conf /etc/asterisk/
root@iZj6c1a8vgbkumvc45lcr8Z:/usr/src/vosk/vosk-asterisk/conf#
确认这几个已经编译的模块在asterisk目录下。
在安装路径中查询这些模块
/usr/lib/asterisk/modules/
或者/usr/lib64/asterisk/modules/
确认这些模块在默认安装目录下以后,然后在模块配置文件中添加新的模块,启动asterisk时会加载我们刚才编译的模块。读者修改modules.conf 配置文件,加载vosk模块。注意,这些模块名称在CLI后台还查询不到。
另外,如果有必要的话,用户可以通过配置文件修改其端口和服务器IP地址。用户可以编辑asterisk配置文件/conf/res_speech_vosk.conf。
[general]
url = ws://localhost:2700 // 通过ws实现和Vosk服务器端通信
创建一个Asterisk拨号规则测试呼叫。用户可以使用pjsip注册一个SIP分机,呼叫到拨号规则以后,执行以下流程。
[from-internal]
exten = 1,1,Answer
same = n,Wait(1)
same = n,SpeechCreate
same = n,SpeechBackground(hello) // 系统回放欢迎语
// // 打印出分机用户所说的内容
same = n,Verbose(0,Result was ${SPEECH_TEXT(0)})
以上是关于Asterisk的安装测试环境。
在FreeSWITCH环境安装和Asterisk环境安装是基本一致的,首先需要编译mod_vosk.so模块,然后添加模块加载和服务器配置控制(modules.conf.xml和conf/vosk.conf.xml),然后配置拨号规则。
更多关于FreeSWITCH配置,参考Vosk-FreeSWITCH模块说明
https://github.com/alphacep/freeswitch/tree/master/src/mod/asr_tts/mod_vosk
3)Vosk服务器端容器安装
再次说明,首先用户需要安装容器工具的支持包。关于支持包安装和docker这里不再做太多介绍。安装好支持包以后,可以先进行测试,支持的是Python 3.9版本。然后启动vosk服务器。Vosk服务器端镜像支持多个语言的镜像,用户可以安装英文版本或者中文版本的容器镜像。笔者安装的是vosk的CN版本。用户可以根据部署环境到官方网站下载不同的model。
如果用户要根据不同model测试的话,用户需要修改测试代码中的model路径.
下载链接如下:
https://alphacephei.com/vosk/models
当然,用户可以根据自己的环境,安装相应的语言支持版本,笔者安装的是:
docker run -d -p 2700:2700 alphacep/kaldi-cn:latest
笔者现在的系统已经安装了docker,所以不再做更多介绍。关于debian环境下docker安装的资料很多,建议用户自己学习。
启动容器以后,执行以下命令安装
// 默认安装英文版本, 这里我们测试中文语言识别,所以安装中文cn版本
docker run -d -p 2700:2700 alphacep/kaldi-cn:latest
安装好vosk服务器端以后,通过docker命令启动状态。
dockers ps -a // 系统已经启动了docker,安装kaldi-cn 镜像
root@iZj6c1a8vgbkumvc45lcr8Z:~# docker run -d -p 2700:2700 alphacep/kaldi-cn:latest
Unable to find image 'alphacep/kaldi-cn:latest' locally
latest: Pulling from alphacep/kaldi-cn
df5590a8898b: Pull complete
b07d59199e84: Pull complete
0e4f6ce137fd: Pull complete
0139dee2664a: Pull complete
Digest: sha256:34272dddd7eddb0c511ac5aac8b2132f8d01b895a427f117fe475c70ef7a27df
Status: Downloaded newer image for alphacep/kaldi-cn:latest
2bc95389b7a18c23770317b9d7ac8885058b1518507c25a82b1d7702c507a660
root@iZj6c1a8vgbkumvc45lcr8Z:~#
确认Vosk服务器端启动以后,登录到Vosk容器中,执行测试:
root@iZj6c1a8vgbkumvc45lcr8Z:~# docker run -it alphacep/kaldi-cn:latest /bin/bash
root@9937544c3dd4:/opt/vosk-server/websocket# ls
asr_server.py test.py test.wav test16k.wav test_alternatives.py test_ffmpeg.py test_microphone.py test_srt.py test_words.py
root@9937544c3dd4:/opt/vosk-server/websocket#
如果要在启用asterisk集成前进行测试的话,需要修改test.py 文件中的IP地址,如果是本地IP的话,应该可以不要修改此地址。
root@4a0d122a913c:/opt/vosk-server/websocket# cat test.py
#!/usr/bin/env python3
import asyncio
import websockets
import sys
import wave
async def run_test(uri):
async with websockets.connect(uri) as websocket:
wf = wave.open(sys.argv[1], "rb")
await websocket.send('{ "config" : { "sample_rate" : %d } }' % (wf.getframerate()))
buffer_size = int(wf.getframerate() * 0.2) # 0.2 seconds of audio
while True:
data = wf.readframes(buffer_size)
if len(data) == 0:
break
await websocket.send(data)
print (await websocket.recv())
await websocket.send('{"eof" : 1}')
print (await websocket.recv())
// 修改为测试地址,在asterisk中对应的也是此地址。
asyncio.run(run_test('ws://localhost:2700'))
Vosk的cn模型配置,用户如果需要优化或者增加自己的一些语料配置的话,可以根据这些配置来优化。
root@4a0d122a913c:/opt/vosk-model-cn# cd model/
root@4a0d122a913c:/opt/vosk-model-cn/model# ls
README am conf graph ivector rescore rnnlm
root@4a0d122a913c:/opt/vosk-model-cn/model# cd conf/
root@4a0d122a913c:/opt/vosk-model-cn/model/conf# ls
mfcc.conf model.conf
root@4a0d122a913c:/opt/vosk-model-cn/model/conf#
root@4a0d122a913c:/opt/vosk-model-cn/model/conf# cat model.conf
--min-active=200
--max-active=7000
--beam=13.0
--lattice-beam=6.0
--acoustic-scale=1.0
--frame-subsampling-factor=3
--endpoint.silence-phones=1:2:3:4:5:6:7:8:9:10
--endpoint.rule2.min-trailing-silence=0.5
--endpoint.rule3.min-trailing-silence=1.0
--endpoint.rule4.min-trailing-silence=2.0
因为启动Vosk服务器和Asterisk实现测试的话,用户服务器需要至少16G内存的配置,防止系统资源不能支持kaldi的正常工作。在Asterisk服务器端启动以后,我们已经看到了Asterisk加载的模块记录
用户注册一个SIP分机以后,可以根据拨号规则的设置,呼入以后,如果用户开始说话的时候,Asterisk会打印出相应的文本内容。因为笔者的测试机系统内存资源有限,启动时出现了资源问题,不能非常完整测试余下的呼叫流程,用户可以根据以上步骤基本上可以搭建一套基于Vosk-kaldi-Asterisk的智能语音系统。
Vosk其它应用集成支持
Vosk是基于Kaldi封装的开源语音识别引擎,它充分利用了kaldi强大的语音识别引擎功能以外,同时增加了第三方集成的应用场景和各种API支持,真正站在了巨人肩膀上,实现了多开发语言集成和多场景支持,极大降低了语音识别应用开发门槛。除了支持我们刚才说的Asterisk和FreeSWITCH媒体服务器以外,还支持了很多和语音关联的其它场景,包括了开源视频服务器-jitsi的支持,unimrcp支持,离线PC桌面应用的实时语音识别支持,副标题生成功能支持,网络收音机控制支持,语音助手和视频搜索功能,移动端的支持。
总结
在本文档中,笔者讨论了关于如何使用离线开源语音识别引擎开发套件Vosk集成媒体服务器Asterisk和FreeSWITCH. Vosk是基于kaldi开源语音识别引擎开发的语音识别套件,极大降低了用户开放部署的成本,同时支持了多种应用场景。
在本文档中主要介绍了如何安装Asterisk的开源语音识别模块vosk,配置vosk模块已经使用拨号规则测试语音识别引擎。在本文档中,笔者也讨论了如何安装vosk容器,配置相关的应用环境测试。最后,笔者介绍了vosk的其它应用场景。
再次说明,本文档仅是一个抛砖引玉,针对Vosk集成媒体服务器的探讨。当然,因为chatgpt的横空出世,和基于python开放的语音识别应用手段越来越简单便捷,语音识别应用呈现了多种业务型态,读者需要根据自己的业务场景对工具进行调整。另外,kaldi的识别准确性以及本地模型调优也需要用户针对自己的环境进行优化处理。这些挑战都已经超过了本人的能力范围,希望读者参考更多行业权威资料来学习。
参考资料:
https://alphacephei.com/vosk/
https://github.com/alphacep/vosk-asterisk
https://github.com/alphacep/vosk-server
www.sip.org.cn
https://hub.docker.com/u/alphacep
https://github.com/kaldi-asr/kaldi
https://xueqiu.com/9217191040/145539282
The Kaldi Speech Recognition Toolkit,Daniel Povey1 , Arnab Ghoshal2 , Gilles Boulianne3 , Luka′s Burget ˇ 4,5 , Ondˇrej Glembek4 , Nagendra Goel6 , Mirko Hannemann4 , Petr Motl′?cek ˇ 7 , Yanmin Qian8 , Petr Schwarz4 , Jan Silovsky′ 9 , Georg Stemmer10, Karel Vesely′ 4
获得关于SIP/IP语音相关技术分享-加入“SIP实验室技术分享群“-QQ号-589995817