# Created by Leo from: C:\Python22\Tom\Speech.leo # << SpeechGui declarations >> # A simple speech recognition program for Windows # When speech is recognized, Python macros are executed. # This requires: # That the wxPython library is installed (obtain from http://www.wxpython.org/) # That the MS Speech API 5 is installed (obtain from http://microsoft.com/speech/) # That MakePy has been run on the MS Speech API (in PythonWin, select Tools | # COM MakePy Utility | Microsoft Speech Object Library 5.1) # Copyright (C) 2001 Inigo Surguy, inigosurguy@hotmail.com # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # or download it from http://www.gnu.org/licenses/gpl.txt from wxPython.wx import * import sys, time, math, string, win32com.client,win32event,pythoncom from win32com.client import constants import win32con import cPickle, zlib import string import pickle import win32api import win32com.client import traceback # Handy methods that make the code included inside the macro area simpler speaker = win32com.client.Dispatch("SAPI.SpVoice") """Say the text via the MS Speech API""" # -- end -- << SpeechGui declarations >> # << SpeechGui methods >> (1 of 10) def say(text): speaker.Speak(text) # << SpeechGui methods >> (2 of 10) shell = win32com.client.Dispatch("WScript.Shell") """Use the Windows Scripting Host sendKeys function to send keystrokes to the currently focused application. See help on the Microsoft site for values that represent special keys: common ones I use are %{TAB} for Alt-Tab, and {PGDN} and {PGUP} for page down and up, and %{F4} for Alt-F4.""" def sendKeys(keystrokes): shell.SendKeys(keystrokes) # << SpeechGui methods >> (3 of 10) """Launch a command via the Windows Scripting Host""" def start(command): shell.Run(command) # << SpeechGui methods >> (4 of 10) """Launch Internet Explorer, and navigate to a given URL""" def browseTo(location): ie = win32com.client.Dispatch("InternetExplorer.Application") ie.Visible = 1 ie.Navigate(location) # << SpeechGui methods >> (5 of 10) """Display a message box with the given message and title""" def message(message, title="Message"): dlg = wxMessageDialog(app.frame, message, title, wxOK | wxICON_INFORMATION) dlg.ShowModal() dlg.Destroy() # << SpeechGui methods >> (6 of 10) # Taken from wxPython demo - generated with wxPython\demo\encode_bitmaps.py """Get the Mondrian picture (from the wxPython demo) that's used as an application icon""" def getMondrianData(): return cPickle.loads(zlib.decompress( 'x\332\323\310)0\344\012V76R\000"3\005Cu\256\304`u\005\205d\005\247\234\304\ \344l0/\002\310Sv\003\0030?\037\3047\000\002(_\017"\017\022\001\363\265!\362\ NnP\276?L?\224\257@\000@\024\351\201\201B\004v0"\024\021\025NP\035X\014\311\ \007\202!\251\210(\337!\205\323\250"\222\024a\001\230\212\374\221\200\2026\ \010\014\013E\204\263\224\036\000\277\004Z\355' )) # << SpeechGui methods >> (7 of 10) def getMondrianBitmap(): return wxBitmapFromXPMData(getMondrianData()) # << SpeechGui methods >> (8 of 10) def getMondrianImage(): return wxImageFromBitmap(getMondrianBitmap()) # << SpeechGui methods >> (9 of 10) """The event handler for speech events""" class ContextEvents(win32com.client.getevents("SAPI.SpSharedRecoContext")): # << class ContextEvents methods >> def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result): newResult = win32com.client.Dispatch(Result) try: # Exec the appropriate listbox entry exec app.items[newResult.PhraseInfo.GetText()] except: # If execution fails, display a messagebox with error and cause etype, value, tb = sys.exc_info() message = (str(etype)+":"+str(value)+ "\nat line "+`tb.tb_next.tb_lineno`+ "for text '"+newResult.PhraseInfo.GetText()+"'") dlg = wxMessageDialog(app.frame, message, 'Exception: '+str(etype), wxOK | wxICON_INFORMATION) dlg.ShowModal() dlg.Destroy() # -- end -- << class ContextEvents methods >> # << SpeechGui methods >> (10 of 10) """Windows speech recognition application""" class MyApp(wxApp): # << class MyApp declarations >> ADD_BUTTON_ID = 10 DELETE_BUTTON_ID = 20 LISTBOX_ID = 30 EDITOR_ID = 40 TEST_BUTTON_ID = 50 TURNON_BUTTON_ID = 60 TURNOFF_BUTTON_ID = 70 SAVE_FILENAME = "save.p" # -- end -- << class MyApp declarations >> # << class MyApp methods >> (1 of 22) def setItems(self): try: self.items = pickle.load(open(self.SAVE_FILENAME)) except IOError: self.items = {u'turn on tee vee': u'sendKeys("^(%z)")', u'channel forty two': u'sendKeys("42")', u'close program now': u'sendKeys("%( )c")', u'channel thirty six': u'sendKeys("36")', u'play woman rock': u"say('please stand by')\nbrowseTo('http://release.theplatform.com/deliverable.select?pid=Mf5zobHmqTDt6bze2ThXCugPnEUpJQQh&UserID=choiceradio')", u'channel sixteen': u'sendKeys("16")', u'open tee vee guide': u"browseTo('http://tv.yahoo.com/grid?lineup=us_AZ02423&dur=&.intl=us&startdate=0&starthour=0&genres=0')", u'channel thirty four': u'sendKeys("34")', u'channel forty four': u'sendKeys("44")', u'play raggae': u"say('please stand by')\nbrowseTo('http://www.totallyradio.com/asx/live/reggae.asx')", u'computer': u"say('working')", u'channel forty': u'sendKeys("40")', u'channel thirty eight': u'sendKeys("38")', u'stop music': u'sendKeys("^(s)")', u'play mellow yellow': u"say('please stand by')\nbrowseTo('http://radio.player.loudeye.com/LoudSE/radio.jsp?anID=22&aID=1874&dsoID=4')", u'channel seven': u'sendKeys("7")', u'channel two': u'sendKeys("2")', u'play new age': u"say('please stand by')\nbrowseTo('http://release.theplatform.com/deliverable.select?pid=tXSTT6E-SWIv_678ayYHCdIp51IFHhLb&UserID=choiceradio')"} # << class MyApp methods >> (2 of 22) def InitSpeech(self): listener = win32com.client.Dispatch("SAPI.SpSharedRecognizer") self.context = listener.CreateRecoContext() self.grammar = self.context.CreateGrammar() self.grammar.DictationSetState(0) self.ListItemsRule = self.grammar.Rules.Add("ListItemsRule", 33, 0) events = ContextEvents(self.context) self.turnedOn = true self.SetWords() # << class MyApp methods >> (3 of 22) def SetWords(self): self.ListItemsRule.Clear() if self.turnedOn: print "Setting words - turned on" [ self.ListItemsRule.InitialState.AddWordTransition(None, word) for word in self.items.keys() ] else: print "Setting words - OFF" self.ListItemsRule.InitialState.AddWordTransition(None, "Turn on") self.grammar.Rules.Commit() self.grammar.CmdSetRuleState("ListItemsRule", 1) self.grammar.Rules.Commit() # << class MyApp methods >> (4 of 22) def SetUpTaskbar(self): # setup a taskbar icon, and catch some events from it self.tbicon = wxTaskBarIcon() icon = wxIconFromXPMData(getMondrianData()) self.tbicon.SetIcon(icon, "Speech recognition") EVT_TASKBAR_LEFT_DCLICK(self.tbicon, self.OnTaskBarActivate) EVT_TASKBAR_RIGHT_UP(self.tbicon, self.OnTaskBarMenu) EVT_MENU(self.tbicon, self.TBMENU_RESTORE, self.OnTaskBarActivate) EVT_MENU(self.tbicon, self.TBMENU_CLOSE, self.OnTaskBarClose) # << class MyApp methods >> (5 of 22) def OnInit(self): self.setItems() self.InitSpeech() self.frame = wxFrame(NULL, -1, "Speech tester", wxPoint(10,10), wxSize(770,300)) self.listBox = wxListBox(self.frame, self.LISTBOX_ID, wxPoint(10, 10), wxSize(120, 200), self.items.keys(), wxLB_SINGLE) self.addButton = wxButton(self.frame, self.ADD_BUTTON_ID, "Add", wxPoint(10,230), wxSize(50, 30)) self.deleteButton = wxButton(self.frame, self.DELETE_BUTTON_ID, "Delete", wxPoint(80, 230), wxSize(50, 30)) self.editor = wxTextCtrl(self.frame, self.EDITOR_ID, "", wxPoint(140,10), wxSize(600,200), style=wxSUNKEN_BORDER+wxTE_MULTILINE+wxTE_PROCESS_TAB) self.testButton = wxButton(self.frame, self.TEST_BUTTON_ID, "Test", wxPoint(140, 230), wxSize(50, 30)) self.turnonButton = wxButton(self.frame, self.TURNON_BUTTON_ID, "On", wxPoint(210, 230), wxSize(50, 30)) self.turnoffButton = wxButton(self.frame, self.TURNOFF_BUTTON_ID, "Off", wxPoint(280, 230), wxSize(50, 30)) self.SetUpTaskbar() EVT_LISTBOX(self, self.LISTBOX_ID, self.OnListBoxSelect) EVT_BUTTON(self, self.ADD_BUTTON_ID, self.OnAddClick) EVT_BUTTON(self, self.DELETE_BUTTON_ID, self.OnDeleteClick) EVT_BUTTON(self, self.TEST_BUTTON_ID, self.OnTestClick) EVT_BUTTON(self, self.TURNON_BUTTON_ID, self.OnTurnOnClick) EVT_BUTTON(self, self.TURNOFF_BUTTON_ID, self.OnTurnOffClick) EVT_TEXT(self, self.EDITOR_ID, self.OnTextEntered) EVT_ICONIZE(self.frame, self.OnIconize) EVT_CLOSE(self.frame, self.OnExitFrame) self.listBox.SetSelection(0) self.displayTextBox() self.frame.Show(true) self.SetTopWindow(self.frame) return true # << class MyApp methods >> (6 of 22) def OnExitFrame(self, event): pickle.dump(self.items, open(self.SAVE_FILENAME, 'w')) if hasattr(self, "tbicon"): del self.tbicon self.frame.Destroy() # << class MyApp methods >> (7 of 22) def OnIconize(self, event): self.frame.Show(false) # << class MyApp methods >> (8 of 22) def OnAddClick(self,event): dlg = wxTextEntryDialog(self.frame, 'Text to recognize', "New item") if dlg.ShowModal() == wxID_OK: self.items[dlg.GetValue()] = "" self.resetItemsList() self.listBox.SetStringSelection(dlg.GetValue()) self.displayTextBox() self.SetWords() dlg.Destroy() # << class MyApp methods >> (9 of 22) def OnDeleteClick(self,event): del self.items[ self.listBox.GetStringSelection() ] self.resetItemsList() self.listBox.SetSelection(0) self.displayTextBox() self.SetWords() # << class MyApp methods >> (10 of 22) def OnListBoxSelect(self,event): self.displayTextBox() # << class MyApp methods >> (11 of 22) def OnTestClick(self, event): self.executeItemInList(self.listBox.GetStringSelection()) # << class MyApp methods >> (12 of 22) def OnTextEntered(self, event): self.items[self.listBox.GetStringSelection()] = event.GetString() # << class MyApp methods >> (13 of 22) #--------------------------------------------- # This is code to use the system tray taken from the wxPython demo TBMENU_RESTORE = 1000 TBMENU_CLOSE = 1001 def OnTaskBarActivate(self, evt): if self.frame.IsIconized(): self.frame.Iconize(false) if not self.frame.IsShown(): self.frame.Show(true) self.frame.Raise() # << class MyApp methods >> (14 of 22) def OnTaskBarMenu(self, evt): menu = wxMenu() menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo") menu.Append(self.TBMENU_CLOSE, "Close") self.tbicon.PopupMenu(menu) menu.Destroy() # << class MyApp methods >> (15 of 22) def OnTaskBarClose(self, evt): self.frame.Close() # because of the way wxTaskBarIcon.PopupMenu is implemented we have to # prod the main idle handler a bit to get the window to actually close wxGetApp().ProcessIdle() # << class MyApp methods >> (16 of 22) #--------------------------------------------- def displayTextBox(self): self.editor.SetValue( self.items[self.listBox.GetStringSelection()] ) # << class MyApp methods >> (17 of 22) def executeItemInList(self,itemName): codeToExecute = self.items[itemName] try: exec codeToExecute except: etype, value, tb = sys.exc_info() message = (str(etype)+":"+str(value)+ "\nat line "+`tb.tb_next.tb_lineno`) dlg = wxMessageDialog(self.frame, message, 'Exception: '+str(etype), wxOK | wxICON_INFORMATION) dlg.ShowModal() dlg.Destroy() # << class MyApp methods >> (18 of 22) def resetItemsList(self): self.listBox.Set(self.items.keys()) # << class MyApp methods >> (19 of 22) def OnTurnOnClick(self, event): self.turnOn() # << class MyApp methods >> (20 of 22) def OnTurnOffClick(self, event): self.turnOff() # << class MyApp methods >> (21 of 22) def turnOn(self): if not self.turnedOn: self.turnedOn = true self.SetWords() # << class MyApp methods >> (22 of 22) def turnOff(self): if (self.turnedOn): self.turnedOn = false self.SetWords() # -- end -- << class MyApp methods >> # -- end -- << SpeechGui methods >> app = MyApp(0) app.MainLoop()