原文:https://blog.csdn.net/weixin_44638960/article/details/96979347
百度AI的连接地址:https://ai.baidu.com/
1、百度AI语音识别技术:百度语音识别通过 REST API 的方式给开发者提供一个通用的 HTTP 接口。上传需要完整的录音文件,录音时长不超过60s。对于任意操作系统,任意编程语言,只要可以对百度语音服务器发起http请求的,均可以使用此接口。
首先我们学习百度给的语音识别demo:https://ai.baidu.com/docs#/ASR-Online-Python-SDK/top
第一步安装python sdk:执行 pip install baidu-aip 命令。(PyCharm直接在File-Setting中搜索baidu-aip导入即可)
第二步新建AipSpeech:AipSpeech是语音识别的Python SDK客户端,为使用语音识别的开发人员提供了一系列的交互方法。
新建AipSpeech代码如下:(APP_ID,API_KEY,SECRET_KEY均在创建应用时都会给出)
from aip import AipSpeech
""" 你的 APPID AK SK """
APP_ID = '你的 App ID'
API_KEY = '你的 Api Key'
SECRET_KEY = '你的 Secret Key'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
第三步对语音文件进行识别:client.asr('speech',‘format’,‘rate’,'dev_pid'),speech为建立包含语音内容的Buffer对象, 语音文件的格式,pcm 或者 wav 或者 amr。不区分大小写;format为音频文件格式,pcm 或者 wav 或者 amr。不区分大小写。推荐pcm文件;rate为采样率,16000,固定值;dev_pid为输入法模型(默认1537),下图为dev_pid的取样表。
dev_pid | 语言 | 模型 | 是否有标点 | 备注 |
---|---|---|---|---|
1536 | 普通话(支持简单的英文识别) | 搜索模型 | 无标点 | 支持自定义词库 |
1537 | 普通话(纯中文识别) | 输入法模型 | 有标点 | 支持自定义词库 |
1737 | 英语 | 有标点 | 不支持自定义词库 | |
1637 | 粤语 | 有标点 | 不支持自定义词库 | |
1837 | 四川话 | 有标点 | 不支持自定义词库 | |
1936 | 普通话远场 | 远场模型 | 有标点 | 不支持 |
语音识别代码如下:
# 读取文件
def get_file_content(filePath):
with open(filePath, 'rb') as fp:
return fp.read()
# 识别本地文件
client.asr(get_file_content('audio.pcm'), 'pcm', 16000, {'dev_pid': 1536})
语音识别 返回数据参数详情:client.asr()返回的是一个字典类型。(下表为返回字典对应键的名称与作用)
参数 | 类型 | 是否一定输出 | 描述 |
---|---|---|---|
err_no | int | 是 | 错误码(0为返回成功) |
err_msg | int | 是 | 错误码描述 |
sn | int | 是 | 语音数据唯一标识,系统内部产生,用于 debug |
result | int | 是 | 识别结果数组,提供1-5 个候选结果,string 类型为识别的字符串, utf-8 编码 |
返回成功与失败样例:(result为录音文件的识别内容,用户可通过此键来获取)
错误类型:由err_no可以推断出错误类型
错误码 | 用户输入/服务端 | 含义 | 一般解决方法 |
---|---|---|---|
3300 | 用户输入错误 | 输入参数不正确 | 请仔细核对文档及参照demo,核对输入参数 |
3301 | 用户输入错误 | 音频质量过差 | 请上传清晰的音频 |
3302 | 用户输入错误 | 鉴权失败 | token字段校验失败。请使用正确的API_KEY 和 SECRET_KEY生成。或QPS、调用量超出限额。或音频采样率不正确(可尝试更换为16k采样率)。 |
3303 | 服务端问题 | 语音服务器后端问题 | 请将api返回结果反馈至论坛或者QQ群 |
3304 | 用户请求超限 | 用户的请求QPS超限 | 请降低识别api请求频率 (qps以appId计算,移动端如果共用则累计) |
3305 | 用户请求超限 | 用户的日pv(日请求量)超限 | 请“申请提高配额”,如果暂未通过,请降低日请求量 |
3307 | 服务端问题 | 语音服务器后端识别出错问题 | 目前请确保16000的采样率音频时长低于30s。如果仍有问题,请将api返回结果反馈至论坛或者QQ群 |
3308 | 用户输入错误 | 音频过长 | 音频时长不超过60s,请将音频时长截取为60s以下 |
3309 | 用户输入错误 | 音频数据问题 | 服务端无法将音频转为pcm格式,可能是长度问题,音频格式问题等。 请将输入的音频时长截取为60s以下,并核对下音频的编码,是否是16K, 16bits,单声道。 |
3310 | 用户输入错误 | 输入的音频文件过大 | 语音文件共有3种输入方式: json 里的speech 参数(base64后); 直接post 二进制数据,及callback参数里url。 分别对应三种情况:json超过10M;直接post的语音文件超过10M;callback里回调url的音频文件超过10M |
3311 | 用户输入错误 | 采样率rate参数不在选项里 | 目前rate参数仅提供16000,填写4000即会有此错误 |
3312 | 用户输入错误 | 音频格式format参数不在选项里 | 目前格式仅仅支持pcm,wav或amr,如填写mp3即会有此错误 |
2、语音读取(目的:将用户所讲内容打印至客户端):
PyAudio的应用和使用,此第三方库可以进行录音,播放,生成wav文件等等。
第一步安装PyAudio:PyCharm直接在File-Setting中搜索PyAudio导入,同导入百度AI类似。
第二步
实现对于音频文件的录制(wave库和PyAudio库的使用):
音频文件的录制:
from pyaudio import PyAudio,paInt16
import wave,time
def SaveVoice():
pa=PyAudio()
wf=wave.open(r'T.wav','wb')#打开wave文件
wf.setnchannels(1)#配置声道数
wf.setsampwidth(2)# 采样宽度2bytes
wf.setframerate(16000)#采样率
stream=pa.open(format=paInt16,channels=wf.getnchannels(),rate=wf.getframerate(),input=True,frames_per_buffer=1024) #打开一个stream
buff=[]#存储声音信息
start=time.time()#开始运行时间戳
print('say:')
while time.time()
buff.append(stream.read(wf.getframerate()))
stream.close()#关闭stream
pa.terminate()
wf.writeframes(b''.join(buff))
wf.close()#关闭wave
或者使用第三方库SpeechRecognition :pip install SpeechRecognition即可
def my_record(rate=16000):
r = sr.Recognizer()
with sr.Microphone(sample_rate=rate) as source:
print("please say something")
audio = r.listen(source)#读入声音信息
with open("T.wav", "wb") as f:
f.write(audio.get_wav_data())#得到wave信息写入音频文件
print("录音完成!")
3、构建一个机器人(图灵机器):连接http://www.turingapi.com/
申请一个账号即可免费创建属于自己的机器人(可在官网上对其属性进行设置),普通注册用户一天可以免费调用100次。
使用说明:1、编码方式UTF-8;2、接口地址:http://openapi.tuling123.com/openapi/api/v2
3、请求方式:http post;4、参数格式:json格式;(具体属性的参数说明详见下表)
{
"reqType":0,#数据类型为整型,用于区分传入的数据类型,0-文本(默认)、1-图片、2-音频
"perception": {#必填项,用户输入的数据
"inputText": {#非必填项,用于保存文本信息
"text": ""#string类型,必填项,文本内容
},
"inputImage": {#非必填项,用于保存图片信息
"url": "imageUrl"#string类型,必填项,图片地址
},
"selfInfo": {#非必填项,用于识别用户信息
"location": {
"city": "",
"province": "",
"street": ""
}
}
},
"userInfo": {#必填项,识别用户信息
"apiKey": "",#此处为图灵机器人的apiKey
"userId": ""
}
}
参数说明
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
reqType | int | N | - | 输入类型:0-文本(默认)、1-图片、2-音频 |
perception | - | Y | - | 输入信息 |
userInfo | - | Y | - | 用户参数 |
perception
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
inputText | - | N | - | 文本信息 |
inputImage | - | N | - | 图片信息 |
inputMedia | - | N | - | 音频信息 |
selfInfo | - | N | - | 客户端属性 |
注意:输入参数必须包含inputText或inputImage或inputMedia!(必须有一个存在)
inputText
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
text | String | Y | 1-128字符 | 直接输入文本 |
inputImage
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
url | String | Y | 图片地址 |
inputMedia
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
url | String | Y | 音频地址 |
selfInfo
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
location | - | N | - | 地理位置信息 |
location
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
city | String | Y | - | 所在城市 |
province | String | N | - | 省份 |
street | String | N | - | 街道 |
userInfo
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
apiKey | String | Y | 32位 | 机器人标识 |
userId | String | Y | 长度小于等于32位 | 用户唯一标识 |
groupId | String | N | 长度小于等于64位 | 群聊唯一标识 |
userIdName | String | N | 长度小于等于64位 | 群内用户昵称 |
返回成功与失败的示例:
失败样例:(只返回错误提示类型)
{#返回失败信息
'intent':
{
'code':5000#错误码,0表示上传成功。
}
}
异常码 说明
5000 无解析结果
6000 暂不支持该功能
4000 请求参数格式错误
4001 加密方式错误
4002 无功能权限
4003 该apikey没有可用请求次数
4005 无功能权限
4007 apikey不合法
4100 userid获取失败
4200 上传格式错误
4300 批量操作超过限制
4400 没有上传合法userid
4500 userid申请个数超过限制
4600 输入内容为空
4602 输入文本内容超长(上限150)
7002 上传信息失败
8008 服务器错误
0 上传成功
成功样例:以询问酒店为例
{
"intent": {#用于表示请求意图
"code": 10005,
"intentName": "",
"actionName": "",
"parameters": {
"nearby_place": "酒店"
}
},
"results": [#输出结果集合
{
"groupType": 1,
"resultType": "url",
"values": {
"url": "http://m.elong.com/hotel/0101/nlist/#indate=2016-12-10&outdate=2016-12-11&keywords=%E4%BF%A1%E6%81%AF%E8%B7%AF"
}
},
{
"groupType": 1,
"resultType": "text",
"values": {#输出值
"text": "亲,已帮你找到相关酒店信息"#机器反馈信息
}
}
]
}
参数说明
参数 | 类型 | 是否必须 | 取值范围 | 说明 |
---|---|---|---|---|
intent | - | Y | - | 请求意图 |
results | - | N | - | 输出结果集 |
intent
参数 | 类型 | 是否包含 | 取值范围 | 说明 |
---|---|---|---|---|
code | int | Y | - | 输出功能code |
intentName | String | N | - | 意图名称 |
actionName | String | N | - | 意图动作名称 |
parameters | Map | N | - | 功能相关参数 |
results
参数 | 类型 | 是否包含 | 取值范围 | 说明 |
---|---|---|---|---|
resultType | String | Y | 文本(text);连接(url);音频(voice);视频(video);图片(image);图文(news) | 输出类型 |
values | - | Y | - | 输出值 |
groupType | int | Y | - | ‘组’编号:0为独立输出,大于0时可能包含同组相关内容 (如:音频与文本为一组时说明内容一致) |
通过requests库的post方法将json数据和编码格式UTF-8(import requests)
import requests#导入requests库,多用于网络爬虫
import json#导入json库
TulingUrl='http://openapi.tuling123.com/openapi/api/v2'
turing_api_key = "你申请的图灵机器人id"
def RobotSpeak(usersay="你好"):#默认为对话你好
robot={
"perception": {
"inputText": {
"text": usersay#用户询问内容
}
},
"userInfo": {
"apiKey": turing_api_key ,
"userId": 'Dudu'#识别用户可随机书写
}
}
response=json.loads(requests.post(TulingUrl,None,robot,headers={'Content-Type':'charset=UTF-8'}).text)
print(response)
if __name__=='__main__':
RobotSpeak('你叫什么名字')
到此位置我们基本可以实现简单的人机交互功能,即用户说一句话机器给出相应的答复,但仅仅是文字的输入输出似乎满足不了我们的需求,我们可以在此基础上扩展新的功能,比如让机器将反馈的信息以语音的形式得以呈现。
Python给我们提供了一个第三方库pyttsx,可以实现文字转换语音的基本功能。
import pyttsx3#导入第三方库
engine=pyttsx3.init()#初始化engine
rate = engine.getProperty('rate')
engine.setProperty('rate', rate-66)#设置语速
engine.say('要说的内容')
engine.runAndWait()#没有此句无声音
from aip import AipSpeech
from pyaudio import PyAudio,paInt16
import requests,json,wave,time,pyttsx3
#百度AI,配置信息
APP_ID = ''#百度ai应用id
API_KEY = ''#百度ai应用的键值
SECRET_KEY = ''
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
#图灵机器,配置信息
TulingUrl='http://openapi.tuling123.com/openapi/api/v2'
turing_api_key = ""#图灵机器人api_key
# 读取文件
def get_file_content(filePath):
with open(filePath, 'rb') as fp:
return fp.read()
#用户语音输入
def SaveVoice():
pa=PyAudio()
wf=wave.open(r'T.wav','wb')#打开wave文件
wf.setnchannels(1)#配置声道数
wf.setsampwidth(2)# 采样宽度2bytes
wf.setframerate(16000)#采样率
stream=pa.open(format=paInt16,channels=wf.getnchannels(),rate=wf.getframerate(),input=True,frames_per_buffer=1024) #打开一个stream
buff=[]#存储声音信息
start=time.time()#开始运行时间戳
print('用户说:')
while time.time()
buff.append(stream.read(wf.getframerate()))
stream.close()#关闭stream
pa.terminate()
wf.writeframes(b''.join(buff))
wf.close()#关闭wave
#接受机器人响应
def RobotSpeakText(usersay="你好"):
robot={
"perception": {
"inputText": {
"text": usersay
}
},
"userInfo": {
"apiKey": turing_api_key ,
"userId": 'Dudu'
}
}
response=json.loads(requests.post(TulingUrl,None,robot,headers={'Content-Type':'charset=UTF-8'}).text)
return str(response['results'][0]['values']['text'])
#语音发声
def RobotVoice(robotsay="我没听清,你在说一遍"):
engine=pyttsx3.init()
rate=engine.getProperty('rate')
engine.setProperty('rate',rate-66)
engine.say(robotsay)
engine.runAndWait()
#主函数
def main():
while True:
try:
SaveVoice()
result = client.asr(get_file_content('T.wav'), 'wav', 16000, {'dev_pid': 1536}) # 识别本地文件
usersay=result['result'][0]
print(usersay)
robotsay=RobotSpeakText(usersay)
print('小嘟嘟说:')
print(robotsay)
RobotVoice(robotsay)
except:#异常处理
break
if __name__=='__main__':
main()