这次的目标是继上次的健康时报打卡机器人,现在要实现语音控制。
一、部署工作
使用的是百度智能云:具体操作文档https://ai.baidu.com/ai-doc/SPEECH/Gk38lyqzo
入门者看着新手指南就可以了。
之后进入百度智能云登录账号后领取可以实现语音识别的额度:
之后点击创建任务:
之后就获取了语音识别的AppID、API Key、Secret Key:
点击隔壁的技术文档:
之后点击下载SDK:
下载Python SDK:
注意看一下使用说明:
之后就开始入门吧。
二、语音识别
安装Python SDK:
pip install baidu-api
或者在Pycharm中找到baidu-aip进行下载:
之后打开pycharm,新建ApiSpeech:参考如下代码
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)
按照技术文档进行操作,要对一段语音文件进行识别:
需要注意的是下面需要调用ffmpeg,在上次的文章中我已经下载完成了:
在cmd中输入ffmpeg表示配置成功。
开启pycharm,在pycharm中的用法如下:
ffmpeg -y -i %s -acodec pcm_s16le -f s16le -ac 1 -ar 16000 %s.pcm
第一个%s表示原始文件
第二个%s也表示原始文件,但是它加了后缀.pcm
在请求时需要指定一个pcm格式的文件,而技术文档给的是如下的代码:
# 读取文件
def get_file_content(filePath):
with open(filePath, 'rb')as fp:
return fp.read()
# 识别本地文件
a = client.asr(get_file_content('录音.pcm'), 'pcm', 16000, {'dev_pid': 1537})
print(a)
看看它需要的参数有如下:
有参数表我们可得知需要格式为pcm、wav或者amr的格式。
如果我单纯只用电脑录音,只会让它报错:
Traceback (most recent call last): File "D:/PythonvideoTest/mian.py", line 18, in <module> a = client.asr(get_file_content('录音.m4a'), 'pcm', 16000, {'dev_pid': 1537}) File "D:\PythonvideoTest\venv\lib\site-packages\aip\speech.py", line 69, in asr data['speech'] = base64.b64encode(speech).decode() File "D:\python\lib\base64.py", line 58, in b64encode encoded = binascii.b2a_base64(s, newline=False) TypeError: a bytes-like object is required, not 'builtin_function_or_method'
16000表示采样率,1537表示是保准的普通话,不可以带口音。
之后我调用了ffmepg进行转码,否则无法生成正确的识别效果:
# 读取文件
def get_file_content(filePath):
cmd_str = "ffmpeg -y -i %s -acodec pcm_s16le -f s16le -ac 1 -ar 16000 %s.pcm" % (filePath, filePath)
os.system(cmd_str) # 调用系统命令ffmpeg,传入音频文件名
with open(filePath, 'rb')as fp:
return fp.read()
# 识别本地文件
a = client.asr(get_file_content('video.m4a'), 'pcm', 16000, {'dev_pid': 1537, })
print(a)
最后的结果是:
上面红色的字是转码的过程。
看看传出来的字典是代表什么意思:
{'corpus_no': '7065173086757783768',
'err_msg': 'success.',
'err_no': 0,
'result': ['你好。'],
'sn': '460221681121644988797'}
若err_msg包含的是错误描述信息,帮助理解和解决发生的错误,看下面这个文档:
https://ai.baidu.com/ai-doc/SPEECH/Dk4o0bmkl
接下来就从字典中取字:
print(a['result'])
在网上看见:当key不存在时,要使用如下:
if a.get('result'):
print(a.get('result')[0])
三、语音生成
result = client.synthesis('嘿嘿嘿嘿嘿', 'zh', 1, {'vol': 5, })
# 识别正确返回语音二进制,错误则返回dict 参照下面代码
if not isinstance(result, dict):
with open("audio.mp3", 'wb')as f:
f.write(result)
#调用系统命令
os.system("audio.mp3")
之后在目录会出现一个audio.mp3文件。但是我并没有生成音频T T。
语音生成的参数:
'spd':5, # 语速-中等
'vol': 5, # 音量-中等
'pit':5, # 音调-中等
'per':0 # 发音人-女声
然后我就把result的结果打印出来:
{'err_detail': '16: Open api characters limit reached',
'err_msg': '16: Open api characters limit reached',
'err_no': 502,
'err_subcode': 16,
'tts_logid': 3329425580}
所以结果是我的字长超过了限制:Open api characters limit reached,没有对应接口额度。
原来是我没有领取免费额度...额...醉了。
其他错误:
https://ai.baidu.com/ai-doc/SPEECH/Ck4nlz91i
四、实时语音识别
(一)各种模块的安装
在上面我们都是使用本地的音频来识别检测的,那么要保持检测麦克风,只要有声音就生成wav文件向API发送请求,当识别不到语音信息时,则自动停止。
使用的语音识别模块为:speech_recognition
需要的其他模块:baidu-aip、PyAudio、pyttsx3、wave
具体说明:
在windows平台下,使用speech_recognition记录音频,并转换为16k的wav,之后利用ffmpeg将wav转化为pcm文件,上传到百度语音端,返回语音信息。
安装speech_recognition:SpeechRecognition · PyPI
pip install SpeechRecognition
或者在pycharm中安装:
安装pocketsphinx(离线语音识别)
pip install pocketsphinx
如若出现:
那么就去:https://www.lfd.uci.edu/~gohlke/pythonlibs/#pocketsphinx下载whl文件,我下载的是:
安装PyAudio:PyAudio · PyPI
pip install PyAudio
如若出现下面的报错:
ERROR: Command errored out with exit status 1: 'd:\python\python.exe' -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\Users\auus\AppData\Local\Temp\pip-install-qifk_0di\pyaudio_ca262538ea45479397c1173b7e87e16a\setup.py'"'"'; __ file ='"'"'C:\Users\auus\AppData\Local\Temp\pip-install-qifk_0di\pyaudio_ca262538ea45479397c1173b7e87e16a\setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(file) if os.path.exists(file) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file__, '"'"'exec'"'"'))' install --record 'C:\Users\auus\AppData\Local\Temp\pip-record-2f5ahtzc\install-record.txt' --single-version-externally-managed --compile --install-headers 'd:\python\Include\PyAudio' Check the logs for full command output.
ERROR: Command errored out with exit status 1: command: 'd:\python\python.exe' -u -c 'import io, os, sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\Users\auus\AppData\Local\Temp\pip-install-qifk_0di\pyaudio_ca262538ea45479397c1173b7e87e16a\setup.py'"'"'; file='"'"'C:\Users\auus\AppData\Local\Temp\pip-install-qifk_0di\pyaudio_ca262538ea45479397c1173b7e87e16a\setup.py'"'"';f = getattr(tokenize, '"'"'open'"'"', open)(file) if os.path.exists(file) else io.StringIO('"'"'from setuptools import setup; setup()'"'"');code = f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' install --record 'C:\Users\auus\AppData\Local\Temp\pip-record-2f5ahtzc\install-record.txt' --single-version-externally-managed --compile --install-headers 'd:\python\Include\PyAudio' cwd: C:\Users\auus\AppData\Local\Temp\pip-install-qifk_0di\pyaudio_ca262538ea45479397c1173b7e87e16a\
解决过程:
-
首先下载whl文件:https://www.lfd.uci.edu/~gohlke/pythonlibs/#pyaudio
-
选择cp代表python版本号3.8、amd64代表64位的whl文件。
- 下载后切换到终端使用pip执行刚刚下载好的文件
pip install PyAudio-0.2.11-cp38-cp38-win_amd64.whl
在GitHub上有语音识别的Demo:https://github.com/Uberi/speech_recognition/blob/master/examples/microphone_recognition.py
在过程中我遇到了一个我明明在pycharm的配置环境中安装了PyAudio(在Windows上安装的),但是使用import PyAduio时却出错的问题。最后我重装python修改了虚拟环境才得以解决这个问题...
(2)代码
语音识别库参考:https://github.com/Uberi/speech_recognition/blob/master/reference/library-reference.rst
第一步:实现可以听取麦克风并且进行读取文本。
import time
import speech_recognition as sr
import pyaudio
import os
import pyttsx3
import wave
import pocketsphinx
from aip import AipSpeech
APP_ID = '25611234'
API_KEY = 'Ia1pGYSvwe3iWfOr0x1n1234'
SECRET_KEY = '4rTh892aD0qh49VwlsTmRiQ6iwv12345'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
# 用于录音speech_recognition
def grow_audio(rate=16000):
# 用于读取麦克风
r = sr.Recognizer()
with sr.Microphone(sample_rate=rate) as source:
print("他在等你讲话...")
# 动态调整能量阈值以解决环境噪音
r.adjust_for_ambient_noise(source)
# 限制录音时长位30s
audio = r.listen(source, phrase_time_limit=30)
print('okk!')
# 将音频写入
with open('voice.wav', 'wb') as f:
f.write(audio.get_wav_data())
# 读取文件
def get_file_content(filePath):
cmd_str = "ffmpeg -y -i %s -acodec pcm_s16le -f s16le -ac 1 -ar 16000 %s.pcm" % (filePath, filePath)
os.system(cmd_str) # 调用系统命令ffmpeg,传入音频文件名
with open(filePath + ".pcm", 'rb')as fp:
return fp.read()
# 识别文件 使用百度API
def pcm2text():
pcm_audio = get_file_content('voice.wav')
text = client.asr(pcm_audio, 'pcm', 16000, {'dev_pid': 1537, })
print(text['result'])
if __name__ == "__main__":
while True:
grow_audio()
pcm2text()
最后实现效果为:
第二步:实现人机交互
导入上次实现的半自动打卡机器人的程序,并且加入pyttsx3进行人机交互。
import time
import speech_recognition as sr
import pyaudio
import os
import pyttsx3
import wave
import pocketsphinx
from aip import AipSpeech
from appium import webdriver
from appium.webdriver.common.touch_action import TouchAction
APP_ID = '25611234'
API_KEY = 'Ia1pGYSvwe3iWfOr0x1n1234'
SECRET_KEY = '4rTh892aD0qh49VwlsTmRiQ6iwv12345'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
# 用于录音speech_recognition
def grow_audio(rate=16000):
# 用于读取麦克风
r = sr.Recognizer()
with sr.Microphone(sample_rate=rate) as source:
print("他在等你讲话...")
# 动态调整能量阈值以解决环境噪音
r.adjust_for_ambient_noise(source)
# 限制录音时长位30s
audio = r.listen(source, phrase_time_limit=30)
print('okk!')
# 将音频写入
with open('voice.wav', 'wb') as f:
f.write(audio.get_wav_data())
# 读取文件
def get_file_content(filePath):
cmd_str = "ffmpeg -y -i %s -acodec pcm_s16le -f s16le -ac 1 -ar 16000 %s.pcm" % (filePath, filePath)
os.system(cmd_str) # 调用系统命令ffmpeg,传入音频文件名
with open(filePath + ".pcm", 'rb')as fp:
return fp.read()
# 识别文件 使用百度API
def pcm2text():
pcm_audio = get_file_content('voice.wav')
text = client.asr(pcm_audio, 'pcm', 16000, {'dev_pid': 1537, })
print(text['result'])
return text['result']
def say_hi():
engine.say('嘿,你来找我玩啦!')
# 本句话是没有声音的,如果要调用say()函数,每次调用都要加上这句
engine.runAndWait()
# 健康上报
def headlth_update():
tests = {
"platformName": "Android",
"platformVersion": "11",
"deviceName": "M2012K11AC",
"appPackage": " com.tencent.wework",
"appActivity": ".launch.LaunchSplashEduActivity",
"noReset": "True"
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", tests)
engine.say('正在健康上报')
engine.runAndWait()
time.sleep(3)
# 工作台
el1 = driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget"
".LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android"
".widget.LinearLayout/android.view.ViewGroup/android.widget.RelativeLayout["
"4]/android.widget.RelativeLayout/android.widget.TextView")
el1.click()
time.sleep(6)
el2 = driver.find_element_by_xpath(
"/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget"
".LinearLayout/android.widget.FrameLayout/android.widget.FrameLayout/android.widget.RelativeLayout/android"
".widget.FrameLayout[2]/android.widget.RelativeLayout/android.view.ViewGroup/androidx.recyclerview.widget"
".RecyclerView/android.widget.RelativeLayout["
"1]/android.widget.LinearLayout/android.widget.RelativeLayout/android.widget.ImageView")
el2.click()
engine.say('健康上报完成')
engine.runAndWait()
if __name__ == "__main__":
# 初始化
engine = pyttsx3.init()
say_hi()
while True:
grow_audio()
output = pcm2text()
if '企业微信进行健康上报' or '打开' or '微信' or '健康上报' in output:
engine.say('好的')
engine.runAndWait()
headlth_update()