Notice: This forum has been recovered from an old backup, so some content, links, and dates may be outdated. The forum is currently read-only while we restore sign-in and registration functionality. Details

If you find this forum valuable and would like to help keep it online, donations to help cover hosting and domain costs are greatly appreciated, but never expected. You can support the forum through Buy Me a Coffee or Ko-fi. Thank you for helping preserve the EventGhost community.

Sapi.SpVoice

Allgemeines zum Thema EventGhost
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

So hat ich's mir vorgestellt ! :D

Lässt du EG mittlerweile vom Source-Code laufen? Ich glaube nämlich win32com.Dispatch läuft so nicht direkt bei den Leuten mit einer EXE Installation von EG, weil dieses dynamische Erzeugen der Wrapper über gen_py nicht drin ist. Dafür musste ich bisher immer das erzeugte Interface-File selber in das Plugin legen.
Momentan hab ich EG als exe am laufen. (Windows Image neu aufgespielt, nur Active Python und EG installiert.)

Soweit ich weiß, ist Sapi Voice ein Teil der XP Standart Installation, nur die Spracherkennung muß extra installiert werden.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

MonsterMagnet wrote:Momentan hab ich EG als exe am laufen. (Windows Image neu aufgespielt, nur Active Python und EG installiert.)
Hmm, dann scheint es doch dynamischen Dispatch zu machen. M├╝sste man nur mal auf einer Kiste ausprobieren, die sicher kein Python drauf hat.
MonsterMagnet wrote:Soweit ich weiß, ist Sapi Voice ein Teil der XP Standart Installation, nur die Spracherkennung muß extra installiert werden.
Spracherkennung? Da haben wir ja schon ein neues Plugin-Projekt. :)
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

Bin schon dabei...

1.MS Agent(Sapi 4)

2.Sapi.SpSharedRecognizer(Sapi 5)

Meiner Meinung nach, ist die Erkennungsrate bei einem W├Ârterbuch bis 100 Eintr├ñge identisch zu MS Agent,
das Mikrofon und die Umgebungsgeräusche sind das Ausschlaggebende.

3.Alternative Spracherkennungs Engine

Auch wenn MS Agent total veraltet ist und auch nie den Durchbruch geschafft hat, w├╝rde ich diese Variante bevorzugen(Resourcenverbrauch).

Was meinst Du ?
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Keine Ahnung, ich hab damit noch nie experimentiert. Setzen alternative Sprach-Engines dann nicht auch auf SAPI auf?
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

http://cmusphinx.sourceforge.net/html/cmusphinx.php

Sieht ziemlich eigenständig aus, aber auch kompliziert und um
vielleicht 20 W├Ârter zu erkennen reicht die MS Sapi 4/5 wohl.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Ja, viel mehr als ein paar Kommando-W├Ârter wird man selten brauchen. Und wenn es tats├ñchlich mal einen Hype daf├╝r gibt, kann man ja noch immer ein Plugin f├╝r eine andere Lib bauen. Hauptsache man hat zuerst mal was, dass wirklich etwas tut.
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

Das hier funktioniert echt gut.

http://surguy.net/articles/speechrecognition.xml

Ich glaube darauf sollte man aufbauen.
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

Also bevor Du nachher wieder alles ins Reine bringen mußt, ist es vielleicht besser Du übernimmst ab hier.
Das ganze funktioniert echt besser als ich dachte.

Habe das Ergebniss von makepy Microsoft Speech Object Library 5.1 ins Plugin Verzeichniss gelegt und voice genannt.

C866CA3A-32F7-11D2-9602-00C04F8EE628x0x5x0.py

Code: Select all

from win32com.client import constants
import win32com.client
import voice
import eg

wordsToAdd = [ "One", "Two", "Three", "Four" ]

class SpeechRecognition(eg.PluginClass):
    
    def __start__(self):

        self.speaker = win32com.client.Dispatch("SAPI.SpVoice")

        self.listener = win32com.client.Dispatch("SAPI.SpSharedRecognizer")

        self.context = self.listener.CreateRecoContext()
        self.grammar = self.context.CreateGrammar()

        self.grammar.DictationSetState(0)

        self.wordsRule = self.grammar.Rules.Add("wordsRule",
                        constants.SRATopLevel + constants.SRADynamic, 0)

        self.wordsRule.Clear()

        [ self.wordsRule.InitialState.AddWordTransition(None, word) for word in wordsToAdd ]

        self.grammar.Rules.Commit()
        self.grammar.CmdSetRuleState("wordsRule", 1)

        self.grammar.Rules.Commit()

        self.eventHandler = ContextEvents(self.context)

        self.speaker.Speak("Speech Recognition started successfully")

class ContextEvents(win32com.client.getevents("SAPI.SpSharedRecoContext")):

    def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result):
        newResult = win32com.client.Dispatch(Result)
        eg.TriggerEvent(newResult.PhraseInfo.GetText())
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Ich muss erstmal ein Mikrofon besorgen... :)
Mein Headset ist neulich abgeraucht.
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

Also ich hab mich nochmal dran versucht, der folgende Code ist erstmal nur
ein Grundger├╝st(hab mir das Speech SDK noch nicht genauer angesehen).

Jetzt hätt ich mal zwei Fragen:

1.Wie bekomme ich Zugriff auf

Code: Select all

win32com.client.getevents("SAPI.SpSharedRecoContext")
2.Wie ersetz ich eg.TriggerEvent mit myplugin.TriggerEvent

Sprich wie bekomm ich die ContextEvents Klasse in den Griff ?

Code: Select all

from win32com.client import constants
import win32com.client
import voice
import eg
import wx

class SpeechRecognition(eg.PluginClass):
   
    def __init__(self):

        self.speaker = win32com.client.Dispatch("SAPI.SpVoice")
        self.listener = win32com.client.Dispatch("SAPI.SpSharedRecognizer")

        self.context = self.listener.CreateRecoContext()
        self.grammar = self.context.CreateGrammar()

        self.grammar.DictationSetState(0) 
        self.eventHandler = self.ContextEvents(self.context)
        self.wordsRule = self.grammar.Rules.Add("wordsRule", constants.SRATopLevel + constants.SRADynamic, 0)
        
    def __start__(self,Commands):
        #self.grammar.CmdSetRuleState("wordsRule", 1)
        self.speaker.Speak("Speech Recognition started")
        
    def __stop__(self):
        #self.grammar.CmdSetRuleState("wordsRule", 0)
        self.speaker.Speak("Speech Recognition halted")

    def __close__(self):
        self.speaker = None
        self.listener = None
        self.eventHandler = None

    def SetupConfigDialog(self, dialog, Commands=["hello","computer"]):        
        sizer = dialog.sizer
        mySizer = wx.FlexGridSizer(cols=2)

        Edit = wx.TextCtrl(dialog, -1,)
        mySizer.Add(Edit, 0, wx.EXPAND|wx.ALL, 5)
        
        CommandsEdit = wx.ListBox(dialog, -1, choices=Commands, style=wx.LB_SINGLE)
        mySizer.Add(CommandsEdit, 0, wx.EXPAND|wx.ALL, 5)

        button1 = wx.Button(dialog, -1, label="Add Command")
        def OnButton1(event):
            newcommand = Edit.GetValue()
            if len(newcommand)> 0:               
                CommandsEdit.Append(newcommand)
                Commands.append(newcommand)
                Edit.Clear()
        button1.Bind(wx.EVT_BUTTON, OnButton1)
        mySizer.Add(button1, 0, wx.EXPAND|wx.ALL, 5)

        button2 = wx.Button(dialog, -1, label="Delete Command")
        def OnButton2(event):
            try:
                Commands.remove (CommandsEdit.GetStringSelection())
                CommandsEdit.Delete(CommandsEdit.GetSelection())
            except:
                pass
        button2.Bind(wx.EVT_BUTTON, OnButton2)
        mySizer.Add(button2, 0, wx.EXPAND|wx.ALL, 5)
        
        sizer.Add(mySizer, 1, wx.EXPAND)
        
        def ReturnResult():
            self.wordsRule.Clear()
            [self.wordsRule.InitialState.AddWordTransition(None, word) for word in Commands ]     
            self.grammar.Rules.Commit()        
            self.grammar.CmdSetRuleState("wordsRule", 1)
            self.grammar.Rules.Commit()
            return [Commands]            
        return ReturnResult
    
    class ContextEvents(win32com.client.getevents("SAPI.SpSharedRecoContext")):        

        def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result):            
            newResult = win32com.client.Dispatch(Result)
            eg.TriggerEvent(newResult.PhraseInfo.GetText())
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Frage 1. habe ich nicht ganz verstanden. Zugriff brauchst du darauf ja nicht, weil die Klasse einfach nur als eine Art Callback registriert wird und dann automatisch aufgerufen wird. Interessant ist ja nur, wie man dann in OnRecognition wieder auf das Plugin verweisen kann. Daf├╝r fallen mir auf die Schnelle zwei L├Âsungen ein:

1. Die ContextEvents-Klasse innerhalb der Plugin.__init__ (oder __start__) definieren und dann einem Attribut die Referenz auf das Plugin zuweisen:

Code: Select all

class SpeechRecognition(eg.PluginClass):
   
    def __start__(self):
        ...
        class ContextEvents(win32com.client.getevents("SAPI.SpSharedRecoContext")):
            plugin = self # <= self ist hier die Plugin-Instanz
            
            def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result):
                # self ist hier die ContextEvents-Instanz
                newResult = win32com.client.Dispatch(Result)
                self.plugin.TriggerEvent(newResult.PhraseInfo.GetText())
        ...
        self.eventHandler = ContextEvents(self.context) 


Die zweite M├Âglichkeit w├ñre, dem Konstruktor von ContextEvents die Plugin-Instanz mitzugeben:

Code: Select all

class SpeechRecognition(eg.PluginClass):
   
    def __start__(self):
        ...
        self.eventHandler = ContextEvents(self.context, self) 


class ContextEvents(win32com.client.getevents("SAPI.SpSharedRecoContext")):

    def __init__(self, context, plugin):
        self.plugin = plugin
        ContextEvents.__init__(self, context)
    
    def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result):
        newResult = win32com.client.Dispatch(Result)
        self.plugin.TriggerEvent(newResult.PhraseInfo.GetText())
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

Danke, ich glaub das hilft mir erst mal weiter, bis das ganze so läuft wie ich mir das vorstelle wird es wohl noch ein paar Fragen dauern.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

├ähm, die zweite L├Âsung ist Schwachsinn. Die w├╝rde zu einer Endlosschleife f├╝hren. :)
Man m├╝sste die dann eher so in der Art schreiben:

Code: Select all

class ContextEventsBase(win32com.client.getevents("SAPI.SpSharedRecoContext")):
    pass


class ContextEvents(ContextEventsBase):

    def __init__(self, context, plugin):
        self.plugin = plugin
        ContextEventsBase.__init__(self, context)
   
    def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result):
        newResult = win32com.client.Dispatch(Result)
        self.plugin.TriggerEvent(newResult.PhraseInfo.GetText())
MonsterMagnet
Plugin Developer
Posts: 137
Joined: Fri Feb 10, 2006 12:04 pm

Post by MonsterMagnet »

Das ist f├╝rs Erste mal bei rausgekommen:

Code: Select all

from win32com.client import constants
import win32com.client
import voice
import eg
import wx

class SpeechRecognition(eg.PluginClass):
   
    def __init__(self):        
        try:
            self.listener = win32com.client.Dispatch("SAPI.SpSharedRecognizer")
        except:
            eg.PrintError ("Cannot create SpeechRecognition object")
            return
        
        maingroup = self.AddGroup(self.name)
        maingroup.AddAction(self.SpeechRules)
        
        self.context = self.listener.CreateRecoContext()
        self.grammar = self.context.CreateGrammar()

        self.grammar.DictationSetState(0) 
        self.eventHandler = ContextEvents(self.context, self)
        self.wordsRule = self.grammar.Rules.Add("wordsRule", constants.SRATopLevel + constants.SRADynamic, 0)
   
    def __start__(self):        
        try:
            self.grammar.CmdSetRuleState("wordsRule", 1)
        except:
            pass
                
    def __stop__(self):        
        self.grammar.CmdSetRuleState("wordsRule", 0)
        
    def __close__(self):        
        self.listener = None
        self.eventHandler = None
        self.grammar = None
        self.wordsRule = None
        
    class SpeechRules(eg.ActionClass):
       
        def __call__(self, Commands, Rule):
            wordsRule = self.plugin.wordsRule
            grammar = self.plugin.grammar            
            wordsRule.Clear()
            [wordsRule.InitialState.AddWordTransition(None, word)for word in Commands ]     
            grammar.Rules.Commit()        
            grammar.CmdSetRuleState("wordsRule", 1)
            grammar.Rules.Commit()        
           
        def GetLabel(self, Commands, Rule):
            return "SpeechRecognition: %s" % Rule
       
        def SetupConfigDialog(self, dialog, Commands=["hello"], Rule="Rule1"):
        
            sizer = dialog.sizer
            mySizer = wx.FlexGridSizer(cols=2)
                        
            desc1 = wx.StaticText(dialog, -1, "Rule Name:")
            mySizer.Add(desc1, 0,  wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5)
            
            Name = wx.TextCtrl(dialog, -1,Rule)
            mySizer.Add(Name, 0, wx.EXPAND|wx.ALL, 5)
            
            Edit = wx.TextCtrl(dialog, -1,)
            mySizer.Add(Edit, 0, wx.EXPAND|wx.ALL, 5)
        
            CommandsEdit = wx.ListBox(dialog, -1, choices=Commands, style=wx.LB_SINGLE)
            mySizer.Add(CommandsEdit, 0, wx.EXPAND|wx.ALL, 5)

            button1 = wx.Button(dialog, -1, label="Add Command")
            def OnButton1(event):
                newcommand = Edit.GetValue()
                if len(newcommand)> 0:               
                    CommandsEdit.Append(newcommand)
                    Edit.Clear()
            button1.Bind(wx.EVT_BUTTON, OnButton1)
            mySizer.Add(button1, 0, wx.EXPAND|wx.ALL, 5)

            button2 = wx.Button(dialog, -1, label="Delete Command")
            def OnButton2(event):
                try:
                    CommandsEdit.Delete(CommandsEdit.GetSelection())
                except:
                    pass
            button2.Bind(wx.EVT_BUTTON, OnButton2)
            mySizer.Add(button2, 0, wx.EXPAND|wx.ALL, 5)
        
            sizer.Add(mySizer, 1, wx.EXPAND)
        
            def ReturnResult():
                Commands =[]
                for i in range (CommandsEdit.GetCount()):
                    Commands.append(CommandsEdit.GetString(i))
                return (Commands, Name.GetValue(),)       
            return ReturnResult

        
class ContextEventsBase(win32com.client.getevents("SAPI.SpSharedRecoContext")):
    
    pass

class ContextEvents(ContextEventsBase):

    def __init__(self, context, plugin):
        self.plugin = plugin
        ContextEventsBase.__init__(self, context)
   
    def OnRecognition(self, StreamNumber, StreamPosition, RecognitionType, Result):
        newResult = win32com.client.Dispatch(Result)
        self.plugin.TriggerEvent(newResult.PhraseInfo.GetText())
Man kann also f├╝r jede Gruppe ob z.B. Musik oder Video eine eigene
Sprachregel erstellen, was die Erkennungsgenauigkeit sehr erh├Âht.
User avatar
Bitmonster
Site Admin
Posts: 2239
Joined: Mon Feb 06, 2006 10:28 pm

Post by Bitmonster »

Wenn ich mal wieder ein Headset habe, probiere ich es mal aus. :)
Werde mir heute mal eines bestellen...
Post Reply