20202418于宗源 2021-2022-2 《Python程序设计》综合实践报告
一、实验要求
Python综合应用:爬虫、数据处理、可视化、机器学习、神经网络、游戏、网络安全等。
课代表和各小组负责人收集作业(源代码、视频、综合实践报告)
二、实验内容
基于百度智能云与tkinter可视化组件的语音合成系统
三、实验过程
(一)想法来源
在和同学们的交流过程中,我偶然得知在百度智能云上提供python专用的语音合成、语音识别等多种功能的SDK。而且最近百度智能云还有活动,可以免费提供50000+20000次的文件调用,于是我便想利用tkinter可视化组件,打造一个可以调声音大小、声音音调、说话速度、声音类型,文本信息支持文档读取与直接输入,生成文件可以自行输入名称,并同时可以指定目录。
(二)代码实现过程
1、main类的建立
为了保证代码的简洁性,我们的主类十分简单,只有两行代码:
import display
dis = display.display()
其中display类是我基于百度智能云aip模块建造的类文件。
2、display类的建立
这一类的主要功能为可视化组件的创建,能够接收用户在特定输入框输入的内容,同时,能够将输入的内容传送到sound类中去。
在这个可视化界面的创作过程中,我一共运用到了11个输入框,9个标签,四个单选按钮,以及一个按钮组件。并将其整齐排布,形成一个美观的界面,如图所示。
类中的属性有:
speed = 5
sound_type = 0
volume = 5
pit = 5
file_way = ""
file_name = ""
flag = -1
be_read = ""
APP_ID = ""
API_KEY = ""
SECRET_KEY = ""
flag1 = -1
其中比较重要的方法有:
1、create_mainloop():
它包含了多个可视化组件,并将其合理的排布在整个页面中。
通过这个方法,即实现了所有的可视化组件的产生,也提供了数据读入的功能,并将这个页面展示给我们。
def create_mainloop(self):
window = Tk()
window.title("主界面")
window.geometry("1150x490")
lb1 = Label(text="请输入你想要的语速:(0-10越来越快)",font=("仿宋",18))
lb1.place(x=30,y=30)
en1 = Entry(window, highlightcolor='black')
en1.place(x=30, y=60, height=35, width=200)
lb2 = Label(text="请输入你想要的声音大小:(0-10越来越大)", font=("仿宋", 18))
lb2.place(x=30, y=100)
en2 = Entry(window, highlightcolor='yellow', relief="groove")
en2.place(x=30, y=130, height=35, width=200)
lb3 = Label(text="请输入你想要的声音类型:", font=("仿宋", 18))
lb3.place(x=30, y=170)
en3 = Entry(window, highlightcolor='yellow', relief="groove")
en3.place(x=30, y=200, height=35, width=200)
lb4 = Label(text="请输入你想要的音调:(0-10越来越高)", font=("仿宋", 18))
lb4.place(x=30, y=240)
en4 = Entry(window, highlightcolor='yellow', relief="groove")
en4.place(x=30, y=270, height=35, width=200)
lb6 = Label(text="请输入音频文件名称(示例:音频文件A)", font=("仿宋", 18))
lb6.place(x=30, y=310)
en6 = Entry(window, highlightcolor='yellow', relief="groove")
en6.place(x=30, y=340, height=35, width=200)
lb7 = Label(text="声音类型如下\n"
"普通机器女声A:0 普通机器男声A:1\n"
"普通机器男声B:3 机器萝莉声:4\n"
"机器机器女声B:5 可爱女生:103\n"
"充满智慧的男性:106 女小学生:110\n"
"甜美女生:111 还原度比较高的男声:5003\n"
" 还原度高的女声:5118\n"
,font=("黑体",12))
lb7.place(x=650,y=280)
lb8 = Label(text="",font=("黑体",12))
lb5 = Label(text="请输入你想要将音频文件保存路径(示例:D://python//music)", font=("仿宋", 16))
en5 = Entry(window, highlightcolor='yellow', relief="groove")
no = Radiobutton(window, text="保存音频到指定目录", value=0, variable=1, command=lambda: [display.flag_set0(self, en5=en5, lb5=lb5)])
yes = Radiobutton(window, text="保存音频到当下目录", value=1, variable=1 ,command=lambda: [display.flag_set1(self, en5=en5, lb5=lb5)])
yes.place(x=30, y=400)
no.place(x=30, y=430)
lb7 = Label(text="请输入你的APP_ID:",font=("仿宋", 13))
lb7.place(x=600,y=30)
en7 = Entry(window, highlightcolor='yellow')
en7.place(x=770, y=30, width=250)
lb8 = Label(text="请输入你的API_KEY:", font=("仿宋", 13))
lb8.place(x=600, y=60)
en8 = Entry(window)
en8.place(x=770, y=60, width=250)
lb9 = Label(text="请输入你的SECRET_KEY:",font=("仿宋", 13))
lb9.place(x=600, y=90)
en11 = Entry(window)
en11.place(x=800,y=90, width=250)
en9 = Entry(window)
bu5 = Button(window, text="确定啦!", height=1, width=10, font="黑体",
command=lambda: [display.button_set_pit(self, en4), display.button_set_type(self, en3),
display.button_set_speed(self, en1), display.button_set_volume(self, en2),
display.button_set_fileway(self, en5), display.button_set_filename(self, en6),
display.read_inget(self,en9), display.register(self,en7,en8,en11),
display.connect(self)])
bu5.place(x=600, y=230)
no1 = Radiobutton(window, text="导入转换内容", value=0, variable=2,
command=display.set_modle2(self))
no1.place(x=600, y=180)
yes1 = Radiobutton(window, text="输入转换内容", value=1, variable=2,command=lambda:[display.set_modle1(self)])
yes1.place(x=600,y=150)
en9.place(x=720, y=160, width=350, height=40)
window.mainloop()
2、connect()方法
这个方法就比较简单了,在create_mainloop():实现后,类中的各个属性都已经被读取了,也就是想要的音调、音色、声音类型、文件名称与位置都已经读好了,那么此时我们使用connect方法构建display和sound的连接桥梁。
so = sound.sound(self.speed, self.sound_type, self.volume, self.pit, self.file_name, self.file_way, self.be_read, self.APP_ID, self.API_KEY, self.SECRET_KEY)
3、sound类的建立
这个类的主要功能就是接收display类的参数,并且依据参数与百度智能库进行连接,并将得到的结果保存在文件中。
代码如下
class sound:
client = AipSpeech('', '', '')
def new_client(self, APP_ID, API_KEY, SECRET_KEY):
self.client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
def __init__(self, speed, sound_type, volume, pit, file_name, file_way, be_read, APP_ID, AIP_KEY, SECRET_KEY):
sound.new_client(self, APP_ID, AIP_KEY, SECRET_KEY)
result = self.client.synthesis(be_read, 'zh', 1,
{'vol': volume, 'spd': speed, 'pit': pit, 'per': sound_type})
if not isinstance(result, dict):
file = open(file_way + file_name + ".mp3", "wb")
file.write(result)
file.close()
else:
print("出错了哦\n")
由图可知,如果当用户选择将文件保存在当下路径中,那么我的file_way为将会是空值,那么在open里面file_way + file_name内容将仅仅只有非常file_name,那么python就会自动将路径转化成代码所在位置。如果正常工作的话,返回的就是一个音频文件,同时会将其保存在file_way + file_name中。如果返回的不是音频文件而是个数组的话,那么就会显示出错了。
四、使用说明
如图所示,在对应的输入框根据你的想法与喜好输入对应的数字即可。同时选择是保存在当下目录还是保存在指定目录中,是要自己写入转换内容还是从其他文件中读取。在右下角还有声音类型,有很多种声音类型,用户可以根据自己的癖好输入对应的数字。
我们来看一个例子
我们选择了将文件保存在指定目录中,并选择从一个txt文档中读入内容。
点击确定啦!之后,就可以发现在对应的文件位置和生成了对应名称的mp3文件。
然后我们来听一下(我突然发我不会在博客园中放音频文件/捂脸笑)但是确实是哈,可以拿我的代码去尝试一下。
五、华为云实验
(一)将代码移植至对应的目录中去
这里我们使用到了winscp软件,输入对应的ip和密码即可登录:
(二)配置Xming
我们为什么要配置xming呢?原因很简单就是linux里面没有可视化的桌面,全是命令行,那我这个tkinter组件就全部不能使用了,如图所示:
刚开始做到这里我的心态就崩了,我就想完了,我好像要改选题了,我忘记了全是命令行了。
我第一次想到的解决方法是在华为云远程登陆中下载一个可视化桌面:
然后我参考了好多资料,尝试了安装gnome桌面、安装深度开发的桌面dde或者安装优麒麟开发的桌面UKUI。都失败了!每一次安装后重启都还是这命令行。我感觉我要完了。
绝地仍有生机,死战或可破敌!
后来和同学讨论中得知还有个好东西叫xming,他能够直接把云端服务篇的可视化组件运行到windows中,于是我赶紧去了解了一下这个软件。
这边我参考的是https://www.bilibili.com/video/BV1ga4y1x7xM?spm_id_from=333.337.search-card.all.click中的第一个方法。
下载好xming要配置相关的设置,在视频中均有提到。先打开xming,然后打开putty,要记得把X11选择选中
成功打开了!
命运给我开了个大大的玩笑,居然全是乱码!!!我感觉我这次实践作业又要凉了
(三)中文字符集的导入
刚开始解决问题的时候,我误以为是xming显示的问题,在网上寻到了这样的解决方法:
然后我试了不行,还是一个个小框框。
后来和同学讨论过程中,发现别人也和我有一样的问题,但是他说一句话点醒了我。
“好像不是xming的问题”
欸确实,怪不得在网上找不到xming中文显示乱码的解决方法,于是我搜索linux中文显示乱码的解决方法。
终于!功夫不负有心人!!我找到了解决方法,原来是linux系统没有中文的字符集,导致我文件中的中文在linux系统里面本来就是一个个小框框。我输入代码:sudo yum -y groupinstall fonts
终于!一个能够正常显示的gui页面向我呈现了出来!!
(四)功能测试
我们还是以那个为例,但是路径需要稍微修改一下,毕竟linux没有什么C盘或者D盘。
这里我们选择的默认放在当下路径,转换内容是自行输入的,可以看到对应的目录成功出现了一个音频文件!
拖过来并播放后发现确实和我想要的结果一样:
指定路径也能够完美运行。
至此,我的python实践作业到此结束。
六、反思与不足
1、面对对象思维不深刻,代码非常冗余
比如在display中,有大量的重复语句
lb1 = Label(text="请输入你想要的语速:(0-10越来越快)",font=("仿宋",18))
lb1.place(x=30,y=30)
en1 = Entry(window, highlightcolor='black')
en1.place(x=30, y=60, height=35, width=200)
这么麻烦我当时为什么不直接定义一个方法呢?一个方法可以创建标签并且同时生成输入框,其中形参有text内容,window以及x和y,返回值为en这样子的话岂不是后面所有的和这四条语句类似的指令都能够通过这个方法实现了吗?这是我写完代码之后才意识到的,说明我面对对象的思维非常浅薄,没有利用好这个思想和python的特点。
2、缺少输入检测与错误提示机制
一个好用的程序必须要有输入检测和错误信息提示,利用try-else语句就可以完美的实现这个功能,但是由于时间紧张,我没有添加这个功能,如果等一会我把其他科目的ddl赶完后,我想要利用try-else语句弄一个错误信息提示窗口,一旦有错误出现就会出现一个messagebox,上面写了错误的位置。
七、实验中遇见的问题
(一)在实验中xming无法正常显示中文字符
在putty中输入:sudo yum -y groupinstall fonts 安装中文字符即可
(二)在button组件中,command=后面只能跟一个函数而且函数不允许有形参
利用command = lambda: [函数名(形参1,形参2,形参3······)]
(三)同类中方法的相互调用
只需要在一个方法中这么引用另一个方法:
类名.方法名(形参·····)
即可实现方法的相互调用
八、结课感想与体会
在选修课报名之前,我问过一个学长:“王志强老师的python课怎么样呀,我有点想报这个课”。学长回答我:“如果你想要真的学东西的话,那么就可以选这个课。因为通过这个课你是真的能学到很多很多东西的。”所以我报名了王志强老师的python课。现在结课了,回想一下我确确实实通过这个课学习到了好多好多真的东西!在这十几周里面,我经历了三次实验,一次综合实践,在云班课中也有超级丰富的课下资料供我们学习。坦白来讲,在这个学期刚开始时我是无论如何都想象不到我还能自己做出来爬虫、网络连接传输还有可视化页面的。但是我一步一步走过来,把这些我本以为可望而不可即的东西都在老师的指导下实现出来了。在这一次综合实践中,当我点击运行的那一刻起,一个有序简介的文本语音转换器出现在了我的面前,在这一瞬间我感受到十分的骄傲与自豪。通过python课,我成功的做出来一个属于我自己的可视化软件。虽然中间有很多想要放弃的时刻,想着反正就十分要不然华为实验就这样半途而废吧,xming中文乱码在网上也没有教程要不然就这样吧。但是我还是没有放弃,终于在我的不懈努力之下我成功的完成综合实践。这个学期python选修课,我感觉到真的是十分充实,学到了好多好多知识。系统性的学习了python编程,感受到了它的便利,它的好处,他的许多优点。相信在今后的生活中,不论是大创,还是文件数据处理,还是爬虫,还是人类识别······python总会给我带来一个又一个惊喜,我和python也会有一个又一个的无约而至。
写在最后的是,Hello,world!十分感谢王老师,把我领到这个python的世界中!我以后一定要让这个工具在我的手中熠熠生辉!
附录
完整代码
main.py
import display
dis = display.display()
display.py
from tkinter import *
import sound
class display:
speed = 5
sound_type = 0
volume = 5
pit = 5
file_way = ""
file_name = ""
flag = -1
be_read = ""
APP_ID = ""
API_KEY = ""
SECRET_KEY = ""
flag1 = -1
def create_mainloop(self):
window = Tk()
window.title("主界面")
window.geometry("1150x490")
lb1 = Label(text="请输入你想要的语速:(0-10越来越快)", font=("仿宋", 18))
lb1.place(x=30, y=30)
en1 = Entry(window, highlightcolor='black')
en1.place(x=30, y=60, height=35, width=200)
lb2 = Label(text="请输入你想要的声音大小:(0-10越来越大)", font=("仿宋", 18))
lb2.place(x=30, y=100)
en2 = Entry(window, highlightcolor='yellow', relief="groove")
en2.place(x=30, y=130, height=35, width=200)
lb3 = Label(text="请输入你想要的声音类型:", font=("仿宋", 18))
lb3.place(x=30, y=170)
en3 = Entry(window, highlightcolor='yellow', relief="groove")
en3.place(x=30, y=200, height=35, width=200)
lb4 = Label(text="请输入你想要的音调:(0-10越来越高)", font=("仿宋", 18))
lb4.place(x=30, y=240)
en4 = Entry(window, highlightcolor='yellow', relief="groove")
en4.place(x=30, y=270, height=35, width=200)
lb6 = Label(text="请输入音频文件名称(示例:音频文件A)", font=("仿宋", 18))
lb6.place(x=30, y=310)
en6 = Entry(window, highlightcolor='yellow', relief="groove")
en6.place(x=30, y=340, height=35, width=200)
lb7 = Label(text="声音类型如下\n"
"普通机器女声A:0 普通机器男声A:1\n"
"普通机器男声B:3 机器萝莉声:4\n"
"机器机器女声B:5 可爱女生:103\n"
"充满智慧的男性:106 女小学生:110\n"
"甜美女生:111 还原度比较高的男声:5003\n"
" 还原度高的女声:5118\n"
, font=("黑体", 12))
lb7.place(x=650, y=280)
lb8 = Label(text="", font=("黑体", 12))
lb5 = Label(text="请输入你想要将音频文件保存路径(示例:D:\python\music\)", font=("仿宋", 16))
en5 = Entry(window, highlightcolor='yellow', relief="groove")
no = Radiobutton(window, text="保存音频到指定目录", value=0, variable=1,
command=lambda: [display.flag_set0(self, en5=en5, lb5=lb5)])
yes = Radiobutton(window, text="保存音频到当下目录", value=1, variable=1,
command=lambda: [display.flag_set1(self, en5=en5, lb5=lb5)])
yes.place(x=30, y=400)
no.place(x=30, y=430)
lb7 = Label(text="请输入你的APP_ID:", font=("仿宋", 13))
lb7.place(x=600, y=30)
en7 = Entry(window, highlightcolor='yellow')
en7.place(x=770, y=30, width=250)
lb8 = Label(text="请输入你的API_KEY:", font=("仿宋", 13))
lb8.place(x=600, y=60)
en8 = Entry(window)
en8.place(x=770, y=60, width=250)
lb9 = Label(text="请输入你的SECRET_KEY:", font=("仿宋", 13))
lb9.place(x=600, y=90)
en11 = Entry(window)
en11.place(x=800, y=90, width=250)
en9 = Entry(window)
bu5 = Button(window, text="确定啦!", height=1, width=10, font="黑体",
command=lambda: [display.button_set_pit(self, en4), display.button_set_type(self, en3),
display.button_set_speed(self, en1), display.button_set_volume(self, en2),
display.button_set_fileway(self, en5), display.button_set_filename(self, en6),
display.read_inget(self, en9), display.register(self, en7, en8, en11),
display.connect(self)])
bu5.place(x=600, y=230)
no1 = Radiobutton(window, text="导入转换内容", value=0, variable=2,
command=display.set_modle2(self))
no1.place(x=600, y=180)
yes1 = Radiobutton(window, text="输入转换内容", value=1, variable=2, command=lambda: [display.set_modle1(self)])
yes1.place(x=600, y=150)
en9.place(x=720, y=160, width=350, height=40)
window.mainloop()
def set_modle1(self):
self.flag1 = 1
def set_modle2(self):
self.flag1 = 0
def read_inget(self, en9):
if self.flag1 == 1:
self.be_read = en9.get()
else:
self.be_read = open(en9.get(), "r+", encoding="UTF-8").read()
print(self.be_read)
def register(self, en7, en8, en11):
self.APP_ID = en7.get()
self.API_KEY = en8.get()
self.SECRET_KEY = en11.get()
def input_byclient(self, en9):
self.be_read = en9.get()
def input_byfile(self, en9):
file = en9.get()
self.be_read = open("file", "r+").read()
def flag_set1(self, lb5, en5):
self.flag = 1
lb5.place_forget()
en5.place_forget()
def flag_set0(self, lb5, en5):
self.flag = 0
lb5.place(x=190, y=400)
en5.place(x=200, y=430, height=35, width=200)
def button_set_speed(self, w):
self.speed = w.get()
def button_set_type(self, w):
self.sound_type = w.get()
def button_set_volume(self, w):
self.volume = w.get()
def button_set_pit(self, w):
self.pit = w.get()
# , file_way, file_name
def button_set_fileway(self, en5):
if self.flag == 0:
self.file_way = en5.get()
else:
self.file_way = ""
def button_set_filename(self, w):
self.file_name = w.get()
def connect(self):
so = sound.sound(self.speed, self.sound_type, self.volume, self.pit, self.file_name, self.file_way,
self.be_read, self.APP_ID, self.API_KEY, self.SECRET_KEY)
def __init__(self):
print("可视化桌面的构造\n")
display.create_mainloop(self)
sound.py
from aip import AipSpeech
class sound:
client = AipSpeech('', '', '')
def new_client(self, APP_ID, API_KEY, SECRET_KEY):
self.client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
def __init__(self, speed, sound_type, volume, pit, file_name, file_way, be_read, APP_ID, AIP_KEY, SECRET_KEY):
sound.new_client(self, APP_ID, AIP_KEY, SECRET_KEY)
result = self.client.synthesis(be_read, 'zh', 1,
{'vol': volume, 'spd': speed, 'pit': pit, 'per': sound_type})
if not isinstance(result, dict):
file = open(file_way+file_name + ".mp3", "wb")
file.write(result)
file.close()
else:
print("出错了哦\n")