Author:qyan.li
Date:2022.5.15
Topic:简单记录阿里云语音识别
API
调用
~~~~~~ 最近的课程设计需要语音识别
算法,但由于自己实现能力不够,只能借助于现成的API
资源,目前国内比较成熟的包括百度云,阿里云,科大讯飞等等。由于百度云自己之前使用过,无法免费调用,故此次转到阿里云API
尝试。
~~~~~~ 本篇博文主要记录自己在阿里云API
调用中遇到的问题及解决方案。但是需要提醒的是,下述的方案可以保证大家能够使用阿里云API
,但肯定不是最优甚至正确的方案,也希望有大佬可以贡献下思路和调用方法。
~~~~~~ 废话不多说,先上代码,方便大家参考使用,至于为什么这么改,后面会详细说,修改代码操作包含以下三步:
首先,在下载下的SDK
文件夹下新建CodeTest.py
文件,并将下面的代码拷贝至文件中,保存
# -*- coding = utf-8 -*-
import time
import threading
import sys
import nls
## 阿里云语音识别调用规范(此处信息更换为个人)
URL="********"
AKID="*******"
AKKEY="*********"
APPKEY="*******"
class TestSr:
def __init__(self,test_file):
self.__test_file = test_file
## 读取音频文件内容,存放在self.__data中
def loadfile(self, filename):
with open(filename, "rb") as f:
self.__data = f.read()
def getResult(self):
self.loadfile(self.__test_file)
## type == str而非dict,因此需按照字符串格式进行内容提取
return self.__test_run().split('"')[-4]
def __test_run(self):
sr = nls.NlsSpeechRecognizer(
url=URL,
akid=AKID,
aksecret=AKKEY,
appkey=APPKEY
)
r = sr.start(aformat="pcm", ex={"hello":123})
## 将文件数据传递NlsSpeechRecognizer
self.__slices = zip(*(iter(self.__data),) * 640)
for i in self.__slices:
sr.send_audio(bytes(i))
time.sleep(0.01)
r = sr.stop()
return sr.result
t = TestSr("./test.wav") # 参数传入待识别的语音文件
result = t.getResult()
print(result)
'''
识别结果:
省点钱还能买回点东西来行了嗯上海天气超市买东西
'''
在SDK的文件夹下找到_speech_recognizer.py
文件(在子文件夹nls
下),并在python
文件中添加两行代码:
NlsSpeechRecognizer
类的构造函数函数末尾添加代码self.result = None
,大概在121行左右的位置,注意在构造函数内部,缩进__sr_core_on_msg
函数的末尾添加代码:self.result = msg
致此,代码的修改已经全部完成,你可以测试一下,理论上将应该是可以成功运行获得语音识别的结果。
~~~~~~ OK
,首先,代码中删除多线程部分,主要原因在于自己对多线程了解不多,代码难以掌控,其次,自己仅作简单的语音识别,实在也是没有必要添加多线程的处理,故去除此处多线程的代码。
~~~~~~ 另外,我解释一下我为什么要添加后面的代码?
~~~~~~ 首先,如果你粘贴阿里云官方文档上的代码直接运行,你大概率会看到一连串的语句输出,并且循环往复不停的在执行。并且输出诸多红色字体的语句并在前方伴随着时间信息和DEBUG字符
,如下面:
2022-05-29 17:00:23,573 - DEBUG - get token baa04102311f4d099986b83636281002
2022-05-29 17:00:23,574 - DEBUG - ws run...
2022-05-29 17:00:23,574 - DEBUG - wait cond wakeup
2022-05-29 17:00:24,862 - DEBUG - core_on_open:(<nls._core.NlsCore object at 0x00000256C37B3C48>, '{"header": {"message_id": "5441d027d9c7468cb3fcf85b80d78f30", "task_id": "87e6f295fd584e0fa716362c2f0d0aab", "namespace": "SpeechRecognizer", "name": "StartRecognition", "appkey": "kK77KCDsoBijyG7y"}, "payload": {"format": "pcm", "sample_rate": 16000, "enable_intermediate_result": false, "enable_punctuation_prediction": false, "enable_inverse_text_normalization": false, "hello": 123}}')
2022-05-29 17:00:24,862 - DEBUG - notify on open
2022-05-29 17:00:24,862 - DEBUG - wakeup without timeout
2022-05-29 17:00:24,862 - DEBUG - __sr_core_on_open
~~~~~~ 按照自己的猜测这应该就是所谓的程序日志。虽然有所耳闻,但毕竟作为学生仅写些小代码的自己哪里见过这等阵仗,但是不要慌:
~~~~~~ 仔细观察,会发现其中存在这样的输出:
2022-05-29 17:00:33,017 - DEBUG - core_on_msg:{"header":{"namespace":"SpeechRecognizer","name":"RecognitionCompleted","status":20000000,"message_id":"e277e5e9f9c3403aa8a56c6edb22e854","task_id":"87e6f295fd584e0fa716362c2f0d0aab","status_text":"Gateway:SUCCESS:Success."},"payload":{"result":"省点钱还能买回点东西来行了嗯上海天气超市买东西","duration":9980}}
2022-05-29 17:00:33,017 - DEBUG - __sr_core_on_msg:msg={"header":{"namespace":"SpeechRecognizer","name":"RecognitionCompleted","status":20000000,"message_id":"e277e5e9f9c3403aa8a56c6edb22e854","task_id":"87e6f295fd584e0fa716362c2f0d0aab","status_text":"Gateway:SUCCESS:Success."},"payload":{"result":"省点钱还能买回点东西来行了嗯上海天气超市买东西","duration":9980}} args=()
~~~~~~ 看到其中我们喜欢的部分了吗?就是其中的result
所对应的value
,这不就是我们目标识别的语音内容吗?但是怎么提出出来呢!既然能够显示在python
的输出中,就意味着代码中一定存在某个部分是负责这个输出的。那么接下来的任务就变的纯粹,那就是找到这个输出。
~~~~~~ 很明显,CodeTest.py
的代码中是不可能负责它的输出的,一定是调用的某个文件中存在日志的输出,观察CodeTest.py
的代码,代码中出现NlsSpeechRecognizer
类的构造,那就从它入手,在CodeTest.py
中选中NlsSpeechRecognizer
,鼠标右键选择implements
即可自动跳转至类的实现。
~~~~~~ 在回来观察日志输出,会发现这两个包含语音识别输出的部分前部字符均与core_on_msg
有关,那就在_speech_recognizer.py
文件中ctrl+f
搜索上述字符,会自动对应到一个叫做__sr_core_on_msg
的函数的位置,我们仔细观察这个函数:
def __sr_core_on_msg(self, msg, *args):
_logging.debug("__sr_core_on_msg:msg={} args={}".format(msg, args))
self.__handle_message(msg)
~~~~~~ 发现,这个_logging.debug("__sr_core_on_msg:msg={} args={}".format(msg, args))
的代码不就是和我们上面输出的第二个相互对应的嘛?
2022-05-29 17:00:33,017 - DEBUG - __sr_core_on_msg:msg={"header":{"namespace":"SpeechRecognizer","name":"RecognitionCompleted","status":20000000,"message_id":"e277e5e9f9c3403aa8a56c6edb22e854","task_id":"87e6f295fd584e0fa716362c2f0d0aab","status_text":"Gateway:SUCCESS:Success."},"payload":{"result":"省点钱还能买回点东西来行了嗯上海天气超市买东西","duration":9980}} args=()
~~~~~~ 只不过此时参数msg
以字典的形式给出,参数args
没有,ok
,我们定位到这里,接下来问题容易解决,既然传入的msg
中包含我需要的目标信息(语音识别结果),那么我给出一个接口,外部可以访问msg
变量,在进行适当的解析不就可以获得语音识别结果嘛?
~~~~~~ 据此,我们添加上面的代码,自定义self.result
变量,并在此函数中将msg
赋值给self.result
变量,外部可访问,即可获得对应的语音识别结果。但需要提醒result
并非语音识别的结果,而是包含结果的一串字符串,还需要经过字符串处理才能实现语音识别结果的分离:
result.split('"')[-4]
~~~~~~ 上述经过改动的代码可以正常获得语音识别结果的输出,但是识别的速度会比较慢,预估可能需要十秒左右的时间,从识别的时间来看,上述代码基本也没有办法使用。但是这并不影响我们在这其中学习知识,掌握分析代码结构的方式,从这一点上来说,写这篇博文收获也还是有的。
~~~~~~ 最终,如果大家想调用语音识别接口,从我自己的体验上来讲,百度云的体验更好,CSDN
上可参考的教程也比较多。这对于我们技术不太成熟的学生来讲是更加友好的。
自行修改的代码已经上传至网盘,百度网盘链接:
链接:
https://pan.baidu.com/s/1sFUhXYUTBElgpSS8v3D2Lg
提取码:uc5e