#!/usr/bin/env python
#----------------------------------------------------------
# pyCSVoice: Common Sense Voice Recognition Correction
# Developed by Waseem Daher
# For the Software Agents Group
# MIT Media Lab
# Spring 2004
#----------------------------------------------------------
# See http://www.surguy.net/articles/speechrecognition.xml
# for code samples and tips on how to use the
# Microsoft Speech engine in Python
#----------------------------------------------------------

from wxPython.wx import *
import os, sys
sys.path.append('./omcsnet/')
import OMCSNetAPI


NUM_ALTERNATES = 20 # Number of alternates to get from the voice reco engine

# Only attempt to do voice recognition when in Windows
# In GNU/Linux, just disable it so I can work on the interface
if os.name == 'nt':
    from win32com.client import constants
    import win32com.client
    import pythoncom
   
    class VoiceRecoHandler(win32com.client.getevents("SAPI.SpSharedRecoContext")):
        def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result):
            newResult = win32com.client.Dispatch(Result)
            vrAlternates = newResult.Alternates(NUM_ALTERNATES)
            alternates = []
            for alternate in vrAlternates:
                alternates.append(alternate.PhraseInfo.GetText())
            application.mainForm.newSpeech(alternates)
else:
    print "Sorry, this application requires Microsoft Windows"
   
#-- Set up ID constants
for name in ['MAINFRAME', 'TEXTBOX', 'VRALT', 'CNALT', 'ALTERNATES']:
    exec('wxID_%s = wxNewId()' % name)
    
class pyCSVoiceApp(wxFrame):
    def __init__(self, parent, id, title):
        wxFrame.__init__(self, parent, id, title,
                        pos = wxDefaultPosition,
                        size = wxSize(830, 520),
                        style = wxDEFAULT_FRAME_STYLE)
        # -- Let's get a normal-colored background
        self.SetBackgroundColour(wxNamedColour('WHITE'))
        self.Refresh()

        # -- Set up menu bar
        file = wxMenu()
        self.addMenuEvent(file, self.menuChangeReco, '&Pause Recognition', 'Pause the Voice Recognition Engine')
        self.addMenuEvent(file, self.menuExit, 'E&xit', 'Quit Common Sense Voice Recognition Correction')
        help = wxMenu()
        self.addMenuEvent(help, self.menuAbout, 'About this program...', 'About Common Sense Voice Recognition Correction')
        menuBar = wxMenuBar()
        menuBar.Append(file, '&File')
        menuBar.Append(help, '&Help')
        self.SetMenuBar(menuBar)
        
        #-- Set up main input textbox
        self.txtMainInput = wxTextCtrl(parent = self,
                                    id = wxID_TEXTBOX, 
                                    value = '',
                                    pos = wxPoint(10, 20),
                                    size = wxSize(530, 200),
                                    style = wxTE_MULTILINE)
        self.lblMainInput = wxStaticText(self, -1, 'Voice Recognition Results', wxPoint(10,5))

        #-- Set up listboxes of alternates
        self.lstVRAlternates = wxListBox(parent = self,
                                            id = wxID_VRALT,
                                            pos = wxPoint(10, 250),
                                            size = wxSize(250, 200),
                                            style = wxLC_LIST)
        self.lblVRAlternates = wxStaticText(self, -1, 'Voice Recognition Alternates', wxPoint(10,235))
        #self.lstVRAlternates.InsertItems(['Voice Reco Alt 1', 'Voice Reco Alt 2', 'etc.'], 0)

        self.lstCNAlternates = wxListBox(parent = self,
                                            id = wxID_CNALT,
                                            pos = wxPoint(290, 250),
                                            size = wxSize(250, 200),
                                            style = wxLC_LIST)
        self.lblCNAlternates = wxStaticText(self, -1, 'Conceptually-related words', wxPoint(290,235))
        #self.lstCNAlternates.InsertItems(['ConceptNet Alt 1', 'ConceptNet Alt 2', 'etc.'], 0)
        
        self.lstAlternates = wxListBox(parent = self,
                                            id = wxID_ALTERNATES,
                                            pos = wxPoint(550, 20),
                                            size = wxSize(250, 200),
                                            style = wxLC_LIST)
        self.lblAlternates = wxStaticText(self, -1, 'Alternates', wxPoint(550,5))
        #self.lstAlternates.InsertItems(['Alternative 1', 'Alternative 2', 'etc.'], 0)

        # -- Initialize ConceptNet
        self.conceptNet = OMCSNetAPI.OMCSNetAPI()

        # -- Event handler
        EVT_TEXT(self, wxID_TEXTBOX, self.newTextInput)

    def newTextInput(self, event):
        # For now, we just type in one word. Later this needs to get smarter.
        newWord = self.txtMainInput.GetValue()
        newList = newWord.split()
        contextList = self.conceptNet.get_context(newList)
        os.system('cls')
        self.updateContextList(contextList)

    def updateContextList(self, contextList):
        # This also needs to get smarter to make things get older, etc.
        output = []
        for item in contextList:
            output.append("%s (%d%%)" % (item[0], (item[1] * 100)))
        self.lstCNAlternates.Clear()
        self.lstCNAlternates.InsertItems(output, 0)

    def addMenuEvent(self, menu, callbackMethod, label, tooltip, checked=0):
        id = wxNewId()
        EVT_MENU(self, id, callbackMethod)
        item = wxMenuItem(menu, id, label, tooltip, checked)
        menu.AppendItem(item) 
        return item

    def menuExit(self, event):
        # Shut down the VR engine nicely here, please

        # Destroy my window        
        self.Destroy()

    def menuChangeReco(self, event):
        wxMessageBox('This does nothing yet')

    def menuAbout(self, event):
        wxMessageBox('Common Sense Voice Recognition Correction\n\nDeveloped by Waseem Daher for the MIT Media Lab')

    def newSpeech(self, alternatesList = []):
        self.lstVRAlternates.Clear()
        self.lstVRAlternates.InsertItems(alternatesList, 0)
    
class MyApp(wxApp):
    def __init__(self, foo):
        wxApp.__init__(self, foo)

    def InitSpeech(self):
        listener = win32com.client.Dispatch("SAPI.SpSharedRecognizer")
        self.context = listener.CreateRecoContext()
        self.grammar = self.context.CreateGrammar()
        self.grammar.DictationSetState(1) # Enable free-form dictation
            
    def OnInit(self):
        self.mainForm = pyCSVoiceApp(NULL, -1, 'Common Sense Voice Recognition Correction')
        self.mainForm.Show(true)
        if os.name == 'nt':
            self.InitSpeech()
            events = VoiceRecoHandler(self.context)
        self.SetTopWindow(self.mainForm)
        return True

if __name__ == '__main__':
    application = MyApp(0)
    application.MainLoop()


