制作语音助手
思路
制作语音助手其实不难,只是步骤有点繁琐,但是其实每一步都挺简单的。
步骤大致分为以为5点
1.将输入保存成语音文件(RECORD)
2.读取语音文件获得文本(ASR)
3.对文本处理输出所需要的文本(NLP)
4.将输出文本转换成语音文件(TTS)
5.将语音文件播出(PLAY)
其中第一点和第五点可以放到一起,支持录音的一般也支持播音。
其中第二点和第四点可以放到一起,支持语音识别的一般也支持语音合成。
第三点可以简单对文本处理,实现任务型的语音助手,
也可以用神经网络,也有现成的图灵机器人,实现交流型的语音助手。
RECORD和PLAY
这一方面可以用pyaudio实现,我也实际实践过
但是它封装后可设置得参数指向性不是很明显
而且效果也没有系统自带的好
所以最后选择了用python执行命令行程序
调用系统自带的arecord来RECORD,用aplay来PLAY
即方便又简洁还好用。
pyaudio
pyaudio代码可以参考源码:http://people.csail.mit.edu/hubert/pyaudio/
其中有几个地方要注意
1.录音和播音过程会出现报错信息,但是不影响录音,可以关闭信息
import sys,os
os.close(sys.stderr.fileno())
2.play的代码有问题
# 源码
data = wf.readframes(CHUNK)
while data != '':
stream.write(data)
data = wf.readframes(CHUNK)
# while的判断有问题 因为就算readframes读到最后 返回的也是b'' != '' 所以是死循环
# 应该改成 while len(data) >0:
# 或者直接改成下面这样子
while True:
data = wf.readframes(CHUNK)
if len(data) > 0:
stream.write(data)
else:
break
3.有bug时注意查看播放设备对不对以及其他各个参数
pyaudio的文档:http://people.csail.mit.edu/hubert/pyaudio/docs/
stream类有挺多参数可以设置的
系统自带arecord
- 查看可录音设备
arecord -l
留意card和device后面的数字 例如card 1 device 0
- 录音
arecord -D plughw:1,0 -d 5 -f cd -r 16000 -c 1 -t wav test.wav
hw代表直接访问硬件,plughw代表经过采样率和格式转换插件。
-D 指定设备 hw:1,0 代表card1 device0
-d 指定录音时间
-f 指定录音格式
-r 指定采样率
-c 指定采样通道
-t 指定文件格式
- python调用
import os
os.system("arecord -D plughw:1,0 -d 5 -f cd -r 16000 -c 1 -t wav test.wav")
参考:https://blog.csdn.net/z2066411585/article/details/99089141
参考:https://blog.csdn.net/xiongtiancheng/article/details/80577478
系统自带aplay
- 查看可播放设备
aplay -l
留意card和device后面的数字 例如card 1 device 0
- 播放
aplay -D plughw:1,0 test.wav
- python调用
import os
os.system("aplay -D plughw:1,0 test.wav")
ASR和TTS
这一方面我使用 百度语音识别 直接看官方的例程和开发文档
网址:https://cloud.baidu.com/doc/SPEECH/s/Vk38lxily
首先要创建一个应用,获得 API Key和Secret Key,然后套入官方代码就可以使用了。
代码使用官方代码:https://github.com/Baidu-AIP/speech-demo
API Key和Secret Key不要手输!!直接复制粘贴!!
因为真的会分辨不了,我把I(大写i)输错成l(小写L),debug了好久!
可以先将API_KEY和SECRET_KEY带入到下面网址,然后输入到网页验证是否可用
http://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=API_KEY&client_secret=SECRET_KEY
补充一下ASR后续的处理
输出是一个很长的字符串,假设是’“xxx”:[xxx],“result”:[“你好。”]’
我们需要将其中的你好。提取出来
我使用的是正则表达式,先匹配"result":[],
然后再把输出结果切片获得我们所需的文本,
注意末尾是有标点符号的,但是我们不要将其剔除掉
因为语音合成会将标点符号也计算进去。
代码如下
#solve output
match = re.search('"result":\[(.*)]', result_str)#正则表达式匹配
if match:
start, end = match.span()
result = result_str[start + 11:end - 2]#切片获得所需文本
print(result,'\n')
各个模块实现了,接下来就是中间的逻辑处理了,大致处理如下,叮咚为唤醒名称。
def record(device,time,rate,file):
print(" * RECORD")
cmd = "arecord -D plughw:"+\
str(device)+\
" -d " +\
str(time)+\
" -f cd -r "+\
str(rate)+\
" -c 1 -t wav " +\
file
os.system(cmd)
print()
def play(device,file):
print(" * PLAY")
cmd = "aplay -D plughw:"+\
device+\
" " + \
file
os.system(cmd)
print()
flag = False # 唤醒flag
cnt = 0 # 非任务语音计数
while True:
output_text = " " # 输出的文本
# 录音并语音识别
record(device,record_time,rate,"./record.wav")
text = asr("./record.wav",rate)
if flag:
# 这里就通过if elif 罗列所需要的任务
if 0:
pass
elif 0:
pass
else:
cnt += 1
output_text = " "
# 计数大于一定值则结束唤醒
if cnt >5:
flag = False
cnt = 0
if "叮咚" in text:
flag = True
output_text = "在"
print("输出语音:",output_text)
if flag:
# 语音合成并播放
tts(output_text, "./play.wav")
play(device,"./play.wav")
由于语音识别结果均为汉字,我们有要求要将其中的数字提取出来,也就是九转成9、十二转成12这种,
实现思路就是先将所有汉字单独转为数字,
然后变步长遍历
如果是0,就步长跨1
如果是小于10的数,就与下一位相乘,然后累加到result里,然后步长跨2
如果是大于10的数,直接累计到result里,然后步长跨1
该代码仅适用于正数,代码实现如下
def chinese_char2num(character):
result = -1
characters = {"零": 0, "一": 1, "二": 2, "三": 3, "四": 4,
"五": 5, "六": 6, "七": 7, "八": 8, "九": 9,
"十": 10, "百": 1e2, "千": 1e3, "万": 1e4, }
for c in characters:
if character == c:
result = characters[c]
return result
def chinese_chars2num(text):
success = True
result = 0
# 将每一个汉字转为数字
nums = []
for t in text:
num = chinese_char2num(t)
nums.append(num)
i = 0
while True:
if nums[i] < 0:
success = False
break
if nums[i] == 0:
i += 1
elif nums[i] < 10:
if i + 1 < len(nums):
if nums[i + 1] >= 10:
result += nums[i] * nums[i + 1]
else:
result += nums[i]
i += 2
else:
result += nums[i]
i += 1
if i > len(nums):
break
if not success:
result = -1
return result
print(chinese_chars2num('一万二千三百四十五'))
最后放一张我们小组最后实现的结果,是一个可以实时显示当前空气质量可以定时提醒,并具有语音交互功能的小电视。