使用Python把树莓派改造成一个语音助手
对博客平台有些失望,转语雀只当留档用了。
语音助手已经不是什么新事物了。就在两三年前,语音助手的使用体验还不是那么好,尝尝鲜后也就没用过了。但最近发现不管是微软的Cortana、苹果的Siri,还是一些不怎么有名气的,例如MIUI的小爱同学等,使用体验真的改善了很多,确确实实能带来一些方便了。
随着各种云服务、API的面世,语音方面的云服务可以说是十分健全了。你是否也想过自己动手搭建一个语音助手系统呢?本文将总结使用Python把树莓派(3代b型)改造成一个简易语音助手的基本流程。
概述
这次要做的说白了,就是把各种云服务、API串起来,并不涉及任何核心技术、算法的实现,望知悉。
这次将要使用到的服务包括:
为了实现这个语音助手系统,需要完成的工作每一个都不难,但数量稍多了些。以下是涉及到的一些博客:
后文在介绍各部分的具体实现时,只附上代码和进行一些必要的说明,详细内容还需要参考相应博客。
各部分的实现
由于整个项目用到的服务比较多,而且各部分的分工很明显,所以选择各部分分别用一个python程序来实现,最后再用一个程序整合在一起的方式。
录音
笔者采用了“按住按钮进行录音”的操作方式,如下图所示接线。如果你手头上没有按钮或觉得这么做不方便,可以修改代码改成“按回车键开始/结束录音”之类的操作方式。
另外,树莓派的板载3.5mm耳机接口是不带语音输入功能的,所以你需要另外购买USB声卡。
* 文件 rec.py
import RPi.GPIO as GPIO
import pyaudio
import wave
import os
import sys
def rec_fun():
# 隐藏错误消息,因为会有一堆ALSA和JACK错误消息,但其实能正常录音
os.close(sys.stderr.fileno())
BUTT = 26 # 开始录音的按钮:一边接GPIO26,一边接地
GPIO.setmode(GPIO.BCM)
# 设GPIO26脚为输入脚,电平拉高,也就是说26脚一旦读到低电平,说明按了按钮
GPIO.setup(BUTT, GPIO.IN, pull_up_down = GPIO.PUD_UP)
# wav文件是由若干个CHUNK组成的,CHUNK我们就理解成数据包或者数据片段。
CHUNK = 512
FORMAT = pyaudio.paInt16 # pyaudio.paInt16表示我们使用量化位数 16位来进行录音
RATE = 44100 # 采样率 44.1k,每秒采样44100个点。
WAVE_OUTPUT_FILENAME = "/home/pi/chat/command.wav"
print('请按住按钮开始录音...')
GPIO.wait_for_edge(BUTT, GPIO.FALLING)
# To use PyAudio, first instantiate PyAudio using pyaudio.PyAudio(), which sets up the portaudio system.
p = pyaudio.PyAudio()
stream = p.open(format = FORMAT,
channels = 1, # cloud speecAPI只支持单声道
rate = RATE,
input = True,
frames_per_buffer = CHUNK)
print("录音中...")
frames = []
# 按住按钮录音,放开时结束
while GPIO.input(BUTT) == 0:
data = stream.read(CHUNK)
frames.append(data)
print("录音完成,输出文件:" + WAVE_OUTPUT_FILENAME + ' ')
stream.stop_stream()
stream.close()
p.terminate()
wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
wf.setnchannels(1)
wf.setsampwidth(p.get_sample_size(FORMAT)) # Returns the size (in bytes) for the specified sample format.
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
return
# 可以直接运行rec.py进行测试,同时保证该文件import时不会自动运行
if __name__ == '__main__':
rec_fun()
语音识别
参考:
由于某些原因,笔者选择了使用谷歌Cloud Speech API进行语音识别。既然要用谷歌的服务,自然就涉及到了科学上网、代理、谷歌云平台的使用,如果不想这么折腾,完全可以用国内的讯飞、百度来实现。
另外,API KEY之类的字符串在这里删除了,还请麻烦修改代码加上你自己申请的API KEY。
* 文件 speech_api.py
import json
import urllib.request
import base64
def wav_to_text():
api_url = "https://speech.googleapis.com/v1beta1/speech:syncrecognize?key=替换成你的API密钥"
print('语音文件编码中...')
audio_file = open('/home/pi/chat/command.wav', 'rb')
audio_b64str = (base64.b64encode(audio_file.read())).decode()
audio_file.close()
voice = {
"config":
{
"languageCode": "cmn-Hans-CN"
},
"audio":
{
"content": audio_b64str
}
}
voice = json.dumps(voice).encode('utf8')
print('编码完成。正在上传语音...')
req = urllib.request.Request(api_url, data=voice, headers={'content-type': 'application/json'})
response = urllib.request.urlopen(req)
response_str = response.read().decode('utf8')
response_dic = json.loads(response_str)
if ('results' not in response_dic.keys()):
print('您录制的文件似乎没有声音,请检查麦克风。')
return
transcript = response_dic['results'][0]['alternatives'][0]['transcript']
confidence = response_dic['results'][0]['alternatives'][0]['confidence']
result_dic = {'text':transcript ,'confidence':confidence}
print('识别完成。以字典格式输出:')
print(result_dic)
return result_dic
if __name__ == '__main__':
wav_to_text()
获取文字回答
这个获取回答的程序有些粗糙,只能获得普通的文字回答。实际上图灵机器人回复的内容中包括了文字、问题类型甚至情感等信息,还有很多修改的空间。
* 文件 turing.py
import json
import urllib.request
def chat(question):
api_url = "http://openapi.tuling123.com/openapi/api/v2"
text_input = question['text']
req = {
"perception":
{
"inputText":
{
"text": text_input
},
"selfInfo":
{
"location":
{
"city": "上海",
"province": "上海",
"street": "文汇路"
}
}
},
"userInfo":
{
"apiKey": "替换成你的APIKEY",
"userId": "用户参数"
}
}
# 将字典格式的req转为utf8编码的字符串
req = json.dumps(req).encode('utf8')
print(' ' + '正在调用图灵机器人API...')
http_post = urllib.request.Request(api_url, data=req, headers={'content-type': 'application/json'})
response = urllib.request.urlopen(http_post)
print('得到回答,输出为字典格式:')
response_str = response.read().decode('utf8')
response_dic = json.loads(response_str)
intent_code = response_dic['intent']['code']
# 返回网页类的输出方式
if(intent_code == 10023):
results_url = response_dic['results'][0]['values']['url']
results_text = response_dic['results'][1]['values']['text']
answer = {"code": intent_code, "text": results_text, "url":results_url}
print(answer)
return(answer)
# 一般的输出方式
else:
results_text = response_dic['results'][0]['values']['text']
answer = {"code": intent_code, "text": results_text}
print(answer)
return(answer)
if __name__ == '__main__':
eg_question = {'text': '今天是几号', 'confidence': 0.9}
chat(eg_question)
读出回答(语音合成)
笔者在使用讯飞Web API时,该服务才开放不到一周,难免以后该API会有所变动,如有问题建议查阅官方文档。
* 文件 tts.py
import base64
import json
import time
import hashlib
import urllib.request
import urllib.parse
import os
def speak(text_content):
# API请求地址、API KEY、APP ID等参数,提前填好备用
api_url = "http://api.xfyun.cn/v1/service/v1/tts"
API_KEY = "替换成你的APIKEY"
APP_ID = "替换成你的APPID"
AUE = "lame"
# 构造输出音频配置参数
Param = {
"auf": "audio/L16;rate=16000", #音频采样率
"aue": AUE, #音频编码,raw(生成wav)或lame(生成mp3)
"voice_name": "xiaoyan",
"speed": "50", #语速[0,100]
"volume": "10", #音量[0,100]
"pitch": "50", #音高[0,100]
"engine_type": "aisound" #引擎类型。aisound(普通效果),intp65(中文),intp65_en(英文)
}
# 配置参数编码为base64字符串,过程:字典→明文字符串→utf8编码→base64(bytes)→base64字符串
Param_str = json.dumps(Param) #得到明文字符串
Param_utf8 = Param_str.encode('utf8') #得到utf8编码(bytes类型)
Param_b64 = base64.b64encode(Param_utf8) #得到base64编码(bytes类型)
Param_b64str = Param_b64.decode('utf8') #得到base64字符串
# 构造HTTP请求的头部
time_now = str(int(time.time()))
checksum = (API_KEY + time_now + Param_b64str).encode('utf8')
checksum_md5 = hashlib.md5(checksum).hexdigest()
header = {
"X-Appid": APP_ID,
"X-CurTime": time_now,
"X-Param": Param_b64str,
"X-CheckSum": checksum_md5
}
# 构造HTTP请求Body
body = {
"text": text_content
}
body_urlencode = urllib.parse.urlencode(body)
body_utf8 = body_urlencode.encode('utf8')
# 发送HTTP POST请求
print(' ' + "正在调用科大讯飞语音合成API...")
req = urllib.request.Request(api_url, data=body_utf8, headers=header)
response = urllib.request.urlopen(req)
# 读取结果
response_head = response.headers['Content-Type']
if(response_head == "audio/mpeg"):
out_file = open('/home/pi/chat/answer.mp3', 'wb')
data = response.read() # a `bytes` object
out_file.write(data)
out_file.close()
print('得到结果,输出文件: /home/pi/chat/answer.mp3')
else:
print(response.read().decode('utf8'))
# 播放音频
print("播放音频中...")
print("以下均为mplayer的输出内容 ")
os.system("mplayer -ao alsa:device=hw=1.0 /home/pi/chat/answer.mp3")
return
if __name__ == '__main__':
eg_text_content = "苟利国家生死以,岂因祸福避趋之"
speak(eg_text_content)
整合&测试
现在,你的项目文件夹中应该有这些python代码文件:
接下来我们只需要将他们整合在一起运行。
* 文件 combine.py
# 这些import进来的模块是同目录下的py文件
import rec # rec.py负责录制wav音频
import speech_api # speech_api.py负责wav转文字
import turing # turing.py负责获得图灵机器人的文字回答
import tts # tts.py负责读出回答
rec.rec_fun() # 录制音频
recognize_result = speech_api.wav_to_text() # 识别语音,返回值是字典格式,包含文字结果和信心
turing_answer = turing.chat(recognize_result) # 得到图灵的回答,返回值仍是字典格式
tts.speak(turing_answer['text'])
如果一切顺利的话,实际运行效果如下:
树莓派_语音助手_youku
小结
语音助手这边的工作算是告一段落了,结果小结却不知道怎么写了。不管怎么说,很开心最后能得到实际的结果,做的过程中也有一些脑洞想要继续扩展,过段时间应该还会继续!
做这个项目的过程中,项目外的收获或许比这个项目本身还要多。这段时间从很多博客、论坛得到了数不尽的帮助,国内的、国外的、中文的、英文的、日文的都有,深深地感受到了互联网共享精神的力量,这也是促使我开始写这些文章的原因。那么,最后还是说一句:感谢你阅读文章!
使用Python把树莓派改造成一个语音助手相关推荐
- 如何用树莓派做一个家庭语音助手/智能音箱
一.前言 这学期闲来无事,于是搞了个简单的家庭语音助手,其主要实现的功能有: 语音唤醒: 控制家电: 询问时间和日期: 询问天气情况: 查询垃圾分类: 播报新闻: 微信小程序远程控制 以下是为实现上述 ...
- Python构建您自己的交互式语音助手 Voice Assistant with Python – Alexa Clone
构建您自己的交互式语音助手 你会学到: 构建虚拟助理 使用API 根据个人需求修改语音助手 Python编程 MP4 |视频:h264,1280×720 |音频:AAC,44.1 KHz,2 Ch 语 ...
- 爆肝一周,用Python在物联网设备上写了个智能语音助手-阿里云智能语音交互
基于HaaS云端一体框架,用Python打造HaaS EDU K1智能语音助手的过程中需要用到云端能力.本篇文章介绍如何开通阿里云智能语音交互,并创建配置语音识别及语音合成项目,获取Appkey.请参 ...
- 语音库构建_在10分钟内构建一个多功能语音助手
语音库构建 Nowadays people don't have time to manually search the internet for information or the answers ...
- 单片机学习:第一篇 基于Python的树莓派语音助手
title: 单片机学习:第一篇 基于Python的树莓派语音助手 tags: 树莓派,python,语音助手,百度AIP 目录 一.pyaudio录音 二.语音识别 三.与图灵机器人对话 四.语音合 ...
- 【小白教程】基于树莓派的智能语音助手-python
[完整教程零基础]基于树莓派的智能语音助手-python 树莓派3b+.python3系统自带.百度语音识别与合成.调用图灵机器人(热词唤醒失败,可用snowboy) 1.Windows系统下[下载+ ...
- python语音控制智能家电_基于树莓派的智能家居语音控制系统
2018-10 基于树莓派的智能家居语音控制系统 Intelligent home voice control system based on raspberry Pi 刘 华 , 田占生 , 冯宇飞 ...
- python控制小爱同学_神秘鸭,用Siri小爱同学语音助手控制你的电脑
智能手机发展至今,智能可不仅是改变了沟通和上网形式,依据强大的算法核心,各种基于AI的智能语音助手屡见不鲜,其中苹果的Siri.小米的小爱同学.阿里的天猫精灵,极受欢迎.虽说现在的人工智能语音助手,仍 ...
- 在树莓派上定时播放语音
在树莓派上定时播放语音的原因是家里的小朋友早上起床和出门拖延严重,另外有的时候忘记看天气预报带雨伞. 树莓派的好处是耗电少,环保一些.也确实不会因为要做个提醒的功能一直开着电脑.实际上家里的电脑还真是 ...
最新文章
- 达摩院实现自动驾驶核心技术突破,达摩院首次实现3D物体检测精度与速度的兼得
- 设计模式之工厂类模式总结对比、简单工厂模式、工厂方法模式、抽象工厂模式、带反射的工厂模式、例子代码分析、最详细
- 【Python-ML】神经网络-Theano张量库(GPU版的Numpy)
- python语音控制智能家电_Python 树莓派智能音箱语音控制电脑开关机-Python 实用宝典...
- 马云:我不懂技术但欣赏技术 达摩院必须超越微软 - 20171011
- Qt入门(3)——信号和槽
- iOS中如何监测来电
- 服务器无法在发送 http 标头之后设置内容类型。_python socket编程预知内容
- 迅雷使用积分制的真正作用和目的 [揭密迅雷]
- 004:2的幂次方表示
- cookie 和session
- Android .apk逆向工程(安装篇):如何正确使用dex2jar
- 参数整定类毕业论文文献有哪些?
- Kubernetes Dashboard 终结者:KubeSphere
- java约等于符号_markdown常见数学符号和运算
- 网络抓包与HTTP协议(采用wireshark、Fiddler抓包软件)
- 关于Windows系统脚本(jscript)
- CYUSB3014设计方案|替代CYUSB3014芯片|方寸微T630可完全替代兼容CYPRESS CYUSB3014
- 一个用于网络摄像机的开源软件 --- mjpg-streamer
- HTML导出PDF有边框,使用jspdf导出的pdf的页面边框
热门文章
- 《DSP using MATLAB》示例Example 8.5
- 0x01第一个汇编程序
- [转]Kali-linux安装之后的简单设置
- VC++实现全局钩子勾住消息对话框
- HDU1492 The number of divisors(约数) about Humble Numbers【约数】
- Vijos P1974 金币【数列】
- CCF201503-5 最小花费(30分)
- GAN(Generative Adversarial Networks) 初步
- 算法 Tricks(四)—— 判断序列中的字符/数值是否交替出现
- 强悍的 vim 实用功能