Grammatiken - dialogos-project/dialogos GitHub Wiki
Spracherkenner-Knoten in DialogOS verwenden Grammatiken, um die möglichen Äußerungen des Benutzers zu definieren. Dies schränkt die möglichen Äußerungen ein, die der Spracherkenner unterscheiden können muss, und erhöht deshalb die Genauigkeit des Spracherkenners - solange der Benutzer sich an die Äußerungen hält, die die Grammatik erlaubt.
Sie können eine Grammatik für den Spracherkenner auf verschiedene Weisen definieren:
- Indem Sie Schlüsselwörter angeben (DirectGrammar, "<Aus den Alternativen generieren>");
- indem Sie Ihre eigene Grammatik schreiben;
- indem Sie Programmcode schreiben, der eine Grammatik erzeugt (DynamicGrammar, "<Aus Ausdruck generieren>")
Aus den Alternativen generieren
Wenn Sie in einem Spracherkenner-Knoten unter "Grammatik" den Eintrag "<Aus den Alternativen generieren>" auswählen, erzeugt DialogOS automatisch eine Grammatik, die genau die Schlüsselwörter angibt, die Sie in der Liste mit dem Titel "Alternativen" angegeben haben. Der Knoten bekommt so viele ausgehende Ports, wie die Liste Einträge hat.
Im einfachsten Fall ist jede Alternative ein einzelnes Schlüsselwort ("ja", "nein" usw.) oder eine Phrase ("Ich will Pizza"). Sie können zum Beispiel zwei Einträge "ja" und "nein" in der "Alternativen"-Liste anlegen. Der Spracherkenner wird dann die beiden Wörter "ja" und "nein" zu erkennen versuchen. Der Knoten hat zwei ausgehende Ports - einen für jede der beiden Alternativen.
Sie können außerdem einen Timeout-Port anlegen, indem Sie im Reiter "Optionen" eine Zeitbegrenzung angeben. Dieser Port wird als rotes Dreieck auf der Unterseite Ihres Knotens angezeigt. Der Knoten wird durch diesen Knoten verlassen, wenn der Spracherkenner innerhalb der angegebenen Zeit keine Benutzer-Äußerung erkennen kann.
Der Spracherkenner wird versuchen, jede Äußerung des Benutzers auf eine der Alternativen abzubilden. Wenn der Benutzer also z.B. im Beispiel oben "vielleicht" sagen, kann dies unter Umständen als "ja" oder "nein" erkannt werden. Sie können einstellen, wie sicher sich der Spracherkenner über sein Ergebnis sein muss, um es zu akzeptieren, indem Sie im Reiter "Optionen" die Konfidenz-Schwelle ändern. Ein höherer Wert sagt dem Erkenner, dass er lieber gar nichts erkennt, wenn er sich unsicher ist.
Die Option "Überschüssige Wörter zulassen" im Reiter "Optionen" erlaubt dem Spracherkenner, eine Alternative auch dann zu matchen, wenn der Benutzer zusätzliche Wörter gesagt hat. Wenn zum Beispiel unter "Alternativen" die Option "Ich will Pizza" angegeben ist, darf der Benutzer in diesem Fall auch "Ich will eine große Pizza" sagen.
Fortgeschrittene Alternativen
Über einfache Schlüsselwörter hinaus können Sie fortgeschrittene Alternativen angeben, indem Sie beliebige Symbole verwenden, die Sie auch auf der rechten Seite einer Grammatik-Regel verwenden können (siehe unten). Zulässig sind zum Beispiel die folgenden Alternativen:
ja
eins plus zwei
Ich will eine (große|kleine) Pizza.
ja +
Anders als bei der Verarbeitung von Werten, die von einer Grammatik zurückgegeben werden, können Sie allerdings bei der Option "Aus den Alternativen generieren" keine beliebigen Muster verwenden. Insbesondere können Sie nicht das Muster für reguläre Ausdrücke /.../ = (variable)
verwenden, um einen Teil Ihres Erkenner-Ergebnisses in einer Variable zu speichern. Wenn Sie solche Muster verwenden möchten, sollten Sie selbst eine Grammatik schreiben (siehe unten).
Grammatiken
Wenn Sie flexibler angeben möchten, was der Benutzer sagen kann, können Sie von Hand eine Grammatik für den Spracherkenner schreiben. Die Grammatiken, die in Ihrem Dialog verfügbar sind, können Sie unter dem Menüpunkt Graph -> Grammatiken verwalten.
Einfache Grammatiken
DialogOS verwendet kontextfreie Grammatiken, die in einem Dialekt des Speech Recognition Grammar Format (SRGF) aufgeschrieben werden. Die folgende Beispielgrammatik (übernommen von Uwe Debachers DialogOS-Seite) akzeptiert Varianten von "ja" und "nein":
language "Deutsch";
root $JaNein;
$JaNein = $Ja | $Nein;
$Ja = Ja | Jau | Jo ;
$Nein = Nein | Nee | Nö ;
Diese Grammatik verwendet die Nichtterminal-Symbole $JaNein
, $Ja
und $Nein
, um die Wörter "ja", "jau", "jo", "nein", "nee" und "nö" zu akzeptieren. Mit der root
-Deklaration in der zweiten Zeile wird das Symbol $JaNein
als Startsymbol festgelegt. Der Spracherkenner wird versuchen, eine Äußerung zu erkennen, die von diesem Startsymbol abgeleitet wird, und dann den erkannten String zurückgeben.
Die Zeile language "Deutsch"
legt die Sprache der Grammatik als "deutsch" fest. Diese Angabe ist optional; stattdessen können Sie die Sprache auch im Spracherkenner-Knoten oder in den globale Spracherkenner-Einstellungen angeben. Wenn die Grammatik eine language
-Zeile enthält, überschreibt diese die anderen Angaben.
Auf der rechten Seite jeder Regel können Sie Symbole (wie z.B. |
) verwenden, um anzugeben, wie das Nichtterminal-Symbol auf der linken Seite expandiert werden kann. Die folgenden Symbole werden unterstützt:
| logisches Oder (matcht sowohl den Ausdruck links als auch rechts vom Strich)
( ) Sequenz: fasst Ausdrücke zusammen
[ ] optional: Ausdruck in den Klammern kann in der Eingabe stehen oder auch nicht
+ wiederholt einen Ausdruck beliebig oft (mindestens einmal)
* wiederholt einen Ausdruck beliebig oft (mindestens null-mal)
Zum Beispiel matcht die Regel $Ja = ja +
die Äußerungen ja
, ja ja
, ja ja ja
usw.
Muster
Wenn die Grammatik die Äußerung des Benutzers als grammatisch korrekt erkannt hat, wird im Normalfall die erkannte Äußerung zurückgegeben - also mit der Beispielgrammatik oben z.B. der String Jau
. Sie können diese Äußerung dann gegen beliebig viele Muster matchen, die Sie in der Liste "Eingabemuster" angeben können. Der Spracherkenner-Knoten hat einen ausgehenden Port für jedes Eingabemuster, und DialogOS wird den Knoten durch den Port für das erste Muster verlassen, der die erkannte Äußerung matcht.
Ihr Muster kann einen regulären Ausdruck /.../ = (variable)
enthalten. Damit können Sie einen Teil der Äußerung extrahieren und in einer Variable abspeichern.
Tags
Für die oben angegebene Beispielgrammatik würde man typischerweise zwei Eingabemuster angeben: eines für Ja | Jau | Jo
und eines für Nein | Nee | Nö
. Das macht für einfache Grammatiken Sinn, aber kann für komplexere Grammatiken schnell zu kompliziert werden.
Um die Muster zu vereinfachen, können Sie in der Grammatik angeben, dass statt der kompletten Äußerung ein Tag zurückgegeben werden soll. Dies kann z.B. folgendermaßen aussehen:
language "Deutsch";
root $JaNein;
$JaNein = $Ja {$ = "Positiv"} | $Nein {$ = "Negativ"};
$Ja = Ja | Jau | Jo ;
$Nein = Nein | Nee | Nö ;
Diese Grammatik erkennt die gleiche Sprache wie die oben angegebene Beispielgrammatik ("Ja", "Nö" usw.). Allerdings gibt sie an DialogOS als Wert nicht diese Wörter zurück. Stattdessen wird für die Äußerungen Ja
, Jau
oder Jo
den Wert Positiv
zurück und für die Äußerungen Nein
, Nee
und Nö
den Wert Negativ
. Der Spracherkenner-Knoten muss dann nur noch zwischen den Werten Positiv
und Negativ
unterscheiden und nicht zwischen den einzelnen Wörtern.
Tags werden angegeben, indem der Variable $
Werte zugewiesen werden.
Tags an Eltern weitergeben
Manchmal ist es nützlich, den Wert eines Nichtterminals auf der rechten Seite einer Regel an das Nichtterminal auf der linken Seite weiterzugeben. Dazu kann man der Variablen $
(= Wert für das Nichtterminal auf der linken Seite) die Variable $kind
zuweisen (= Wert für das Nichtterminal $kind
auf der rechten Seite). Die folgende Grammatik gibt z.B. für die Äußerung eins
den DialogOS-String "1"
zurück.
root $input;
$input = $number { $ = $number };
$number = eins {$ = "1"};
Dabei ist wichtig, dass in der Regel $input = $number
ein Wert für den $
-Tag angegeben wird. Ansonsten wird einfach die komplette Äußerung zurückgegeben - auch wenn die Regel für $number
einen Tag verwendet hat. Beispielsweise gibt die folgende Grammatik für die Äußerung eins
nicht "1"
zurück, sondern einfach die Äußerung eins
selbst.
root $input;
$input = $number;
$number = eins {$ = "1"};
Tags, Datentypen und Ausdrücke
Jeder Tag in DialogOS hat einen Datentyp. Sie können in einer Grammatik den Wert eines Tags als den Wert eines beliebigen Ausdrucks berechnen lassen, der die Werte der Kinder-Tags als Variablen verwenden kann. Dies wird in der folgenden Grammatik illustriert:
language "Deutsch";
root $calculator;
$calculator = ($numberA plus $numberB) { $ = $numberA + $numberB; };
$numberA = $number { $ = parseInt($number); };
$numberB = $number { $ = parseInt($number); };
$number = "eins" { $ = "1"} | "zwei" { $ = "2" };
Hier einige interessante Beobachtungen über diese Grammatik:
- Den Wörtern "eins" und "zwei" werden die Tags
"1"
und"2"
zugewiesen (als Werte von Datentyp "String"). - Diese Strings werden in den Regeln für
$numberA
und$numberB
in int-Werte konvertiert. - Die Regel für
$calculator
addiert die int-Werte, die von den Nichtterminalen$numberA
und$numberB
berechnet wurden, und gibt das Ergebnis zurück (als Wert vom Typ int).
Sie können diesen int-Wert im Spracherkenner-Knoten mithilfe des reguläre-Ausdrücke-Musters einer DialogOS-Variable zuweisen. Diese Variable muss dann ebenfalls vom Datentyp "int" sein (nicht String), damit sie einen int-Wert enthalten kann.
Eine Grammatik mit Programmcode erzeugen
Manchmal ist es nützlich, eine Grammatik erst dann zu erzeugen, wenn der Dialog schon ausgeführt wird. Zum Beispiel möchte man manchmal eine Liste von Namen aus einer Datenbank auslesen und dann eine Grammatik erzeugen, die alle diese Namen versteht. In DialogOS kann man zu diesem Zweck eine dynamische Grammatik verwenden.
Um eine dynamische Grammatik zu verwenden, gehen Sie wie folgt vor.
- Definieren Sie eine String-Variable (z.B.
grammatik
) im Menüpunkt Graph -> Variablen. Diese Variable wird Ihre Grammatik enthalten. - Fügen Sie zu Ihrem Dialog einen Skript-Knoten hinzu und schreiben Sie Ihre Grammatik als String in die
grammatik
-Variable. - Wählen Sie in Ihrem Spracherkenner-Knoten unter dem Punkt "Grammatik" die Option "<Aus Ausdruck generieren>" aus. Klicken Sie auf den Button "Bearbeiten" und geben Sie dort die Variable an, die Ihre Grammatik enthält (
grammatik
).
Ihr Skript kann beliebigen DialogOS-Skript-Code verwenden, um Ihre Grammatik zu berechnen. Hier ist ein einfaches Beispiel:
grammatik = "root $Input;\n";
grammatik += "$Input = hallo;\n";
Dieses Skript setzt die Variable grammatik
auf den folgenden Wert:
root $Input;
$Input = hallo;
Grammatiken, die Sie in einem Skriptknoten erzeugen, folgen der gleichen Syntax wie Grammatiken, die Sie von Hand schreiben. Deshalb akzeptiert diese Grammatik die Äußerung "hallo" und gibt diese dann als String-Wert zurück.