在之前的一篇文章中,开发了一款爬取租房信息的工具,文章链接如下:
制作简易python爬虫工具——爬取租房信息(界面搭建->功能实现->数据抓取)一步到位
之后我觉得显示信息是一方面,能语音播报的话感觉更好,因此在原来的基础上添加了语音播放的功能,正好以此功能为案例详细讲解一下怎么去根据信息合成语音以及怎么播报
文章目录
一、创建应用
首先登录百度智能云的平台,找到相应的语音技术应用,使用在线语音合成的应用进行创建
创建好应用之后,会获得平台分配的AppID、APIKey、SecretKey
拿到这些之后我们就可以参考技术文档去合成语音文件了
二、进入python SDK接入文档
进入技术文档当中之后我们要创建一个AipSpeech的客户端
创建的过程当中我们要传输获取到的AppID、APIKey、SecretKey用于标识用户,为访问做签名验证,这几个量均为字符串
创建client的参考代码如下
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)
如果说想要配置AipSpeech的网络请求参数,可以在构造AipSpeech之后调用接口设置参数,目前只支持以下参数:
接口 | 说明 |
---|---|
setConnectionTimeoutInMillis | 建立连接的超时时间(单位:毫秒 ) |
setSocketTimeoutInMillis | 通过打开的连接传输数据的超时时间(单位:毫秒) |
创建好client之后就可以开始合成语音了
在合成语音的时候有一个注意事项
即:合成文本长度必须小于1024字节,如果本文长度较长,可以采用多次请求的方式。文本长度不可超过限制
那么在这的话可以参考以下内容:
client调用synthesis方法合成相应的语音文件,在使用过程当中可以根据下面的参数进行适当的调整
如果可以正确合成语音,那么将语音文件以二进制的形式写入文件,否则返回dict
result = client.synthesis('你好百度', 'zh', 1, {
'vol': 5,
})
# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
with open('audio.mp3', 'wb') as f:
f.write(result)
参数 | 类型 | 描述 | 是否必须 |
---|---|---|---|
tex | String | 合成的文本,使用UTF-8编码, 请注意文本长度必须小于1024字节 | 是 |
cuid | String | 用户唯一标识,用来区分用户, 填写机器 MAC 地址或 IMEI 码,长度为60以内 | 否 |
spd | String | 语速,取值0-9,默认为5中语速 | 否 |
pit | String | 音调,取值0-9,默认为5中语调 | 否 |
vol | String | 音量,取值0-15,默认为5中音量 | 否 |
per | String | 发音人选择, 0为女声,1为男声, 3为情感合成-度逍遥,4为情感合成-度丫丫,默认为普通女 | 否 |
三、播放合成的语音文件
播放音频文件就比较简单了,可以使用pygame模块中自带的内容
1、先加载音频文件
pygame.mixer.music.load(filename or object)
2、播放音频文件
pygame.mixer.music.play()
四、将功能加入项目
在之前的项目当中,主要显示信息的界面有两个一个是二级界面,一个是三级界面,在这两个界面当中都加入语音播放的功能
需求提出来了之后,逐步开始准备解决方案
首要解决的是要先把模块下载安装一下
当我去DOS里面安装的时候发现报错:Fatal error in launcher: Unable to create process using ‘"’
这种情况的出现时,可以升级一下pip工具python -m pip install --upgrade pip
然后正常安装模块即可:pip install baidu-aip
如果已经有了,那么在pycharm里面导入一下即可
安装成功之后就可以开始写了
考虑到在合成文件的时候以及在处理语音文件时要产生多个语音文件,并要处理爬取的数据,以便更好地合成语音文件,需要加入以下模块
import pygame
from aip import AipSpeech
import re
import random
五、index1.py代码编写
首先第一步的是要将语音文件合成出来
1、创建client
client的创建是非常简单的,根据手册里面的指导,将创建好的应用加入代码当中调用AipSpeech即可,为了方便起见,我把合成语音文件的操作封装在了一个函数当中
def play_house_info():
global audioName
# 语音合成
APP_ID = '百度智能云分配的ID'
API_KEY = '分配的api_key'
SECRET_KEY = '分配的secret_key'
# 创建client
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
创建好之后就可以开始合成语音文件了,这个时候需要client调用专门的systhesis方法进行处理
2、合成语音文件
合成语音文件时,要求语音播报的语速、语调、音量大小、男女声音等的设置可以根据表格当中提供的参数去增减
audioName = 'audio/audio_info%s.mp3'%random.randint(1, 100)
# 合成语音文件
result_audio = client.synthesis(res_info, 'zh', 1, {'vol': 5, 'per': 3, 'spd': 3})
print(result_audio)
if not isinstance(result_audio, dict):
with open(audioName, 'wb') as f:
f.write(result_audio)
但是在合成语音文件之前我漏掉了一个很严重的问题
根据实际的需要我得把要播报的信息处理一下,首先是在原来index1.py文件当中要展示房屋信息的函数体draw_house_info内,要把信息获取好,整合之后为了方便处理将其写入文件
因为我们要做到去访问某一条数据的时候就播报某一条的数据,所以说它的信息获取是要经过控制的
# 语音播报的信息
info_play = str(totalInfo[choice][I.i]['house_name']) + str(totalInfo[choice][I.i]['house_info']) + str(totalInfo[choice][I.i]['house_price'])
with open('audio/info_play.txt', 'w', encoding = 'utf-8') as f:
f.write(info_play)
但是写入这个文件之后我们发现获取到的数据中实际上是有一些杂质的,比如说下图当中的数据里面有:· - / ()这些符号,这些符号在合成语音文件的时候是识别不了的,所以说要将这个字符串里面的这些特殊符号给它去掉,如果不加以处理就直接读取info_play.txt里面的内容进行合成的话,是100%失败的
这也是为什么我在合成语音文件的时候始终是调用失败的,而且在控制台的报错信息当中我也找不出到底是哪的逻辑出现了问题
问题解决了之后,就可以开始处理文件当中的字符串数据了,根据自己的需要可以选择在写入文件前处理,也可以在写入文件后处理,甚至可以不需要读写文件,直接变量传参即可,我当时读写文件的时候就是为了排查问题的原因而已
解决之后的代码如下:
with open(r'audio\info_play.txt', 'r', encoding='utf-8') as f:
msg = f.read()
res = re.split('·|-|/|(|)| ', msg)
res_info = ''.join([i for i in res if i != None])
那么问题来了,在处理字符串数据的时候可能第一时间想到的就是调用split()和join()来进行数据的分割及整合,但是内置的str.split()无法满足多个分隔符的处理,每次调用的时候只能传入一个参数,那这样的话数据处理就会很麻烦,两个方法可以解决:
1、使用正则表达式,用正则去匹配多个要分割的字符;
2、调用re模块里面的split()方法体当中使用 | 进行分割符的间隔
一般的初学者可能不太懂正则的匹配规则,也无法熟练运用,所以在这我就直接用了re模块里面的split(),之后的文章再去做正则的详解
处理好之后就整个的方法就完成了90%,最后将合成的音频文件进行一个加载和播放即可
def play_house_info():
global audioName
# 语音合成
APP_ID = '平台的app_id'
API_KEY = '平台的api_key'
SECRET_KEY = '平台的secret_key'
# 创建client
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
with open(r'audio\info_play.txt', 'r', encoding='utf-8') as f:
msg = f.read()
res = re.split('·|-|/|(|)| ', msg)
res_info = ''.join([i for i in res if i != None])
print(res_info)
audioName = 'audio/audio_info%s.mp3'%random.randint(1, 100)
# 合成语音文件
result_audio = client.synthesis(res_info, 'zh', 1, {'vol': 5, 'per': 3, 'spd': 3})
print(result_audio)
if not isinstance(result_audio, dict):
with open(audioName, 'wb') as f:
f.write(result_audio)
3、播放语音
语音播放的功能可以直接通过pygame模块里面的mixer.music即可,首先需要先进行语音文件的加载,然后在调用专门的播放按钮进行播放,由于每一条的信息播放一次即可,所以不用设置多次播放的功能
1、加载音频文件
pygame.mixer.music.load(audioName)
2、播放音频
pygame.mixer.music.play() # 无参调用即可
4、绘制播放按钮
播放按钮的绘制就比较容易了,按照之前的套路,加载图片、设置按钮属性、放置按钮
一定要记得进行command的设置,否则按钮和函数之间会没有联系
# 绘制播放按钮
play = ImageTk.PhotoImage(file = 'images/play.jpg')
playBtn = tk.Button(window, image = play, width = 100, height = 100, command = play_house_info)
playBtn.place(x = 0, y = 400)
六、index2.py代码编写
三级界面的代码编写和二级界面的内容是一致的,放置的地方也是一致,但是一个问题是三级界面的信息和二级界面的信息是不同的,所以在数据的处理上会不同
1、数据整合
将其写入文件当中
house_info = '面积:'+info['面积']+'朝向:'+info['朝向']+'维护:'+info['维护']+'入住:'+info['入住']+'楼层:'+info['楼层']+'电梯:'+info['电梯']+ \
'车位:' + info['车位']+'用水:'+info['用水']+'用电:'+info['用电']+'燃气:'+info['燃气']+'采暖:'+info['采暖']+'租期:'+info['租期']+'看房:'+info['看房']
with open('audio/house_info.txt', 'w', encoding = 'utf-8') as f:
f.write(house_info)
当然这些内容是完全可以进行一个再次的优化的,大家可以在这个基础上进行补充
数据整合好之后,还是沿用二级界面合成语音的操作即可
2、语音合成及播放
由于两个界面的信息不同,所以说不能共用一个音频文件
def play_house_info():
global audioName
# 语音合成
APP_ID = '平台的app_id'
API_KEY = '平台的api_key'
SECRET_KEY = '平台的secret_key'
# 创建client
client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
with open('audio/house_info.txt','r', encoding='utf-8') as f:
msg = f.read()
audioName = 'audio/audio_info_num%s.mp3'%random.randint(1, 100)
# 合成语音文件
result_audio = client.synthesis(msg, 'zh', 1, {'vol': 5, 'per': 3, 'spd': 3})
print(result_audio)
if not isinstance(result_audio, dict):
with open(audioName, 'wb') as f:
f.write(result_audio)
pygame.mixer.music.load(audioName)
pygame.mixer.music.play()
七、效果
由于上传文件受限制,所以合成的众多音频文件没有办法直接上传到这上面,如果大家感兴趣,可以私信我,发音的参数可以通过per的值去做调整,根据自己的情况去进行设置