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)
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")
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()