安装扩展库pywin32和speech,然后修改一下speech.py文件使得适用于Python 3.x。
步骤1:安装pywin32
在命令行模式运行:
pip install pywin32
安装出现超时错误,如下:
用镜像安装:
pip --default-timeout=1000 install -U pywin32 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
步骤2:安装扩展库speech
安装扩展库speech
pip3 install speech
然后修改speech.py 文件使得适用于Python 3.x,重点修改之处如图,
改为:
改为:
改为:
完整的speech.py代码如下
""" speech recognition and voice synthesis module. Please let me know if you like or use this module -- it would make my day! speech.py: Copyright 2008 Michael Gundlach (gundlach at gmail) License: Apache 2.0 (http://www.apache.org/licenses/LICENSE-2.0) For this module to work, you'll need pywin32 (http://tinyurl.com/5ezco9 for Python 2.5 or http://tinyurl.com/5uzpox for Python 2.4) and the Microsoft Speech kit (http://tinyurl.com/zflb). Classes: Listener: represents a command to execute when phrases are heard. Functions: say(phrase): Say the given phrase out loud. input(prompt, phraselist): Block until input heard, then return text. stoplistening(): Like calling stoplistening() on all Listeners. islistening(): True if any Listener is listening. listenforanything(callback): Run a callback when any text is heard. listenfor(phraselist, callback): Run a callback when certain text is heard. Very simple usage example: import speech speech.say("Say something.") print "You said " + speech.input() def L1callback(phrase, listener): print phrase def L2callback(phrase, listener): if phrase == "wow": listener.stoplistening() speech.say(phrase) # callbacks are executed on a separate events thread. L1 = speech.listenfor(["hello", "good bye"], L1callback) L2 = speech.listenforanything(L2callback) assert speech.islistening() assert L2.islistening() L1.stoplistening() assert not L1.islistening() speech.stoplistening() """ from win32com.client import constants as _constants import win32com.client import pythoncom import time import threading # Make sure that we've got our COM wrappers generated. from win32com.client import gencache gencache.EnsureModule('{C866CA3A-32F7-11D2-9602-00C04F8EE628}', 0, 5, 0) _voice = win32com.client.Dispatch("SAPI.SpVoice") _recognizer = win32com.client.Dispatch("SAPI.SpSharedRecognizer") _listeners = [] _handlerqueue = [] _eventthread=None class Listener(object): """Listens for speech and calls a callback on a separate thread.""" _all = set() def __init__(self, context, grammar, callback): """ This should never be called directly; use speech.listenfor() and speech.listenforanything() to create Listener objects. """ self._grammar = grammar Listener._all.add(self) # Tell event thread to create an event handler to call our callback # upon hearing speech events _handlerqueue.append((context, self, callback)) _ensure_event_thread() def islistening(self): """True if this Listener is listening for speech.""" return self in Listener._all def stoplistening(self): """Stop listening for speech. Returns True if we were listening.""" try: Listener._all.remove(self) except KeyError: return False # This removes all refs to _grammar so the event handler can die self._grammar = None if not Listener._all: global _eventthread _eventthread = None # Stop the eventthread if it exists return True _ListenerBase = win32com.client.getevents("SAPI.SpSharedRecoContext") class _ListenerCallback(_ListenerBase): """Created to fire events upon speech recognition. Instances of this class automatically die when their listener loses a reference to its grammar. TODO: we may need to call self.close() to release the COM object, and we should probably make goaway() a method of self instead of letting people do it for us. """ def __init__(self, oobj, listener, callback): _ListenerBase.__init__(self, oobj) self._listener = listener self._callback = callback def OnRecognition(self, _1, _2, _3, Result): # When our listener stops listening, it's supposed to kill this # object. But COM can be funky, and we may have to call close() # before the object will die. if self._listener and not self._listener.islistening(): self.close() self._listener = None if self._callback and self._listener: newResult = win32com.client.Dispatch(Result) phrase = newResult.PhraseInfo.GetText() self._callback(phrase, self._listener) def say(phrase): """Say the given phrase out loud.""" _voice.Speak(phrase) def input(prompt=None, phraselist=None): """ Print the prompt if it is not None, then listen for a string in phraselist (or anything, if phraselist is None.) Returns the string response that is heard. Note that this will block the thread until a response is heard or Ctrl-C is pressed. """ def response(phrase, listener): if not hasattr(listener, '_phrase'): listener._phrase = phrase # so outside caller can find it listener.stoplistening() if prompt: print(prompt) if phraselist: listener = listenfor(phraselist, response) else: listener = listenforanything(response) while listener.islistening(): time.sleep(.1) return listener._phrase # hacky way to pass back a response... def stoplistening(): """ Cause all Listeners to stop listening. Returns True if at least one Listener was listening. """ listeners = set(Listener._all) # clone so stoplistening can pop() returns = [l.stoplistening() for l in listeners] return any(returns) # was at least one listening? def islistening(): """True if any Listeners are listening.""" return not not Listener._all def listenforanything(callback): """ When anything resembling English is heard, callback(spoken_text, listener) is executed. Returns a Listener object. The first argument to callback will be the string of text heard. The second argument will be the same listener object returned by listenforanything(). Execution takes place on a single thread shared by all listener callbacks. """ return _startlistening(None, callback) def listenfor(phraselist, callback): """ If any of the phrases in the given list are heard, callback(spoken_text, listener) is executed. Returns a Listener object. The first argument to callback will be the string of text heard. The second argument will be the same listener object returned by listenfor(). Execution takes place on a single thread shared by all listener callbacks. """ return _startlistening(phraselist, callback) def _startlistening(phraselist, callback): """ Starts listening in Command-and-Control mode if phraselist is not None, or dictation mode if phraselist is None. When a phrase is heard, callback(phrase_text, listener) is executed. Returns a Listener object. The first argument to callback will be the string of text heard. The second argument will be the same listener object returned by listenfor(). Execution takes place on a single thread shared by all listener callbacks. """ # Make a command-and-control grammar context = _recognizer.CreateRecoContext() grammar = context.CreateGrammar() if phraselist: grammar.DictationSetState(0) # dunno why we pass the constants that we do here rule = grammar.Rules.Add("rule", _constants.SRATopLevel + _constants.SRADynamic, 0) rule.Clear() for phrase in phraselist: rule.InitialState.AddWordTransition(None, phrase) # not sure if this is needed - was here before but dupe is below grammar.Rules.Commit() # Commit the changes to the grammar grammar.CmdSetRuleState("rule", 1) # active grammar.Rules.Commit() else: grammar.DictationSetState(1) return Listener(context, grammar, callback) def _ensure_event_thread(): """ Make sure the eventthread is running, which checks the handlerqueue for new eventhandlers to create, and runs the message pump. """ global _eventthread if not _eventthread: def loop(): while _eventthread: pythoncom.PumpWaitingMessages() if _handlerqueue: (context,listener,callback) = _handlerqueue.pop() # Just creating a _ListenerCallback object makes events # fire till listener loses reference to its grammar object _ListenerCallback(context, listener, callback) time.sleep(.5) _eventthread = 1 # so loop doesn't terminate immediately _eventthread = threading.Thread(target=loop, args=()).start()
安装之后使用发现错误:
from speech import say
ModuleNotFoundError: No module named 'speech'
原因:安装了多个Python;需要安装到正确的位置;
ModuleNotFoundError: No module named 'win32com'
pip install pywin32
原因:安装了多个Python;需要安装到正确的位置;
speech会调用 win32com(即为pywin32)
speech需要注册和激活
步骤3:
准备一个文本文件,保存学生信息,如图
学生名单.txt
20210223,张三
20210224,李四
20210225,王五
20210226,赵六
20210227,周七
20210228,钱八
我们自己写的源代码如下:
import tkinter from tkinter.messagebox import showinfo from time import sleep from random import shuffle from itertools import cycle from threading import Thread from speech import say try : from speech import say has_speech = True except: has_speech = False root = tkinter.Tk() #窗口标题 root.title('随机提问')#窗口初始大小和位置 root.geometry( '260x180+400+300')#不允许改变窗口大小 root.resizable(False,False) #关闭程序时执行的函数代码,停止滚动显示学生名单 def closewindow( ): if rolling.get(): showinfo('不能关闭','请先停止名单滚动') return root.destroy() root.protocol('WM_DELETE_WINDOw' , closewindow) #读取学生名单,如果不存在文件就使用模拟数据try : try: with open( '学生名单.txt' , encoding='utf8 ' ) as fp: students = fp.read( ).splitlines() except: showinfo('学生名单不存在', '当前目录中没有文件:学生名单.txt 临时使用模拟数据') students =['张三','李四','王五','赵六','周七','钱八'] #变量,用来控制是否滚动显示学生名单 rolling = tkinter.BooleanVar(root, value=False) def switch(): rolling.set(True) #随机打乱学生名单 t = students[ : ] shuffle(t) t = cycle(t) while rolling.get(): # 滚动显示 lbFirst[ 'text'] = lbSecond[ 'text' ] lbSecond[ 'text'] = lbThird[ 'text'] lbThird[ 'text'] = next(t) #数字可以修改,控制滚动速度 sleep(0.1) def btnStartClick(): # 每次单击“开始”按钮启动新线程 Thread(target=switch).start() btnStart[ 'state' ] = 'disabled' btnStop[ 'state' ] = 'normal' btnStart = tkinter.Button( root, text='开始', command=btnStartClick) btnStart.place(x=30,y=10,width=80,height=20) saying = tkinter.BooleanVar(root, value=False) def say_name(): while has_speech and saying.get(): say(f"请{lbSecond[ 'text' ].replace( ' ,','')}回答问题") def btnStopClick(): #单击“停”按钮结束滚动显示rolling.set(False) sleep(0.3) saying.set(True) Thread(target=say_name).start() showinfo('恭喜','本次中奖: '+lbSecond[ 'text' ]) saying.set(False) btnStart[ 'state' ] = 'normal' btnStop[ 'state' ] = 'disabled' btnStop = tkinter.Button(root,text='停', command=btnStopClick) btnStop[ 'state'] = 'disabled' btnStop.place(x=150,y=10, width=80,height=20) #用来滚动显示学生名单的3个Label组件 #可以根据需要进行添加,但要修改上面的线程函数代码 lbFirst = tkinter.Label(root, text='') lbFirst.place(x=80, y=60, width=100,height=20) #红色Label组件,表示中奖名单 lbSecond = tkinter.Label(root,text='') lbSecond[ 'fg' ] = 'red' lbSecond.place(x=80,y=90,width=100,height=20) lbThird = tkinter.Label(root,text='') lbThird.place(x=80,y=120,width=100,height=20) #启动tkinter主程序 root.mainloop()
来自: