本篇代码存在部分错误 ,现已经更新
(https://blog.csdn.net/aqqwvfbukn/article/details/131277668)
这次项目开发能按部就班顺利完成,主要是靠队友成功在软件的前期设计阶段,需求分析和用例设计起到了重要的作用。当然,这次的开发过程中也遇到了很多的问题,有许多功能是书上没有学到的,也是跟队友们商量,上网搜索,图书馆学习,才能解决的问题.要是没有队友的帮助,这次的课程设计也是很难完成的。这也让我意识到了团队协助的重要性。也许单打独斗也能完成这次的课程设计,但是相比于团队协助,开发的时间,进度和准确性肯定大大不如团队协作。完成这次项目开发,收获良多。在此向我的队友表示衷心的感谢!!!
——————————————分割线————————————————————
摘要: 当下,人工智能正在走进家居、教育、医疗、交通等几乎所有行业,尤其在计算机领域内,得到了愈加广泛的重视。并在机器人,经济政治决策,控制系统,仿真系统中得到应用。本文主要运用所学的python知识,基于Python的一些库制做了一个带有人机互动、音乐播放、天气播报及新闻播报功能的GUI图形界面。在人机交互、音乐播放、天气播报功能中,将通过麦克风获取的语音信息,进行解析并提取其中的关键信息,来分别获取图灵机器人的返回消息、到指定网页去爬取把需要的内容,最后通过调用Python的库播放出来,新闻播报功能中则直接爬取新闻信息并播放。最终将四个功能模块集合起来作成GUI界面。相信在未来,人工智能已经并且将继续不可避免地改变我们的生活。
关键词: 人工智能 ;Python ;爬虫 ;语音合成
一、需求分析
(一)任务概述
1、目标
(1)软件开发意图:
A.使老人不再因为儿女不在身边无人说话而感到孤独,有一个说话对象;
B.陶冶情操,老人可以随时听听戏曲听听歌曲;
C.使得老人随时可以知道天气变化情况,以防感冒;
D.老人可以不用等待新闻联播便可知今日新闻。
(2)应用目标:
通过本系统软件,可以让老人跟上时代潮流体验人工智能,随时随地打开软件便可语音聊天、听音乐、了解天气和实时新闻,时效性、方便快捷性、创新性得到了一定的应用。
(3)作用以及范围:
本软件适用于语音智能系统,可以进行人机互动聊天、音乐播放、天气播报和新闻播报,为使用者带来了极大的便利。
2、用户的特点
最终用户特点:最终用户主要为老年人,软件设计符合该类群体的使用习惯,预计会为他们的日常生活带来便利。
(二)需求规定
1、对功能的规定
(1)使用该系统有两个角色用户,分别为一般用户、操作员。一般用户可以完成人机互动、音乐播放、天气播报和新闻播报;操作员可以实现软件的界面更新、功能的改进优化以及错误维护。
(2)系统分为四个模块:
A.人机互动模块
B.音乐播放模块
C.天气播报模块
D.新闻播报模块
2、对性能的规定
(1)时间特性要求
响应时间:0.5s内
更新处理时间:0.5s内
数据的更换和传送时间:1s内
(2)灵活性
说明对该软件的灵活性的要求,即当需求发生某些变化时,该软件对这些变化的适应能力:
a. 运行环境的变化:该软件适用于win10系统;
b. 精度和有效时限的变化:因不同情况而定;
c. 计划的变化和改进:根据用户的需求随时最软件做必要的升级和更新。
3、故障处理要求
软件故障:软件可能出现兼容性问题,可以及时与开发端联系。
4、其他专门要求
软件的可维护性:出现运行错误需找专业人员进行维护工作;
软件的易读性、可靠性:要求用户按照要求合法输入,不得随意对软件的相关控件做任何非法删改。
(三)运行环境规定
1、运行环境
系统版本:Windows10
运行内存:4GB及以上
Python版本:Python3.7
2、接口
用户接口:将向用户提供人机互动、音乐播放、天气播报、新闻播报的四个命令选择,对应系统不同功能的实现;
外部接口:鼠标、音响和麦克风
3、控制
该系统的主要输入设备是鼠标、麦克风,输出主要是音响和显示器
二、概要设计
(一)总体设计
1、基本设计概念和处理流程
主要功能模块流程图如下:
2、结构
(二)接口设计
1、用户接口
命令 | 语法 | 信息正确 |
---|---|---|
人机互动 | 点击 | 实现命令 |
音乐播放 | 点击 | 实现命令 |
天气播报 | 点击 | 实现命令 |
新闻播报 | 点击 | 实现命令 |
2、外部接口
软件、硬件 | 鼠标 | 音响 | 麦克风 |
---|---|---|---|
人机互动模块 | 连接 | 连接 | 连接 |
音乐播放模块 | 连接 | 连接 | 连接 |
天气播报模块 | 连接 | 连接 | 连接 |
新闻播报模块 | 连接 | 连接 | 连接 |
三、详细设计
(一)系统功能模块结构
1、人机互动
算法流程:
2、音乐播放
算法流程:
3、天气播报
算法流程:
4、新闻播报
算法流程:
(二)界面设计
算法流程:
四、成果展示
(一)人机互动
以下输出的文字内容均以语音播放
(二)音乐播放
以下输出的文字内容均以语音播放
(三)天气播报
以下输出的文字内容均以语音播放
(四)新闻播报
以下输出的文字内容均以语音播放
(五)界面设计
五、小组分工
组员 | 任务 |
---|---|
欧健聪 | 功能模块(人机互动、音乐播放、天气播报、新闻播报)代码实现、代码的整合以及调试、readme文档 |
施雅蓉 | 资料的收集、GUI界面代码的实现、项目开发报告 |
六、项目分析及总结
(一)未解决待改进的问题
A.项目无法脱离python实现
我们最初的理想实现是通过pyinstaller将程序打包为EXE文件,在任意一台电脑即可实现无需安装python,但是尝试了各种方法无法实现,修改了绝对路径也无法实现,所以在接下来我们将学习如何解决打包过程出现的错误。
B.项目功能过于少且无创新性
由于时间问题,我们没有扩展更多的功能模块,例如学习模块,并且在创新方面我们没有做到很好,没有比市场上现有的语音智能助手创新性,只是实现了部分他们的功能。因此在接下来我们会去在功能方面创新。
C.音乐播放模块现有BUG
在独立运行时,音乐播放可以随时停止,但将其导入GUI中却出现了无法停止的问题,由于时间问题我们还未来的及去解决,再接下来的时间内去查阅资料将其完善。
D.无法实现在GUI中将动图GIF作为按钮
我们的理想实现是在机器人脸部插入一张GIF的嘴巴,使其更加形象化,我们尝试了两天去解决这个问题,最终还是未解决。故这是一个界面设计的缺陷,接下来去丰富自己界面设计的知识来做出更加完美的界面效果。
(二)项目总结
本次项目开发实践中,从一开始的毫无头绪到后面的确定项目名称再到实现相应功能板块的过程中,认识到自己的运用知识的能力不足,更加认识到自己要不断地学习新知识,还要把学过的知识进行巩固总结才能成为自己的。在这个过程中也知道了遇到问题怎样运用互联网的优势去寻找解决的方案,并结合自己的知识做出相应的改变。知识是无穷无尽的,尤其是与互联网技术方面相关的知识更是不断更新,我们要做的就是在巩固自己的知识的前提下,不断地学习最新的技术,以了解科技发展的方向。深刻认识到在短短8天的时间内,能完成一个GUI界面的设计与实现,并与相应的功能模块进行连接起来,最终可以达到预期的效果,如果是自己一个人做的话,基本是不可能实现的,所以还要感谢队友的支持与鼓励。总之经历了这次项目开发实践,自己也积累了一些经验,为以后的项目开发与设计提供了一定的基础,也更加明白自己的专长所在,我们将不断学习更多的技术知识来充实自己。
参考文献
[1] 小葫芦.详解快速实现基于Python的微信聊天机器人示例代码[EB/OL].http://www.php.cn/python-tutorials-355055.html,2017-03-06.
[2] Keif.用Python与图灵机器人聊天[EB/OL].https://segmentfault.com/a/1190000013900291,2018-03-22.
[3] Alpaca_Max.Python破解网易云音乐下载版权限制[EB/OL].https://blog.csdn.net/qq_37225652/article/details/85221683,2018-12-23.
[4] 匿了名的米老鼠.python语音天气预报[EB/OL].https://zhuanlan.zhihu.com/p/32030780,2017-12-14.
[5] Car12.wxpython 基本的控件(按钮)[EB/OL].https://blog.csdn.net/u010261063/article/details/52525672,2016-09-13.
[6] 夜雨寄北、.wxPython学习笔记(三)[EB/OL].https://www.cnblogs.com/ziv-chan/p/5517757.html,2016-05-22.
注 :图片素材自取
链接:https://pan.baidu.com/s/1C5zyf5_LedJiJ_wcza4_Rw
提取码:wgje
附录1:Readme.txt
1、运行环境:
系统版本:Windows10
运行内存:4GB及以上
Python版本:Python3.7
2、导入相关模块
import os
import wx
import pyttsx3
import requests
from bs4 import BeautifulSoup
import chardet
from lxml import etree
import urllib
import pygame
import pyaudio
import wave
import win32com.client
from aip import AipSpeech
import pyttsx3
import time
import base64
import random
from binascii import hexlify
from Crypto.Cipher import AES
import json
3、使用方法:
(1)把main.py文件和“bg.png”,“hudong.png”,“yinyue.png”,“tianqiqing.png”,“xinwen.png”,放到同一目录下,并在该目录下创建一个名为“data”的文件夹;
(2)修改main.py中的百度key/图灵key;
(3)运行main.py产生GUI界面;
(4)点击相应功能的图标,在播放音乐和天气预报时,听到“开始录音”后对着麦克风说“播放+歌名”或“播放+地名+天气情况”,当听到“录音结束”时,等待播放结果即可。人机互动功能中也是一样在听到“开始录音”后对麦克风说话。而在新闻播报模块中,点击相应图标即可听到新闻。
附录2:程序代码
main.py
import pyaudio
import wave
import win32com.client
from aip import AipSpeech
from bs4 import BeautifulSoup
import requests
import chardet
from lxml import etree
import pyttsx3
import pygame
import time
speaker = win32com.client.Dispatch("SAPI.SpVoice")
def record(file_path):# 各路参数CHUNK = 1024FORMAT = pyaudio.paInt16CHANNELS = 1RATE = 16000RECORD_SECONDS = 5WAVE_OUTPUT_FILENAME = file_pathpau = pyaudio.PyAudio()stream = pau.open(format=FORMAT,channels=CHANNELS,rate=RATE,input=True,frames_per_buffer=CHUNK, )frames = []print("开始录音")speaker.Speak("开始录音") for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):data = stream.read(CHUNK)frames.append(data)print("录音结束")speaker.Speak("录音结束") stream.stop_stream()stream.close()pau.terminate()wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')wf.setnchannels(CHANNELS)wf.setsampwidth(pau.get_sample_size(FORMAT))wf.setframerate(RATE)wf.writeframes(b''.join(frames))wf.close()
def voice2text(APP_ID, API_KEY, SECRET_KEY, file_path):client = AipSpeech(APP_ID, API_KEY, SECRET_KEY)ret = client.asr(get_data(file_path), 'pcm', 16000, {'dev_pid': 1536}, )return ret['result']
def get_data(file_path):with open(file_path, 'rb') as fp:return fp.read()
#人机互动
import requests
import time
import pygame
import requests
import pyttsx3
engine = pyttsx3.init()
# 向api发送请求
def get_response(msg):apiUrl = 'http://www.tuling123.com/openapi/api'data = {'key' : '51e9d4c62c25410ead75257a8a778440','info' : msg,'userid' : 'pth-robot',}try:r = requests.post(apiUrl, data=data).json()engine.say(r.get('text'))engine.runAndWait()print(r.get('text'))except:return
def say():global chat_message# 存放的文件名称file_path = "data/chat-audio.wav"# 百度需要的参数APP_ID = '16630199'API_KEY = 'SwyMvhvVQRAx6i4yU8sGQvGb'SECRET_KEY = 'ciD7HueB0NaQGMUNtU5ev8rWaX7k1N0T'# 先调用录音函数record(file_path)# 语音转成文字的内容chat_message = voice2text(APP_ID, API_KEY, SECRET_KEY, file_path)print(chat_message)
def chatwithrobot(): i=0while i<5:say()get_response(chat_message)i=i+1
#音乐播放
import base64
import random
from binascii import hexlify
from Crypto.Cipher import AES
import json
import requests
import urllib, requests
import pyttsx3
import pygame
class GetMusic:def __init__(self):self.key = GetParamsAndEncSecKey()self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36','Referer': 'http://music.163.com/'}self.session = requests.Session()self.session.headers = self.headersself.conmment_url = 'https://music.163.com/weapi/v1/resource/comments/R_SO_4_{}?csrf_token=' # 评论self.lyric_url = 'https://music.163.com/weapi/song/lyric?csrf_token=' # 歌词self.music_url = 'https://music.163.com/weapi/song/enhance/player/url?csrf_token=' # 歌曲self.url = 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token=' # 搜索歌曲列表,无歌曲链接 def get_params_and_encSecKey(self, song=None):'''获取什么就返回所需要两个参数1. 歌曲2. 歌词3. 评论 默认4. 搜索的歌曲列表:param song::return:'''if isinstance(song, int):data = {"ids": [song], "br": 128000, "csrf_token": ""}elif isinstance(song, str) and song.isdigit():data = {"id": song, "lv": -1, "tv": -1, "csrf_token": ""}elif song == None:data = {}else:data = {"hlpretag": "<span class=\"s-fc7\">", "hlposttag": "</span>", "s": song, "type": "1", "offset": "0","total": "true", "limit": "30", "csrf_token": ""} song = json.dumps(data)data = self.key.get(song)return data def get_music_list_info(self, name):'''获取歌曲详情:歌名+歌曲id+作者:param name::return:'''data = self.get_params_and_encSecKey(name)res = self.session.post(self.url, data=data) # 歌曲song_info = res.json()['result']['songs'] for song in song_info:song_name = song['name']song_id = song['id']songer = song['ar'][0]['name']print(song_name, '\t', song_id, '\t', songer)global SongName # 定义为全局变量global SongId # 定义为全局变量global Songer # 定义为全局变量SongName=song_nameSongId=song_idSonger=songer self.get_music_url(song_id)self.get_music_lyric(song_id)self.get_music_comment(song_id)break def get_music_url(self, id):'''获取歌曲URL链接:param id::return:'''global Song_url # 定义为全局变量data = self.get_params_and_encSecKey(id)res = self.session.post(self.music_url, data=data)song_url = res.json()['data'][0]['url'] Song_url=song_url#print(song_url) def get_music_lyric(self, id_str):'''获取歌词:param id_str::return:'''data = self.get_params_and_encSecKey(str(id_str))res = self.session.post(self.lyric_url, data=data)lyric = res.json()['lrc']['lyric']#print(lyric) def get_music_comment(self, song_id):'''获取歌曲评论: 评论人+内容+头像:param song_id::return:'''data = self.get_params_and_encSecKey()comment = self.session.post(self.conmment_url.format(str(song_id)), data=data)com_list = comment.json()['hotComments']for com in com_list:content = com['content']nickname = com['user']['nickname']user_img = com['user']['avatarUrl']#print(nickname, '!!!!' + content + '!!!!', user_img)
class GetParamsAndEncSecKey:def __init__(self):self.txt = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'self.i = ''.join(random.sample(self.txt, 16)) # 16为随机数self.first_key = '0CoJUm6Qyw8W8jud'def get(self, song):'''获取加密的参数params是两次加密的:param song::return:'''res = self.get_params(song, self.first_key)params = self.get_params(res, self.i)encSecKey = self.get_encSecKey()return {'params': params,'encSecKey': encSecKey}def get_params(self, data, key):'''获得params,加密字符长度要是16的倍数:param data::param key::return:'''iv = '0102030405060708'num = 16 - len(data) % 16data = data + num * chr(num) # 补足cipher = AES.new(key.encode(), AES.MODE_CBC, iv.encode())result = cipher.encrypt(data.encode())result_str = base64.b64encode(result).decode('utf-8')return result_strdef get_encSecKey(self):'''获取encSecKey,256个字符串hexlify--->转换为btyes类型pow--->两个参数是幂,三个参数是先幂在取余format(rs, 'x').zfill(256)-->256位的16进制:return:'''enc_key = '010001'modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7'rs = pow(int(hexlify(self.i[::-1].encode('utf-8')), 16), int(enc_key, 16), int(modulus, 16))return format(rs, 'x').zfill(256)
def music():file_path="data/music.wav"# 百度需要的参数APP_ID = '16630199'API_KEY = 'SwyMvhvVQRAx6i4yU8sGQvGb'SECRET_KEY = 'ciD7HueB0NaQGMUNtU5ev8rWaX7k1N0T'# 先调用录音函数record(file_path)# 语音转成文字的内容song_message = voice2text(APP_ID, API_KEY, SECRET_KEY, file_path)print(song_message)input2=''.join(song_message) #转换成字符串song_name=input2[2:]Msuic = GetMusic()Msuic.get_music_list_info(song_name) songid=str(SongId)url = 'https://music.163.com/song/media/outer/url?id='+songidheaders = { 'User-agent':'Mozilla/5.0 (X11; Linux x86_64; rv:57.0)Gecko/20100101 Firefox/57.0','Host':'music.163.com','Referer':'https://music.163.com'}req = requests.get(url, headers=headers, allow_redirects=False) #拒绝默认的301/302重定向musicLink = req.headers['Location'] #从而可以通过html.headers[‘Location’]拿到重定向的URL。urllib.request.urlretrieve(musicLink,'data/'+SongName+".mp3") #下载并重命名文件engine = pyttsx3.init()engine.say("即将为您播放 "+Songer+' 的 '+SongName)engine.runAndWait()pygame.mixer.init()filename = 'data/' + SongName+'.mp3'pygame.mixer.music.load(filename)
pygame.mixer.music.play()
#天气播报
def weather(): # 存放的文件名称file_path='data/weather-audio.wav'# 百度需要的参数APP_ID = '16630199'API_KEY = 'SwyMvhvVQRAx6i4yU8sGQvGb'SECRET_KEY = 'ciD7HueB0NaQGMUNtU5ev8rWaX7k1N0T'# 图灵需要的参数TULING_KEY = '466f8cd5ac1146d39b9a0c8c9f857b0f'# 先调用录音函数record(file_path)# 语音转成文字的内容weather_message =voice2text(APP_ID, API_KEY, SECRET_KEY, file_path)print(weather_message)#抓取中国天气网指定城主天气#input_message=['播放杭州天气情况']input2=''.join(weather_message) #转换成字符串city_name=input2[2:4]s1='https://way.jd.com/jisuapi/weather?city='s2='&cityid=111&citycode=101260301&appkey=6f9f4bf8c5d672c29aee8b5992bc20a9'url=s1+city_name+s2 #拼接 urlr = requests.get(url)r.encoding = 'utf-8'# 提取相关天气信息date=r.json()["result"]['result']["date"]templow=r.json()["result"]['result']["templow"]temphigh=r.json()["result"]['result']["temphigh"]tempnow=r.json()["result"]['result']["temp"]week=r.json()["result"]['result']["week"]tip=r.json()["result"]['result']["index"][3]["detail"]weather=r.json()["result"]['result']['daily'][0]['night']['weather']add=r.json()["result"]['result']["city"]wind=r.json()["result"]['result']['winddirect']WS=r.json()["result"]['result']["windpower"]t = time.localtime() # 当前时间的纪元值fmt = "%H %M"now = time.strftime(fmt, t) # 将纪元值转化为包含时、分的字符串now = now.split(' ') #以空格切割,将时、分放入名为now的列表中hour = now[0]minute = now[1]wea='你好,今天是%s%s,现在北京时间%s时%s分,%s天气 %s,气温%s摄氏度~%s摄氏度,现在为%s摄氏度,%s,风力%s,%s'%(date,week,hour,minute,add,weather,templow,temphigh,tempnow,wind,WS,tip)print(wea)engine = pyttsx3.init()engine.say('即将为您播放'+city_name+"天气情况")engine.say(wea)
engine.runAndWait()
#新闻播报
def news():def get_content(): url="http://www.ejuhua.cn/cms/tech/" # 爬取一名话新闻网科技类新闻headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'}rqg=requests.get(url,headers=headers) # 开始爬取,设置headers信息来伪装成浏览器请求数据rqg.encoding=chardet.detect(rqg.content)['encoding']html=rqg.content.decode('utf-8') #换化编码为utf-8 soup=BeautifulSoup(html,'lxml') soup.prettify() #格式化soup对象return soupsoup2=get_content()target=soup2.find_all(class_='title') #取新闻标题Tag=[]Tag2=[]for tag in target:Tag.append(tag.get_text()) #取新闻标题文本添加到列表中for t in Tag:tag2=t[1:-1] # 去除新闻标题前后的 "\n" (清洗数据)Tag2.append(tag2)engine = pyttsx3.init()engine.say('即将为您播放新闻')engine.runAndWait()for i in range(1,10+1): # 取前10条新闻作为例子播放s2='%d, '%(i)+Tag2[i-1]#print(s2)engine.say(s2) # 播放engine.runAndWait()
#GUI界面
import os
import wx
import pyttsx3
import requests
from bs4 import BeautifulSoup
import chardet
from lxml import etree
import urllib
import pygame
import win32com.client
speaker = win32com.client.Dispatch("SAPI.SpVoice")
class Panel1(wx.Panel):"""class Panel1 creates a panel with an image on it, inherits wx.Panel"""def __init__(self, parent, id):# create the panelwx.Panel.__init__(self, parent,id)try:image_file = 'bg.png'bmp1 = wx.Image(image_file, wx.BITMAP_TYPE_ANY).ConvertToBitmap()self.bitmap1 = wx.StaticBitmap(self, -1, bmp1, (0, 0))except IOError:print ("Image file is not found") % imageFileraise SystemExitpic1 = wx.Image("hudong.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap() pic2 = wx.Image("yinyue.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap() pic3 = wx.Image("tianqiqing.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap() pic4 = wx.Image("xinwen.png", wx.BITMAP_TYPE_ANY).ConvertToBitmap() #绘图按钮1,默认风格3D self.button1 = wx.BitmapButton(self.bitmap1, -1, pic1, pos = (230, 420),style=0,size=(50,50))self.Bind(wx.EVT_BUTTON, self.On1Click, self.button1)self.button1.SetDefault()#绘图按钮2,默认风格3D self.button2 = wx.BitmapButton(self.bitmap1, -1, pic2, pos = (300, 420),style=0,size=(50,50))self.Bind(wx.EVT_BUTTON, self.On2Click, self.button2)self.button2.SetDefault()#绘图按钮3,默认风格3D self.button3 = wx.BitmapButton(self.bitmap1, -1, pic3, pos = (230, 480),style=0,size=(50,50))self.Bind(wx.EVT_BUTTON, self.On3Click, self.button3)self.button3.SetDefault()#绘图按钮4,默认风格3D self.button4 = wx.BitmapButton(self.bitmap1, -1, pic4, pos = (300, 480),style=0,size=(50,50))self.Bind(wx.EVT_BUTTON, self.On4Click, self.button4)self.button4.SetDefault()def On1Click(self, event):print("人机交互")speaker.Speak("您已选择人机交互模式 ")chatwithrobot()event.Skip()def On2Click(self, event):print("音乐播放")speaker.Speak("您已选择音乐播放模式 ")music()event.Skip()def On3Click(self, event): print("天气播报") speaker.Speak("您已选择天气播报模式 ") weather()event.Skip()def On4Click(self, event): print("新闻播报") speaker.Speak("您已选择新闻播报模式 ") news()event.Skip()
app = wx.App(False)
frame1 = wx.Frame(None, -1, title='Robot', size=(600, 640))
# create the class instance
panel1 = Panel1(frame1, -1)
frame1.Show(True)
app.MainLoop()