mal wieder Events... oder andere Ideen?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Buell
User
Beiträge: 90
Registriert: Samstag 29. Oktober 2005, 14:17

Hallo,

folgendes Problem:

ich habe ein win32server modul geschrieben, welches so weit auch einwandfrei funtkioniert. Zu diesem win32server modul gibt es verschiedene Client Module (alles momentan nur Testmodule). Das win32server Modul dient zur "Vereinigung" aller möglichen SAPI Schnittstellen also Spracherkennung. Bei einem erkannten Word wird eine Methode/Funktion im win32server Modul ausgeführt. Diese setzt ein Event, was auch wunderbar funktioniert (frei nach diesem Beispiel: Python Cookbook)
Was ich nun natürlich möchte ist, dass die Clients auch das erkannte Word der Spracherkennung bekommen und dies nicht im win32server verbleibt. Dazu gibt es nun natürlich viele verschiedene Wege, ich würde die Realisierung mittels Events favorisieren. Aber genau da liegt das Problem, wie bringe ich die Clients dazu auf Events des win32server Modules zu reagieren? Hatte daran gedacht einfach win32com.client.DispatchWithEvents(...) zu verwenden, aber das bringt mir folgende Fehlermeldung:
TypeError: This COM object can not automate the makepy process - please run makepy manually for this object
Verwundert mich etwas, denn die COM Schnittstelle wird ja durch ein py Skript (das win32server Modul) erzeugt. Makepy aus py hört sich für mich etwas komisch an.
Momentan realisiere ich den Datentransport mittels SendKeys(), was einfach nur eine Tastatureingabe realisiert, funktioniert einwandfrei, ist jedoch nicht die elegante Lösung. Lustigerweise kann ich mit dieser Funktion jetzt jedes Programm mit Spracherkennung betreiben, lustiger Nebeneffekt. Für den, den es interessiert mal den gesamten Quelltext am Ende dieses Beitrages.

Bin nun sehr gespannt auf kreative Vorschläge!

Bei den folgenden Beispielen fehlen natürlich die Module zur anbindung an die COM Schnittstellen, aber das würde den Rahmen etwas sprengen.

win32server Modul (SpeechServer.py):

Code: Alles auswählen

class TTS:

    '''
    for generating _reg_clsid_ use this:
    >>> import pythoncom
    >>> print pythoncom.CreateGuid()
    {0C26DD80-2846-43C7-A232-301EF1679BAB}


    Property Name           Description
    --------------------    -----------------------------
    _reg_clsid_             The CLSID of the COM object

    _reg_progid_            The "program ID", or Name, of the COM Server.
                            This is the name the user usually uses to instantiate the object

    _reg_desc_              The description of the COM Server.
                            Used primarily for COM browsers.

    _reg_class_spec_        A string which represents how Python can create the
                            class instance. The string is of format
                            [package.subpackage.]module.class

                            The portion up to the class name must be valid for
                            Python to "import", and the class portion must be a
                            valid attribute in the specified class.

                            This is (will be!) optional in Python 1.5.

    _public_attrs_          List of all attribute names exposed to remote COM clients

    _readonly_attrs_        List of all attributes which can be accessed, but not set.
    '''
    _reg_clsid_ = "{0C26DD80-2846-43C7-A232-301EF1679BAB}"
    _reg_desc_ = "Python Speech Project TTS COM Server"
    _reg_progid_ = "Python.TTSServer" # This is the name of the Server!!!!!

    # Next line assumes file is "SpeechServer.py"
    _reg_class_spec_ = "SpeechServer.TTS"
    _public_methods_ = ['Hello','EnginesList','TextOut','ChangeEngine']
    _public_attrs_ = ['softspace', 'noCalls']
    _readonly_attrs_ = ['noCalls']

    def __init__(self):
        self.softspace = 1
        self.noCalls = 0

        self.Initial()

    def Initial(self):
        self.engines = self.EnginesList()
        self.cur_engine = 0

        # prepare connect to all engines
        self.tts_import = []
        self.tts = []
        i = 0
        for item in self.engines:
            self.tts_import.append(__import__("TTS." + item, globals(), locals(), item))
            self.tts.append(self.tts_import[i].pySapiOut())
            i += 1
        return None

    # just for testing ;)
    def Hello(self, who):
        self.noCalls = self.noCalls + 1

        # insert "softspace" number of spaces
        return "Hello" + " " * self.softspace + who

    def EnginesList(self):
        engines = ['SAPI4','SAPI5'] # Note: SAPI4 id=0 ...
        return engines
    
    def ChangeEngine(self, engine):
        i = 0
        for item in self.engines:
            if item == engine:
                self.cur_engine = i
            i += 1
        return None

    def TextOut(self, text):
        self.tts[self.cur_engine].MySpeakOut(text)
        return None

class SR:
    _reg_clsid_ = "{EE5DEF6D-6001-41C6-BD5F-2C48AB542A99}"
    _reg_desc_ = "Python Speech Project SR COM Server"
    _reg_progid_ = "Python.SRServer" # This is the name of the Server!!!!!
    _reg_class_spec_ = "SpeechServer.SR"
    _public_methods_ = ['Hello']
    _public_attrs_ = ['softspace', 'noCalls']
    _readonly_attrs_ = ['noCalls']

    def __init__(self):
        self.softspace = 1
        self.noCalls = 0

        self.Initial()

    def Initial(self):
        self.engines = self.EnginesList()
        self.cur_engine = 0

        # prepare connect to all engines
        self.sr_import = []
        self.sr = []
        for item in self.engines:
            self.sr_import.append(__import__("SR." + item, globals(), locals(), item))

        self.ConnectCurEngine()
        return None

    def Hello(self, who):
        self.noCalls = self.noCalls + 1

        # insert "softspace" number of spaces
        return "Hello" + " " * self.softspace + who

    def EnginesList(self):
        engines = ['SAPI5'] # Note: SAPI5 id=0 ...
        return engines

    def ConnectCurEngine(self):
        self.sr = self.sr_import[self.cur_engine].pySapiIn()
        return None

    def DisconnectCurEngine(self):
        return None

    def ChangeEngine(self, new_engine):
        self.DisconnectCurEngine()
        self.cur_engine = GetId()
        self.ConnectCurEngine()
        return None

    def GetId(self, engine):
        i = 0
        answer = 0
        for item in self.engines:
            if item == engine:
                answer = i
            i += 1
        return answer

    def StartServer(self):
        self.sr.running = 1
        return none

    def StopServer(self):
        self.sr.running = 0
        return none

import SendKeys
import thread
import win32event   # see here: http://aspn.activestate.com/ASPN/docs/ActivePython/2.4/pywin32/win32event.html
                    # and here: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/82236
TIMEOUT = 200 #ms

Recognition = win32event.CreateEvent(None, 0, 0, None)
OtherEvent = win32event.CreateEvent(None, 0, 0, None)

class GetSR:
    _reg_clsid_ = "{6A028CFD-8DDD-43E9-BEA9-28ABCCC3DDED}"
    _reg_desc_ = "Python Speech Project GetSR COM Server"
    _reg_progid_ = "Python.GetSRServer" # This is the name of the Server!!!!!
    _reg_class_spec_ = "SpeechServer.GetSR"
    _public_methods_ = ['Hello','OnWordRecognition','OnPhraseRecognition']
    _public_attrs_ = ['softspace', 'noCalls']
    _readonly_attrs_ = ['noCalls']
    '''_dispid_to_func_ = {
            1 : "Recognition"
            }'''

    def __init__(self):
        self.text = ""
        thread.start_new_thread(self._MessagePump,())

    def Hello(self, who):
        self.noCalls = self.noCalls + 1

        # insert "softspace" number of spaces
        return "Hello" + " " * self.softspace + who

    def OnWordRecognition(self, word):
        #print "Recognized:" + word
        self.text = str(word)
        win32event.SetEvent(Recognition)
        SendKeys.SendKeys(str(word), pause = 0.05, with_spaces = False, with_tabs = False, with_newlines = False, turn_off_numlock = True)
        SendKeys.SendKeys("{ENTER}", pause = 0.05, with_spaces = False, with_tabs = False, with_newlines = False, turn_off_numlock = True)
        #SendKeys.SendKeys("{SPACE}", pause = 0.05, with_spaces = False, with_tabs = False, with_newlines = False, turn_off_numlock = True)
        return None

    def OnPhraseRecognition(self, phrase):
        win32event.SetEvent(Recognition)
        return None

    def OnRecognition(self):
        print "yes"
        return None

    def _MessagePump(self):

	while 1:
	    rc = win32event.MsgWaitForMultipleObjects(
		(Recognition,OtherEvent), 
		0, # wait for all = false
		TIMEOUT,  #  (or win32event.INFINITE)
		win32event.QS_ALLEVENTS) # type of input

		# You can call a function here if it doesn't take too long.
		#   It will get executed *at least* every 200ms -- possibly
		#   a lot more, depending on the number of windows messages received.

	    if rc == win32event.WAIT_OBJECT_0:
			# Our first event listed was triggered.
			# Someone wants us to exit.
		self.OnRecognition()
		break
	    elif rc == win32event.WAIT_OBJECT_0+1:
			# Our second event "OtherEvent" listed was set.
			# This is from some other component -
			#   wait on as many events as you need
		break
	    elif rc == win32event.WAIT_OBJECT_0+2:
			# A windows message is waiting - take care of it.
			# (Don't ask me why a WAIT_OBJECT_MSG isn't defined < WAIT_OBJECT_0)
			# Note: this must be done for COM and other windowsy
			#   things to work.
		if pythoncom.PumpWaitingMessages():
                    break # wm_quit
	    elif rc == win32event.WAIT_TIMEOUT:
			# Our timeout has elapsed.
			# Do some work here (e.g, poll something can you can't thread)
			#   or just feel good to be alive.
			# Good place to call watchdog(). (Editor's note: See my "thread lifetime" recepie.)
		pass
	    else:
		raise RuntimeError( "unexpected win32wait return value")
    


if __name__=='__main__':
    # only for python 1.4! import ni
    import win32com.server.register
    win32com.server.register.UseCommandLine(TTS)
    win32com.server.register.UseCommandLine(SR)
    win32com.server.register.UseCommandLine(GetSR)
BeispielClient Sprachausgabe:

Code: Alles auswählen

import win32com.client #Python 1.4 requires import ni

test = win32com.client.Dispatch("Python.TTSServer")
change = test.ChangeEngine("SAPI5")
text = test.TextOut("Hallo World")
BeispielClient Spracherkennung:

Code: Alles auswählen

import win32com.client #Python 1.4 requires import ni
import pythoncom
import win32event

class Test:
    def __init__(self, eventClass=None):
        test = win32com.client.Dispatch("Python.SRServer")
        test2 = win32com.client.DispatchWithEvents("Python.GetSRServer",eventClass)
        self.text = ""
        self.TestFunc()
    def TestFunc(self):
        while 1:
            #pythoncom.PumpWaitingMessages()
            self.text = raw_input("Recognition: ")
            if self.text == "Stop":
                break

class SpeechServerEvents:
    def OnRecoginition(self):
        print "Hallo"


start = Test()
Antworten