程序简介:模仿Siri,参考微信公众号:学习python的正确姿势,在语音播放和搜索的基础上,增加了语音输入和打开常用软件功能。
一、配置
- Windows10系统
- python3.7
- pycharm
(其实这些都不重要)
二、主要体系框架
(1)图灵机器人API
自己做一个生动的能聊天的机器人太麻烦了,不过图灵机器人已经帮我们做好了,而且提供了开放的接口,我们注册一个,使用它的接口就可以轻松实现,链接在下方:
注册登录后,如下图所示创建机器人
创建好后你就拥有了这样一个语音聊天机器人:
你还可以在“人物设置”栏里设置它的名字,性别,年龄之类的
还挺别致。。
这个不重要,我们看看它的API使用文档,了解一下怎么用的
嗯,好像很简单的亚子!
不管了,赶紧来试一下。。
import requests
import json
urls = 'http://openapi.tuling123.com/openapi/api/v2' # 图灵接口的url
api_key = "!!!这里要用你自己的api密钥!!!"
prologue = "主人您好,我是Niubility,爱你哦~" # 定义开场白
count = 1 # 用来计数输入的次数
# 回复
def respond(data):
data_dict = {
"reqType":0,
"perception": {
"inputText": {
"text": data
},
},
"userInfo": {
"apiKey": api_key,
"userId": "584403"
}
}
result = requests.post(urls, json=data_dict)
content = (result.content).decode('utf-8')
# print(content)
ans = json.loads(content)
text = ans['results'][0]['values']['text']
print('Niubility:',text) # 机器人取名就叫Niubility
if __name__ == "__main__":
print("Niubility:", prologue)
while True:
data = input('{}//你:'.format(count)) # 输入对话内容
respond(data)
count += 1
运行一下:
阔以阔以!!!
第一步,图灵机器人API就这样解决了,下一步!
(图灵未认证用户一天只能聊三句话,认证之后一天可以聊100句,我们只要学习它的用法就可以了)
(2)百度语音合成API
同样百度提供了开放的语音合成API,我们也注册一个吧,很简单,网址:
方法和上面图灵机器人差不多
注册完成之后是这样的:
查阅官方文档,用法差不多,有语音合成和语音识别两种,我们这里先完成语音合成吧,官方文档整理的很好:
试一下
首先要下载它的库:
pip3 install baidu-api
然后我们给他定义成方法,传入参数text为要语音合成的文字
import os
import playsound # 播放音频的库
from aip import AipSpeech # 百度语音的api
""" 你的 APPID AK SK """
APP_ID = '!!!你的 App ID!!!'
API_KEY = '!!!你的 Api Key!!!'
SECRET_KEY = '!!!你的 Secret Key!!!'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
# 语音合成
def speak_(text):
result = client.synthesis(text, 'zh', 1, {
'vol': 5,
'per': 0,
'spd': 5,
'pit': 5
})
# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
with open('audio.mp3', 'wb') as f:
f.write(result)
playsound.playsound('audio.mp3') # 播放
os.remove('audio.mp3') # 放完后删除音频文件,否则第二次会无法写入
再在respond(data)方法最后一行调用speak_(text)即可播放语音
(3)键盘监听+录音+保存wav文件
语音输入这部分我想实现的目标功能是:按一下键盘空格键开始录音,再按一下空格键录音结束,然后保存为一个.wav文件
1. 键盘监听
键盘监听我用的是pynput库
基本用法:
from pynput.keyboard import Listener
def check_input():
with Listener(on_press=press) as listener:
listener.join()
def press(key):
# print(key.char) # 按下键盘的操作,例如打印出按下的字符
pass
2. 录音
录音我用的是pyaudio库
基本用法:
import pyaudio
"""pyaudio参数"""
CHUNK = 1024 # 数据包或者数据片段
FORMAT = pyaudio.paInt16 # pyaudio.paInt16表示我们使用量化位数 16位来进行录音
CHANNELS = 1 # 声道,1为单声道,2为双声道
RATE = 16000 # 采样率,每秒钟16000次
# RECORD_SECONDS = 5 # 录音时间
def recoder():
_frames = []
p = pyaudio.PyAudio()
stream = p.open(channels=CHANNELS,
format=FORMAT,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
while 1:
data = stream.read(CHUNK)
_frames.append(data)
stream.stop_stream()
stream.close()
p.terminate()
需要注意的是,后面用到的百度语音识别双声道识别效果很差,设置单声道后就很好了,所以设置CHANNELS=1
还有后面用到的百度语音识别只支持16000采样率,所以RATE设置为16000
3. 保存.wav文件
用到wave库
结合pyaudio,基本用法:
import wave
import pyaudio
"""pyaudio参数"""
CHUNK = 1024 # 数据包或者数据片段
FORMAT = pyaudio.paInt16 # pyaudio.paInt16表示我们使用量化位数 16位来进行录音
CHANNELS = 1 # 声道,1为单声道,2为双声道
RATE = 16000 # 采样率,每秒钟16000次
# RECORD_SECONDS = 5 # 录音时间
def recoder():
_frames = []
p = pyaudio.PyAudio()
stream = p.open(channels=CHANNELS,
format=FORMAT,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
while 1:
data = stream.read(CHUNK)
_frames.append(data)
stream.stop_stream()
stream.close()
p.terminate()
# 保存wav文件
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(_frames))
wf.close()
# print("Saved")
(4)百度语音识别API
有了使用语音合成API的基础,用语音识别API就很easy
前面是一样的,所以我把他写在方法外,可以公用:
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)
后面就是语音识别,传入的参数是音频文件的二进制码,文件格式(我们用的是wav),采样率(只能用16000,所以前面的录音必须设置RATE为16000),语言类别(默认1537,普通话)。
# 读取文件
def get_file_content(filePath):
with open(filePath, 'rb') as fp:
return fp.read()
# 识别本地文件
client.asr(get_file_content(WAVE_OUTPUT_FILENAME), 'wav', 16000, {
'dev_pid': 1537,
})
WAVE_OUTPUT_FILENAME就是我们刚才录音保存的文件名。
(5)浏览器搜索 + 打开常用软件功能
1. 浏览器搜索
打开浏览器,我们需要用到:webbrowser库,
没有的话自己pip安装一下
基本用法:
url = "www.baidu.com"
webbrowser.get().open(url)
我们前面已经能通过语音得到我们说的话text,当我们说的话text中有“搜索”两个字时,打开百度并搜索我们要搜的内容,实现代码:
if '搜索' in text:
_, keywords = text.split('搜索')
url = 'https://www.baidu.com/s?wd=' + keywords
webbrowser.get().open(url)
else:
...
2. 打开常用软件
windows打开软件有很多方法,参考:Python中四种运行其他程序的方式
我用的是win32api库,基本用法:
ShellExecute(hwnd, op, file, args, dir, show)
- hwnd: 父窗口的句柄,如果没有父窗口,则为0
- op : 要运行的操作,为open,print或者为空
- file: 要运行的程序,或者打开的脚本
- args: 要向程序传递的参数,如果打开的是文件则为空
- dir : 程序初始化的目录
- show: 是否显示窗口
盘他:
if '搜索' in data:
...
elif '打开' in data:
_, name = data.split('打开')
# print(name)
if '网易云' in name:
win32api.ShellExecute(0, 'open', 'D:\App\CloudMusic\cloudmusic.exe', '', '', 1) # 打开网易云,
elif 'QQ' in name or 'qq' in name:
win32api.ShellExecute(0, 'open', r'D:\App\QQ\Bin\QQScLauncher.exe', '', '', 1) # 打开QQ
elif '微信' in name:
win32api.ShellExecute(0, 'open', r'D:\App\WeChat\WeChat.exe', '', '', 1) # 打开微信
三、综合实现:
为了实现目标功能,还涉及到多线程,将键盘监听单独占用一个线程,设置run,初始值为False,当按下空格时,run变为True,再次按下时,run变为False,以此类推,当run为True时,开始录音,run为False时,录音结束。
运行效果图:(语音输入,语音输出)
全部完整代码:
(代码中api_key之类的要用你自己的噢)
import webbrowser
import requests
import json
import playsound
import os
import win32api
import pyaudio
import wave
import threading
from aip import AipSpeech
from pynput.keyboard import Listener
prologue = '主人您好,我是Niubility,爱你哦~' # 开场白
"""图灵机器人API"""
urls = 'http://openapi.tuling123.com/openapi/api/v2'
key = '**********'
api_key = '********************'
count = 1 # 计数
run = False
"""pyaudio参数"""
CHUNK = 1024 # 数据包或者数据片段
FORMAT = pyaudio.paInt16 # pyaudio.paInt16表示我们使用量化位数 16位来进行录音
CHANNELS = 1 # 声道,1为单声道,2为双声道
RATE = 16000 # 采样率,每秒钟16000次
# RECORD_SECONDS = 5 # 录音时间
WAVE_OUTPUT_FILENAME = "output.wav" # 保存录音文件名
""" 你的 APPID AK SK """
APP_ID = '**********'
API_KEY = '********************'
SECRET_KEY = '********************'
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY) # 百度语音接口
def recoder():
_frames = []
global run
p = pyaudio.PyAudio()
stream = p.open(channels=CHANNELS,
format=FORMAT,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
while run:
data = stream.read(CHUNK)
_frames.append(data)
stream.stop_stream()
stream.close()
p.terminate()
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(_frames))
wf.close()
# print("Saved")
# 按键按下空格时控制录音功能开关
def press(key):
global run
try:
# print(str(key))
if str(key) == 'Key.space':
run = not run
# print(run)
except AttributeError as e1:
print(e1)
pass
# 监听键盘
def check_input():
with Listener(on_press=press) as listener:
listener.join()
# 读取录音文件字节码
def get_file_content(filePath):
with open(filePath, 'rb') as fp:
return fp.read()
# 识别录音,语音转文字
def lic():
res = client.asr(get_file_content(WAVE_OUTPUT_FILENAME), 'wav', 16000, {
'dev_pid': 1537,
})
text = res['result'][0]
# print(text)
return text
# 语音合成
def speak_(text):
result = client.synthesis(text, 'zh', 1, {
'vol': 5,
'per': 0,
'spd': 5,
'pit': 5
})
# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
with open('audio.mp3', 'wb') as f:
f.write(result)
playsound.playsound('audio.mp3')
os.remove('audio.mp3')
# 第一层判别
def respond(data):
if '歌' in data:
douban_rul = 'https://douban.fm/'
webbrowser.get().open(douban_rul)
elif '搜索' in data:
_, keywords = data.split('搜索')
baidu_url = 'https://www.baidu.com/s?wd=' + keywords
webbrowser.get().open(baidu_url)
elif '打开' in data:
_, name = data.split('打开')
# print(name)
if '网易云' in name:
win32api.ShellExecute(0, 'open', 'D:\App\CloudMusic\cloudmusic.exe', '', '', 1) # 打开网易云
elif 'QQ' in name or 'qq' in name:
win32api.ShellExecute(0, 'open', r'D:\App\QQ\Bin\QQScLauncher.exe', '', '', 1) # 打开QQ
elif '微信' in name:
win32api.ShellExecute(0, 'open', r'D:\App\WeChat\WeChat.exe', '', '', 1) # 打开微信
else:
data_dict = {
"reqType":0,
"perception": {
"inputText": {
"text": data
},
},
"userInfo": {
"apiKey": api_key,
"userId": "!!!你自己的userId!!! "
}
}
result = requests.post(urls, json=data_dict)
content = (result.content).decode('utf-8')
# print(content)
ans = json.loads(content)
text = ans['results'][0]['values']['text']
print('Niubility:',text)
speak_(text)
if __name__ == '__main__':
print('Niubility:', prologue)
speak_(prologue)
print('{}//你:按 空格 键开始说话...'.format(count), end=' ')
t1 = threading.Thread(target=check_input,args=()) # 监听键盘
t1.start()
while 1:
if run is True:
print('\r{}//你:正在听呢,说完了请再按 空格 键...'.format(count), end=' ')
recoder()
text2 = lic()
print('\r{}//你:'.format(count),text2)
respond(text2)
count += 1
print('{}//你:按 空格 键开始说话...'.format(count), end=' ')