CustomIntent mit Dialog

Begonnen von gregorv, 03 Oktober 2024, 10:54:24

Vorheriges Thema - Nächstes Thema

Beta-User

Zitat von: gregorv am 19 November 2024, 13:13:04ToDo: Derzeit ist kein Abbruch mit CancelAction möglich.
Weiß nicht, ob das noch stimmt; hatte dazu was in intentCancelAction ergänzt, aber sentences.ini muss was liefern.

Zitat von: gregorv am 19 November 2024, 13:13:04Wenn ein Kommando nicht verstanden wurde, wird die Session beendet.
Bin nicht sicher, ob das der Standard bleiben sollte. Tendiere dazu, das zu ändern und lieber die Gegenausnahme explizit definieren zu lassen.

Zitat von: gregorv am 19 November 2024, 13:13:04noResponse = true:        -> Standard Antwort eines Intent unterdrücken
Hmmm, hatten wir sowas diskutiert? Bin grundsätzlich der Ansicht, dass eine Sprachsteuerung _immer_ eine Rückmeldung geben sollte, wenn man was von ihr will und sie das kapiert hat (ggf. sogar bei/nach "Schluss jetzt", und das sollte eigentlich sogar schon so in CancelAction vorbereitet sein).

Zitat von: gregorv am 19 November 2024, 13:13:04RetryInput = true
Guter neuer Name. Über das gewünschte Verhalten (und auch das Coding drumrum) würde ich erst abschließend nachdenken, wenn wir ansonsten soweit sind.
Zitat von: gregorv am 19 November 2024, 13:13:04
    • SilentClosure = true
-> Session Ende erfolgt ohne Ansage (nur für Custom Intents)
Ähm, also: nach reopen...() wird nach timer-Ablauf still (?) geschlossen. Unterscheidungsmerkmal wäre ggf., dass der key defined ist, aber nicht irgendwie belegt.

Ansonsten kann ich mir vorstellen, dass wir da schon irgendwie einen numerischen Wert (0=> mach es gleich) mitgeben könnten, um einen timeout zu definieren, aber im Moment ist mir das zugegebenermaßen auch noch zu abstrakt, um dazu was qualifizierteres sagen zu können.

Aus einem CustomIntent heraus wäre es jedenfalls auch wichtig unterscheiden zu können, ob man die alte Sitzung fortführen will oder schlicht ein "reopen" haben möchte. Ist aber auch noch sehr abstrakt...

Zitat von: gregorv am 19 November 2024, 13:21:58bzgl. all wäre es zumindest für die Funktion nicht nötig das mehrfach zu verschachteln - oder gibt es da schon eine Funktion, die das so erwartet ?
Was "nötig" ist, werden wir sehen; im Moment gehe ich davon aus, dass wir eine mehrdimensionale Matrix haben werden, die zu durchsuchen ist und bin daher darauf gekommen, dass das uU. eine tiefere Gliederung erforderlich machen könnte. Mal schauen - die Funktion, um das auszuwerten gibt es nämlich auch noch nicht, du bist also im Prinzip "frei". Meine Bitte ist in dem Zusammenhang nur: Belege möglichst wenige keys, damit das ganze einigermaßen übersichtlich bleibt. Anders gesagt: wir brauchen nicht sowas wie ein bmp, sondern ein svg (hoffe, das "Bild" ist einigermaßen klar ;D )...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

gregorv

Heute mal die Tweaks

rhasspyTweaks -> reopenVoiceInput=SetOnOff=blinds=xxx=yyy=zzz=35 macht im tweaks hash das:
  "reopenVoiceInput" => {
    "SetOnOff" => {
      "blinds" => {
        "xxx" => {
          "yyy" => {
            "zzz" => 35
          }
        }
      }
    }
und bei rhasspyTweaks -> reopenVoiceInput=all=35 kommt das raus:
  "reopenVoiceInput" => {
    "all" => 35
  }
Ich hoffe das '=' auch vor dem Wert, statt ':' ist akzeptabel, sonst muss ich noch was dazu bauen.

In habe ich dafür das eingebaut:
        if ($line =~ m{\A[\s]*(reopenVoiceInput)[\s]*=}x) {
            ($tweak, $values) = split m{=}x, $line, 2;
            $tweak = trim($tweak);
            return "Error in $line! No content provided!" if !length $values && $init_done;
            my @parts = split /=/, $values;
            my $value = pop @parts;
            my $ref = \%path;
            foreach my $key (@parts) {
                if ($key eq $parts[-1]) { 
                    $ref->{$key} = $value;
                } else {
                $ref->{$key} = {} unless exists $ref->{$key};
                $ref = $ref->{$key};
                }
            }
            $hash->{helper}{tweaks}{$tweak} = \%path;
            next;
        }
Für rhasspySpecials Änderung in der _analyze_rhassypAttr()
rhasspySpecials -> reopenVoiceInput:all=25
wird im Device hash zu:
  "reopenVoiceInput" => {
    "all" => "25 "
  },
 
mit folgender Codeänderung (einfacher Voeschlag) hat nun jede Option ihr eigenes Segment
        if ($key =~ m{reopenVoiceInput|RetryIntent}x ){ # @@@
            my ($subkey, $val) = split m{\=}x, $val, 2;
            $hash->{helper}{devicemap}{devices}{$device}{$key}{$subkey} = $val;
        }
auf Device-Ebene ist, denke ich, maximal ein SubKey ausreichend (all oder intent oder group. Ich glaube auf Device Ebene wird wohl immer nur all benötigt.
Wenn es, wie bei Tweaks beliebig viele Ebenen sein sollen, kann ich den Tweaks Code in eine sub auslagern und auch bei Specials verwenden.
Die unterschiedliche Schreibweise bei Tweaks und Specials mit der vertauschen Anwendung von : und = ist etwas gewöhnungsbedüftig.

gregorv

#182
ZitatWeiß nicht, ob das noch stimmt;
Stimmt, ich meine,dass Du sowas gesagt hast - ich schau mir das mal an.
ZitatTendiere dazu, das zu ändern und lieber die Gegenausnahme explizit definieren zu lassen
Kein Problem, was soll die Bezeichnung für diesen Schalter sein ?
ZitatHmmm, hatten wir sowas diskutiert?
Auch Hmmm, Du fandest es sogar so gut, dass Du es in jedem Intent schon eingebaut hast. Für mich ist nur wichtig, dass es im CustomIntent drin bleibt.
In dem Szenario: Sonne blendet -> Kommando:Rolladen Zu -> Kommando:Stop -> doch etwas zu früh Stop gesagt -> Kommando:etwas runter ... würden mich ständige Audio Bestätigungen ziemlich stören - ich sehe es ja. Bei 'etwas lauter' sollte Rhasspy auch nicht dazwisch reden. Auch ist das Micro währen der Response ja zu und man muss warten bis eine Ansage fertig ist. noResponse ist übrigens eine Option die nur auf Ebene sentence Sinn macht. Das muss man dann in Rhasspy machen oder ginge das auch im RHASPY Modul ?
ZitatÄhm, also: nach reopen...() wird nach timer-Ablauf still (?) geschlossen
Jep - nicht einstellbar. Die Ansage 'Da hat etwas zu lange gedauert' wäre auch sehr unpassend - die war ja der Grund warum ich silent eingeführt hatte.
Zitatda schon irgendwie einen numerischen Wert (0=> mach es gleich)
Du meinst aber nicht den sessionTimeout der mit reopen gesetzt werden kann ? Da fehlt mir eine Verknüpfung  :)
ZitatWas "nötig" ist, werden wir sehen; im Moment gehe ich davon aus, dass wir eine mehrdimensionale Matrix haben werden
Mit dem Code, den ich ausgeknobelt (ein Post früher) habe kann es hunderte von SubKeys geben und mehrdimensional ist es schon dadurch, dass das für jede Option gilt.
Die Funktion, die da draus dann $data keys macht könnte allerdings sehr auffwändig werden. Die muss ja immer prüfen, ob die SubKeys mit irgendwas gerade matchen um zu entscheiden ob der Key in $data auftaucht.



Beta-User

Zitat von: gregorv am 19 November 2024, 23:31:33Kein Problem, was soll die Bezeichnung für diesen Schalter sein ?
"deactivateVoiceInput"? Vielleicht sollte man "reopenVoiceInput" auch zu "reactivateVoiceInput" umbenennen? Das würde jedenfalls besser zum setter-Namen passen...

ad "noResponse" - ok, als gezielte Aktion macht es uU. Sinn, und wir bauen das auch nicht wieder aus dem Code aus. Aber für den Moment würde ich erst mal keinen Aufwand in "tweaks"/"specials" dazu reinstecken wollen, erst müßte das Prinzip klarer sein. Also kommt der Key bis auf weiteres entweder aus CustomIntent-Verarbeitung oder aus der sentences.ini, nicht aus der Code-Verarbeitung direkt in RHASSPY.

Zitat von: gregorv am 19 November 2024, 23:31:33
Zitatda schon irgendwie einen numerischen Wert (0=> mach es gleich)
Du meinst aber nicht den sessionTimeout der mit reopen gesetzt werden kann ? Da fehlt mir eine Verknüpfung  :)
Der (eventuell noch nicht zu Ende gedachte) Gedanke war, den Timer zu löschen bzw. mit einem anderen Timer zu überschreiben. Geht irgendwie auch um sauberes "cleanup".

Zitat von: gregorv am 19 November 2024, 23:31:33Mit dem Code, den ich ausgeknobelt (ein Post früher) habe kann es hunderte von SubKeys geben und mehrdimensional ist es schon dadurch, dass das für jede Option gilt.
Nun ja, der Code "kann" beliebig gestuft. Das ist aber nicht unbedingt das, was ich mit "mehrdimensional" gemeint hatte. Die "Dimensionen", die mir im Moment dazu auf die Schnelle einfallen: "intent", "gdt", "device (-regex)", vielleicht sogar "value" ("on" könnte anders zu behandeln sein wie "off"?).

Ich meine, dass "confirm" schon in etwa in diese Richtung geht, und dass der Code sehr viel komplexer sein müßte. Schau dir dazu auch an, wie die Gegenrichtung in etwa funktioniert ("needsConfirmation"?) - wir müssen das, was wir vorne zusammenbasteln ja auch hinten wieder durchsuchen...

Ad coding: über den Style sollten wir mal reden...  "Folklore" wie "foreach" baue ich jedenfalls nicht in den Code ein ;D , und warum du einmal "perlcritic"-optimierte Regexe übernimmst, um dann 3 Zeilen später dem Compiler keine genaueren Anweisungen zu übergeben, erkläre ich mir erst mal durch die Uhrzeit, zu der das entstanden ist :P .
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

gregorv

ZitatDas ist aber nicht unbedingt das, was ich mit "mehrdimensional" gemeint hatte
Eher so (für die Tweaks)?
  "reopenVoiceInput" => {
    "Deckenl*" => 39,
    "Lampen" => 38,
    "SetNumeric" => 36,
    "SetOnOff" => 35,
    "blinds" => 37
  }
Das gefällt mir ,ehrlich gesagt, auch besser und macht auch die Auswertung einfacher.

Man könnte sich auch so etwas vorstellen - oder gemischt.
  "reopenVoiceInput" => {
    "(SetOnOff|SetNumeric|light|Lampen|Deckenl*)" => 35
  }

ZitatAd coding: über den Style sollten wir mal reden...
Schon klar, ich bin happy, wenn es funktioniert, Schönheit kommt beim Aufräumen.

gregorv

Man könnte sich auch so etwas vorstellen;
  "reopenVoiceInput" => {
    "(SetOnOff|SetNumeric|blinds|Lampen|Deckenl*)" => 35,
    "blinds" => "(drive-up-time-to-open|35)"
  }
Also bei gdt blind soll er sich den Wert aus attr drive-up-time-to-open holen und 35 als default.

Beta-User

Sorry für die etwas knappe Antwort:

- Zugriffe auf "fremde" Attribute oder Readings sollten wir vermeiden. Der User soll das erforderlichenfalls halt "doppelt" konfigurieren, die Welt ist m.E. zu bunt, um das (mit vertretbarem Aufwand) per Coding abzufangen.
- Wie soll man das auswerten, wenn alles "vermischt" ist? Meine Idee bei vielen Dingen im RHASSPY-Hash war, das "lesbar" zu machen, wie RHASSPY die Angaben interpretiert. Und da muss es ggf. eine Unterscheidung geben zwischen "blinds" als gdt, Gruppenname und Devicename, und "blinds" kann unterschiedliche Zeiten bedeuten für verschiedliche Intents*... Kann also sein, dass sowohl die Notation der Attribut-Zeile in tweaks/specials sehr komplex werden kann, wie auch der Code zur Analyse (Attribut=>RHASSPY-Hash) und Auswertung (RHASSPY-Hash=>konkrete Aktion nach Spracheingabe).
Hoffe, es wird jetzt noch klarer, was mit "mehrdimensional" gemeint ist.

*Insgesamt angemerkt: Eine zu starke Fragmentierung der Intents hatte ich als "wenig hilfreich" empfunden und das weitgehend rückgebaut, so dass es jetzt einige wenige Grundtypen gibt (teils mit Übergangsmöglichkeiten vom einen zum anderen). Aber grade für sowas wie das, was wir grade zusammenfrickeln, ist es sinnvoll, zwischen den verschiedenen Intents unterscheiden zu können. Auch für die Strukturierung der sentences.ini über die passend gefüllten slots wurde "gefühlt" die Trefferquote deutlich erhöht, was an effektiv gesprochenen Anweisungen "umsetzbar"war - schlicht, weil die erkennbaren "Zusammenhänge" trennschärfer formuliert werden können...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

gregorv

#187
@Beta-User
Folgende Überlegung für die sub zur Auswertung:
Ziel ist es die entsprechende Option als Key mit einem passenden Wert zurückzuliefern in $data zu schreiben.
Glossar:
  • Option ist das, was später als Key zurückgeliefert wird
  • Bedingungen sind die Keys, die unter Option im hash stehen
  • Werte ist das was bei diesen Keys als value im hash steht

Ablauf:
Es wird geprüft, ob die Option z.B. reopenVoiceInput im tweak hash vorhanden ist > damit hat man auch gleich den key für das return
Aus $data werden, soweit vorhanden einige Werte gelesen und als list zusammengestellt. Andere Werte, wie z.B. $gdt werden vorher ermittelt.
die Liste sieht z.B so aus:
my @condition_values = split(' ', "all $data->{intent} $data->{Group} $gdt $data->{device} $device $data->{Room} $data->{Type}");Reihenfolge und welche Bedingungen müssen noch festgelegt werden das wären auch gleichzeitig die Elemente, die in rhasspyTweaks verwendet werden können.
Für jeden Bedingungen in dieser Liste werden alle keys aus hash->helper->tweaks->option überprüft, ob es ein Match gibt.
Falls ja, wird der zugehörige Wert ausgelesen und als value für return gespeichert und die loops beendet.
Damit hat man das key-value Paar für den return Wert. Weiterhin erfolgt dann noch die rhasspySpecials Prüfung, die den Wert ggf. überschreibt.
Der Key/Values im hash kann entweder ein einzelnes key-value Paar sein z.B. SetOnOff=35 oder wenn keine unterschiedlichen Werte für mehrere Bedingungen benötigt werden SetNumeric|light|Lampen=36.
Die Key Varianten können 1 zu 1 im Such-Regex verwendet werden z.B.
if ( $condition =~ m{$condition_line}x ) {Im Klartext: SetOnOff =~ m{SetNumeric|light|Lampen}x

Fragen:
  • Wenn ein Treffer gefunden wurde, wird die weitere Suche beendet. M.E. ist das ausreichend - wenn man für eine bestimmte Gruppe was anderes möchte, kann man das über die rhasspySpecials einstellen. Wie siehst Du das?
  • Wenn im o.Beispiel erst ein Treffer bei light erfolgt, bleibt SetNumeric unbeachtet, auch falls der nächste Key für SetNumeric den Wert 20 liefern würde. Das scheint mir kompliziert, weil die Regel für eine irgendwie gewollte Priorisierung fehlt.
  • Wenn z.B. rhasspyGroup identisch ist mit gdt, soll das unterschieden werden?

Und noch was zur Lesbarkeit: Bei einer Einstellung wie reopenVoiceInput=SetOnOff=15 SetNumeric=16 light=17 Lampen=18 Deckenl*=19 blind=25 weiß man bei Intents sofort, was gemeint ist, light ist auch recht sicher gdt, bei allen anderen ist das schon schwierig. Man könnte das verbessern, indem man statt Lampen Group:Lampen einsetzt oder statt Deckenl* name:Deckenl* wenn, sollte das bei allen Bedingungen angegeben werden und macht auch eine Unterscheidung von gleich benannten Bedingungen möglich. Sogar eine Bedingung, die in der Liste der sub noch gar nicht vorgesehen ist - wie irgend ein Wert aus $data (rawInput:) oder sogar dem $hash ($device->{alias}:). Man könnte auf die Liste sogar ganz verzichten.
Ups... jetzt bin ich doch von der Lesbarkeit abgeschweift, ja, ich weiß, 'zu bunt'.





gregorv

ZitatWeiß nicht, ob das noch stimmt; hatte dazu was in intentCancelAction ergänzt, aber sentences.ini muss was liefern.
Habe ich mir angeschaut und die Zeile:
if ( !defined $data_old || defined $data->{resetInput}) {gefunden, also den $data->key resetInput. Den hatte ich in meiner Aufstellung nicht aufgeführt, weil er nie über die Tweaks gesetzt wird, sondern als Wake-Word{resetInput} in einem sentence.
Er bewirkt ja, dass wenn das Wake-Word während eines offenen Dialoges gesprochen wird die nächste MQTT Nachricht von Rhasspy die Session schließt und eine neue aufmacht. In handleIntentCancelAction() bewirkt er, dass das ganze still passiert.

Der andere $data-key ist closeSession, der in der Zeile:
if ( defined $data->{closeSession} ) {der künftig mal bestimmen wird, welche responseId hier gespielt werden soll (shut-up)
Wenn er gesetzt wird, bewirkt er aber, dass nach der Behandlung eines Intent gar keine neue Session aufgemacht wird.
In respond() die Zeile:
if ( $topic ne 'continueSession' && $type eq 'voice' && !defined $data->{closeSession} && ( defined $data->{reopenVoiceInput} || defined $hash->{sessionTimeout} ) ) {Ein gesetztes $data->{closeSession} sollte nicht eine neue Session blockieren, sondern, wenn diese aufgemacht wird, den Intent CancelAktion aktivieren.


Beta-User

Zitat von: gregorv am 21 November 2024, 11:07:24Ein gesetztes $data->{closeSession} sollte nicht eine neue Session blockieren, sondern, wenn diese aufgemacht wird, den Intent CancelAktion aktivieren.
Nope. "closeSession" ist gedacht für "habe fertig und will jetzt nicht mehr mit Rhasspy quatschen!". Ergo darf in dem Fall auch keine neue Sitzung aufgemacht werden, und imo sollte dazu eine (positive) Bestätigung kommen.

Zitat von: gregorv am 21 November 2024, 11:07:24gefunden, also den $data->key resetInput. Den hatte ich in meiner Aufstellung nicht aufgeführt, weil er nie über die Tweaks gesetzt wird, sondern als Wake-Word{resetInput} in einem sentence.
Er bewirkt ja, dass wenn das Wake-Word während eines offenen Dialoges gesprochen wird die nächste MQTT Nachricht von Rhasspy die Session schließt und eine neue aufmacht. In handleIntentCancelAction() bewirkt er, dass das ganze still passiert.
Zum einen: Er kann (wie prinzipiell alle keys) "überall" gesetzt werden, und ich sehe auch keinerlei (sachlich notwendige) Begrenzung auf ein Wakeword in sentences.ini.
Und der key ist schlicht dafür gedacht, alles "auf Anfang" zu stellen, also insbesondere auch alle Intent-Filter (auf den default) zurückzusetzen.
Ob eine neue Sitzung geöffnet werden soll, ist (zumindest im Moment) damit nicht gesagt; so jedenfalls mein aktuelles Verständnis der End-Sektion in sub respond().

Nebeneffekt: Wenn man "CancelAction" aktivieren will, muss man einen anderen key verwenden und das entsprechend ansteuern, CancelAction ist nicht Teil des per default aktivierten Intent-sets.

Nebenbemerkung:
Wenn das das gemeinsame Verständnis der keys ist, müssen wir das demnächst mal in der commandref niederscheiben, damit wir nicht "versehentlich" wieder die Bedeutung ändern, sondern uns selbst an das halten, was wir mal festgelegt haben...

Zitat von: gregorv am 20 November 2024, 23:44:56Folgende Überlegung für die sub zur Auswertung:
imo ist das (bei weitem) "zu flach", das ganze wird ziemlich sicher noch sehr viel komplexer wie die sub getNeedsConfirmation(), und wir sollten auch "andersum" anfangen zu suchen. Also: Wenn "specials" was liefert, sind wir bereits fertig, "tweaks" ist allgemeiner, und die weitere Suche wäre überflüssig/ineffektiv. Das gilt umso mehr für den Fall, dass "specials" auch die Gegenausnahme liefern kann (unter einem anderen "specials"-key).

Wir können das nur im Moment nicht vercoden (bzw. nur einen Platzhalter vorsehen), weil wir für "specials" noch nichts näheres "wissen".

Ich komme aber im Moment bis auf weiteres auch nicht dazu, Code beizusteuern...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

gregorv

ZitatNope. "closeSession" ist gedacht für "habe fertig und will jetzt ...
Vollkommen richtig, allerdings macht die CancelAktion ja schon die Session zu und räumt auf. Danach gibt es den $data->reopenVoiceInput nicht mehr und es wird somit keine neue Session aufgemacht.
Das Problem ist, dass die CancelAktion nicht aktiv ist und closeSession gar nicht erst kommen kann.

Ich habe das so gelöst.
Wenn wir eine neue Session aufmachen (sonst noch was?) dann wird CancelAktion aus der disabled Liste entfernt und somit kann man via CancelAktion z.B. mit 'fertig' oder 'sei still' die Session beenden (mit einer passenden Ansage).

Folgende Code Änderung in der respond():
In Zeile:
if ( $topic ne 'continueSession' && $type eq 'voice' && ( defined $data->{reopenVoiceInput} || defined $hash->{sessionTimeout} ) ) {das closeSession entfernt, weil nicht nötig.
Unmittelbar darunter zwei neue Zeilen eingefügt:
$toDisable = [qw(ConfirmAction Choice ChoiceRoom ChoiceDevice)];
configure_DialogManager($hash, $data->{siteId}, $toDisable);
um CancelAktion aus der disabled Liste zu entfernen. Das weiter oben schn stehende my $toDisable habe ich aus dem ifelse ...herausgezogen

Und in der handleIntentCancelAction
Die Zeile:
if ( (!defined $data_old || defined $data->{resetInput}) && $data->{intent} ne "CancelAction") {das $data->{intent} ne "CancelAction" mit eingesetzt, damit, falls wirklich der Intent gestartet wurde, die Session auch beendet wird (die handleIntentCancelAction kann ja auch von einer anderen sub aus aufgerufen werden)

Die anderen Ansagen werden so bestimmt.
my $response = ( defined $data->{closeSession} ) ? 'CloseSession' : 'DefaultCancelConfirmation'; # @@@
$response = getResponse( $hash, $response );
Hier habe ich eine neue responseId eingeführt, weil die möglichen Ansagen von DefaultConfirmation unpassend sein können z.B. 'wird erledigt' klingt in dieser Situation etwas unpassend.

Unter CancelAction kann mit dem sentence z.B. (fertig|sei still){closeSession:true} die Session mit einer anderen Antwort beendet werden.

ZitatZum einen: Er kann (wie prinzipiell alle keys) "überall" gesetzt werden ...
In einem beliebigen sentence: JA über Tweaks: oder so NEIN und JA, er macht eine neue Session auf. Ich vermute Du verwechselst da etwas ? In der response() spielt er jedenfalls gar keine keine Rolle - nur in der analyzeMQTTmessage() führt er dazu, dass bei jeder MQTT Nachricht egal welche eine neue Session aufgemacht wird. Damit darf resetInput nur mal kurzzeitig gesetzt sein. Da wird übrigens auch die handleIntentCancelAction() aufgerufen, obwohl kein Intent CancelAction vorliegt, um die alte Session sauber zu beenden.

Zitatsollten auch "andersum" anfangen zu suchen
Stimmt, ist effizienter.

ZitatIch komme aber im Moment bis auf weiteres auch nicht dazu, Code beizusteuern
Kein Problem, Ich bau erst mal die getOptions() so, dass die Keys, die für die Einstellungen der neuen Funktionalität erforderlich sind gesetzt werden können, damit man das nicht nur über den Trick []{option:wert} im sentence machen kann.

Beta-User

Hmmm, bitte, wir gehen erst nochmal wieder einen oder zwei Schritte zurück, bevor wir alles mögliche wieder ausbauen, was da mit/für sub _get_sessionIntentFilter vorbereitet war:
Zitat von: Beta-User am 12 November 2024, 11:04:39Da müssen wir jedenfalls nochmal tiefer ran, ich warte mal auf deinen debug-output. Wenn es so jetzt nicht aktiviert wird, bräuchte ich Info, was da konkret via MQTT versendet wird. (für sowas verwende ich üblicherweise mosquitto_sub).

Theoretischer Hintergrund in Kurzform:
Zitat von: Beta-User am 31 Oktober 2024, 15:43:38Bin jetzt mal über den Code und die Doku bei Rhasspy. Dabei ist mir der Unterschied zwischen dem session-intentFilter (JSON-Array mit flachem Text) und dem globalen "configure" (JSON-Array mit Objekten, die an- oder ausgeschaltet sind) wieder deutlich geworden.

Ich komme im Moment nicht zum Testen und muss mich auf theoretische Hinweise beschränken, sorry...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

gregorv

Zitatbevor wir alles mögliche wieder ausbauen, was da mit/für sub _get_sessionIntentFilter vorbereitet war
Da hast Du mich abgehängt - ich habe die _get_sessionIntentFilter noch nie geändert und Du hast sie auch noch nicht erwähnt.
ZitatWenn es so jetzt nicht aktiviert wird,...
.
Was sollte denn aktiviert werden ? Ich teste das gerne, aber ich müsste wissen was zu testen ist, und welches Resultat erwartet wird.

ZitatUnterschied zwischen dem session-intentFilter (JSON-Array mit flachem Text) und ...
In den Logs habe ich zumindest noch nie etwas anderes gesehen, als flachen text für ein intentFilter (ein array in doublequotes). Rhasspy Dialog Manager erwartet auch nur für configure eine Struktur.
Wenn für startSession intentFilter übergeben wird, werden ALLE intents für diese Session deaktiviert, außer denen im Array. Ein Aktivieren vom Intents, die per configure disabled wurden, ist damit nicht möglich.
Für die nächste Session ist wieder das gültig. was vor mal in configure als Struktur gesendet wurde. 
Die einzige Möglichkeit das (sozusagen die default Einstellung) zu ändern, ist erneut configure zu senden, was unsere configure_DialogManager() macht. Die baut die Struktur aber selbst zusammen, wir übergeben in toEnable oder toDisable nur ein Array wie für startSession and diese Funktion.

Das tritt z.B. beim Trainig auf, oder wenn man configure_DialogManager() zur runtime benutzt:
2024.11.22 10:31:24 5: RHASSPY: [RHASSPY.IF] Parse (IO: RHASSPY.MQTT2): Msg: hermes/dialogueManager/configure => {"intents":[{"intentId": "de.fhem:GetTime","enable": true},{"intentId": "de.fhem:Blinds","enable": true},{"intentId": "de.fhem:SetNumeric","enable": true},{"intentId": "de.fhem:ReSpeak","enable": true},{"intentId": "de.fhem:Shortcuts","enable": true},{"intentId": "de.fhem:SetOnOff","enable": true},{"intentId": "de.fhem:DeviceState","enable": true},{"intentId": "de.fhem:GetNumeric","enable": true},{"intentId": "de.fhem:DayNight","enable": true},{"intentId": "de.fhem:GetDate","enable": true},{"intentId": "de.fhem:ConfirmAction","enable": false},{"intentId": "de.fhem:CancelAction","enable": true},{"intentId": "de.fhem:Choice","enable": false},{"intentId": "de.fhem:ChoiceRoom","enable": false},{"intentId": "de.fhem:ChoiceDevice","enable": false}],"siteId": null}
hier z.B das resultat von dem configure_DialogManager() Aufruf, den ich in der respond() eingebaut habe ({"intentId": "de.fhem:CancelAction","enable": true}

Da fällt mir übigens noch ein, dass ich am Ende der Session wieder in den ursprünglichen Zustand herstellen sollte - gerade erledigt. Obwohl es eigentlich ganz schick wäre, wenn man unmittelbar nach dem Wake-Word auch 'oh nein' sagen könnte - da gab es aber ein Aufräum Problem ?.


Beta-User

#193
Zitat von: gregorv am 22 November 2024, 12:03:14Wenn für startSession intentFilter übergeben wird, werden ALLE intents für diese Session deaktiviert, außer denen im Array. Ein Aktivieren vom Intents, die per configure disabled wurden, ist damit nicht möglich.
Das würde dem widersprechen, was wir bisher bei CustomIntents im Code hatten.

Habe jetzt doch einen Kurztest gemacht, folgender Mitschnitt aus mosquitto_sub:
hermes/dialogueManager/sessionStarted {"sessionId": "motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047", "siteId": "motox", "customData": "manual", "lang": null}
hermes/nlu/query {"input": "wie spät ist es", "siteId": "motox", "id": null, "intentFilter": ["de.fhem:SetColor", "de.fhem:SetColorGroup", "de.fhem:SetTimedOnOffGroup", "de.fhem:GetState", "de.fhem:GetNumeric", "de.fhem:SetOnOffGroup", "de.fhem:GetDate", "de.fhem:SetOnOff", "de.fhem:SetTimedOnOff", "de.fhem:siteId2room", "de.fhem:MediaControls", "de.fhem:Shortcuts", "de.fhem:SetScene", "de.fhem:ReSpeak", "de.fhem:SetTimer", "de.fhem:GetOnOff", "de.fhem:SetNumericGroup", "de.fhem:GetTime", "de.fhem:SetNumeric"], "sessionId": "motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047", "wakewordId": "manual", "lang": null, "customData": "manual", "asrConfidence": 1.0, "customEntities": null}
hermes/nlu/intentParsed {"input": "wie spät ist es 25", "intent": {"intentName": "de.fhem:GetTime", "confidenceScore": 1.0}, "siteId": "motox", "id": null, "slots": [{"entity": "reopenVoiceInput", "value": {"kind": "Unknown", "value": "25"}, "slotName": "reopenVoiceInput", "rawValue": "", "confidence": 1.0, "range": {"start": 16, "end": 18, "rawStart": 16, "rawEnd": 15}}], "sessionId": "motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047"}
hermes/intent/de.fhem:GetTime {"input": "wie spät ist es 25", "intent": {"intentName": "de.fhem:GetTime", "confidenceScore": 1.0}, "siteId": "motox", "id": null, "slots": [{"entity": "reopenVoiceInput", "value": {"kind": "Unknown", "value": "25"}, "slotName": "reopenVoiceInput", "rawValue": "", "confidence": 1.0, "range": {"start": 16, "end": 18, "rawStart": 16, "rawEnd": 15}}], "sessionId": "motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047", "customData": "manual", "asrTokens": [[{"value": "wie", "confidence": 1.0, "rangeStart": 0, "rangeEnd": 3, "time": null}, {"value": "spät", "confidence": 1.0, "rangeStart": 4, "rangeEnd": 8, "time": null}, {"value": "ist", "confidence": 1.0, "rangeStart": 9, "rangeEnd": 12, "time": null}, {"value": "es", "confidence": 1.0, "rangeStart": 13, "rangeEnd": 15, "time": null}, {"value": "25", "confidence": 1.0, "rangeStart": 16, "rangeEnd": 18, "time": null}]], "asrConfidence": 1.0, "rawInput": "wie spät ist es", "wakewordId": "manual", "lang": null}
hermes/dialogueManager/endSession {"customData": "manual","intentFilter": null,"sessionId": "motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047","siteId": "motox","text": "Es ist 12 Uhr 43"}
hermes/dialogueManager/startSession {"customData": "{\u0022confidence\u0022:1,\u0022customData\u0022:\u0022manual\u0022,\u0022input\u0022:\u0022wie spät ist es 25\u0022,\u0022intent\u0022:\u0022GetTime\u0022,\u0022lang\u0022:null,\u0022rawInput\u0022:\u0022wie spät ist es\u0022,\u0022reopenVoiceInput\u0022:\u002225\u0022,\u0022requestType\u0022:\u0022voice\u0022,\u0022sessionId\u0022:\u0022motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047\u0022,\u0022siteId\u0022:\u0022motox\u0022}","init":{"canBeEnqueued": true,"intentFilter": null,"sendIntentNotRecognized": true,"text": " Weitere Wünsche?","type": "action"},"siteId": "motox"}
hermes/dialogueManager/sessionQueued {"sessionId": "2a1187e2-2a63-4ad3-9a6b-9cfebb7677ed", "siteId": "motox", "customData": "{\"confidence\":1,\"customData\":\"manual\",\"input\":\"wie spät ist es 25\",\"intent\":\"GetTime\",\"lang\":null,\"rawInput\":\"wie spät ist es\",\"reopenVoiceInput\":\"25\",\"requestType\":\"voice\",\"sessionId\":\"motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047\",\"siteId\":\"motox\"}"}
hermes/dialogueManager/sessionEnded {"termination": {"reason": "nominal"}, "sessionId": "motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047", "siteId": "motox", "customData": "manual"}
hermes/dialogueManager/sessionStarted {"sessionId": "2a1187e2-2a63-4ad3-9a6b-9cfebb7677ed", "siteId": "motox", "customData": "{\"confidence\":1,\"customData\":\"manual\",\"input\":\"wie spät ist es 25\",\"intent\":\"GetTime\",\"lang\":null,\"rawInput\":\"wie spät ist es\",\"reopenVoiceInput\":\"25\",\"requestType\":\"voice\",\"sessionId\":\"motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047\",\"siteId\":\"motox\"}", "lang": null}
hermes/nlu/query {"input": "ciao", "siteId": "motox", "id": null, "intentFilter": ["de.fhem:SetColor", "de.fhem:SetColorGroup", "de.fhem:SetTimedOnOffGroup", "de.fhem:GetState", "de.fhem:GetNumeric", "de.fhem:SetOnOffGroup", "de.fhem:GetDate", "de.fhem:SetOnOff", "de.fhem:SetTimedOnOff", "de.fhem:siteId2room", "de.fhem:MediaControls", "de.fhem:Shortcuts", "de.fhem:SetScene", "de.fhem:ReSpeak", "de.fhem:SetTimer", "de.fhem:GetOnOff", "de.fhem:SetNumericGroup", "de.fhem:GetTime", "de.fhem:SetNumeric"], "sessionId": "2a1187e2-2a63-4ad3-9a6b-9cfebb7677ed", "wakewordId": "", "lang": null, "customData": "{\"confidence\":1,\"customData\":\"manual\",\"input\":\"wie spät ist es 25\",\"intent\":\"GetTime\",\"lang\":null,\"rawInput\":\"wie spät ist es\",\"reopenVoiceInput\":\"25\",\"requestType\":\"voice\",\"sessionId\":\"motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047\",\"siteId\":\"motox\"}", "asrConfidence": 0.49159699999999995, "customEntities": null}
hermes/nlu/intentNotRecognized {"input": "ciao", "siteId": "motox", "id": null, "customData": "{\"confidence\":1,\"customData\":\"manual\",\"input\":\"wie spät ist es 25\",\"intent\":\"GetTime\",\"lang\":null,\"rawInput\":\"wie spät ist es\",\"reopenVoiceInput\":\"25\",\"requestType\":\"voice\",\"sessionId\":\"motox-manual-6119e0a7-f231-4789-aab6-f399e0fc8047\",\"siteId\":\"motox\"}", "sessionId": "2a1187e2-2a63-4ad3-9a6b-9cfebb7677ed"}

Interessant ist eigentlich vor allem diese Zeile:
Zitathermes/dialogueManager/startSession {"customData": "{bla}","init":{"canBeEnqueued": true,"intentFilter": null,"sendIntentNotRecognized": true,"text": " Weitere Wünsche?","type": "action"},"siteId": "motox"}
"null" bedeutet in dem Zusammenhang: Nimm den default aus configure. Genau das wollten wir aber eigentlich nicht.

Soweit also das, was nicht funktioniert hat. Ein paar kleine Code-Eingriffe später sieht das jetzt so aus:
hermes/dialogueManager/endSession {"customData": "manual","intentFilter": null,"sessionId": "motox-manual-4df43557-f6ab-4ba1-8eec-bd2fb01a785c","siteId": "motox","text": "Es ist 13 Uhr 14"}
hermes/dialogueManager/startSession {"customData": "{\u0022confidence\u0022:1,\u0022customData\u0022:\u0022manual\u0022,\u0022input\u0022:\u0022wie spät ist es 25\u0022,\u0022intent\u0022:\u0022GetTime\u0022,\u0022lang\u0022:null,\u0022rawInput\u0022:\u0022wie spät ist es\u0022,\u0022reopenVoiceInput\u0022:\u002225\u0022,\u0022requestType\u0022:\u0022voice\u0022,\u0022sessionId\u0022:\u0022motox-manual-4df43557-f6ab-4ba1-8eec-bd2fb01a785c\u0022,\u0022siteId\u0022:\u0022motox\u0022}","init":{"canBeEnqueued": true,"intentFilter":["de.fhem:SetColor","de.fhem:SetColorGroup","de.fhem:SetTimedOnOffGroup","de.fhem:GetState","de.fhem:GetNumeric","de.fhem:SetOnOffGroup","de.fhem:GetDate","de.fhem:SetOnOff","de.fhem:SetTimedOnOff","de.fhem:siteId2room","de.fhem:MediaControls","de.fhem:Shortcuts","de.fhem:SetScene","de.fhem:ReSpeak","de.fhem:SetTimer","de.fhem:GetOnOff","de.fhem:SetNumericGroup","de.fhem:GetTime","de.fhem:SetNumeric","de.fhem:CancelAction"],"sendIntentNotRecognized": true,"text": "Sonst noch was? ","type": "action"},"siteId": "motox"}
hermes/dialogueManager/sessionQueued {"sessionId": "224aecb0-9029-4272-8f06-a9084a16fe5b", "siteId": "motox", "customData": "{\"confidence\":1,\"customData\":\"manual\",\"input\":\"wie spät ist es 25\",\"intent\":\"GetTime\",\"lang\":null,\"rawInput\":\"wie spät ist es\",\"reopenVoiceInput\":\"25\",\"requestType\":\"voice\",\"sessionId\":\"motox-manual-4df43557-f6ab-4ba1-8eec-bd2fb01a785c\",\"siteId\":\"motox\"}"}
hermes/dialogueManager/sessionEnded {"termination": {"reason": "nominal"}, "sessionId": "motox-manual-4df43557-f6ab-4ba1-8eec-bd2fb01a785c", "siteId": "motox", "customData": "manual"}
hermes/dialogueManager/sessionStarted {"sessionId": "224aecb0-9029-4272-8f06-a9084a16fe5b", "siteId": "motox", "customData": "{\"confidence\":1,\"customData\":\"manual\",\"input\":\"wie spät ist es 25\",\"intent\":\"GetTime\",\"lang\":null,\"rawInput\":\"wie spät ist es\",\"reopenVoiceInput\":\"25\",\"requestType\":\"voice\",\"sessionId\":\"motox-manual-4df43557-f6ab-4ba1-8eec-bd2fb01a785c\",\"siteId\":\"motox\"}", "lang": null}
hermes/nlu/query {"input": "ciao", "siteId": "motox", "id": null, "intentFilter": ["de.fhem:SetColor", "de.fhem:SetColorGroup", "de.fhem:SetTimedOnOffGroup", "de.fhem:GetState", "de.fhem:GetNumeric", "de.fhem:SetOnOffGroup", "de.fhem:GetDate", "de.fhem:SetOnOff", "de.fhem:SetTimedOnOff", "de.fhem:siteId2room", "de.fhem:MediaControls", "de.fhem:Shortcuts", "de.fhem:SetScene", "de.fhem:ReSpeak", "de.fhem:SetTimer", "de.fhem:GetOnOff", "de.fhem:SetNumericGroup", "de.fhem:GetTime", "de.fhem:SetNumeric", "de.fhem:CancelAction"], "sessionId": "224aecb0-9029-4272-8f06-a9084a16fe5b", "wakewordId": "", "lang": null, "customData": "{\"confidence\":1,\"customData\":\"manual\",\"input\":\"wie spät ist es 25\",\"intent\":\"GetTime\",\"lang\":null,\"rawInput\":\"wie spät ist es\",\"reopenVoiceInput\":\"25\",\"requestType\":\"voice\",\"sessionId\":\"motox-manual-4df43557-f6ab-4ba1-8eec-bd2fb01a785c\",\"siteId\":\"motox\"}", "asrConfidence": 0.99798579, "customEntities": null}
hermes/nlu/intentParsed {"input": "Cancel", "intent": {"intentName": "de.fhem:CancelAction", "confidenceScore": 1.0}, "siteId": "motox", "id": null, "slots": [{"entity": "Mode", "value": {"kind": "Unknown", "value": "Cancel"}, "slotName": "Mode", "rawValue": "ciao", "confidence": 1.0, "range": {"start": 0, "end": 6, "rawStart": 0, "rawEnd": 4}}, {"entity": "closeSession", "value": {"kind": "Unknown", "value": ""}, "slotName": "closeSession", "rawValue": "", "confidence": 1.0, "range": {"start": 7, "end": 6, "rawStart": 5, "rawEnd": 4}}], "sessionId": "224aecb0-9029-4272-8f06-a9084a16fe5b"}
Aktualisierte Fassung anbei, jetzt muss ich mich aber dringlich wieder anderen Dingen zuwenden :) .
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: MiLight@ESP-GW, BT@OpenMQTTGw | MySensors: seriell, v.a. 2.3.1@RS485 | ZWave | ZigBee@deCONZ | SIGNALduino | MapleCUN | RHASSPY
svn: u.a MySensors, Weekday-&RandomTimer, Twilight,  div. attrTemplate-files

gregorv

ZitatDas würde dem widersprechen, was wir bisher bei CustomIntents im Code hatten.
Genau so hatte ich das bisher als gewollt gesehen.
Zitat"null" bedeutet in dem Zusammenhang: Nimm den default aus configure
und das auch.
Ich bin auch ziemlich sicher, dass das schon immer so war - weiß ich aber nicht genau. Werde ich mal mit der Version von vor unserm Start testen.

"null" bedeutet also jetzt: Alle existierenden Intents werden aktiv ?

Für unseren Fall reopenVoiceInput ist configure_DialogManager() mit $toDisable = [qw(ConfirmAction Choice ChoiceRoom ChoiceDevice)] einfacher, um CancelAction zu aktivieren. Oder spricht etwas dagegen
Wenn wir das mit intentFilter machen, müssten wir erst mal alle aktiven Intents mit /nlu/query hole und dann CancelAction in das intentFilter Array pushen. Oder hast Du das an anderer Stelle schon so gemacht?