CustomIntent mit Dialog

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

Vorheriges Thema - Nächstes Thema

gregorv

@Beta-User,
danke für die Hinweise.
ZitatgrpMark=( die ...
Ich habe das inzwischen sogar gelöst! Immerhin gab mir das den Anstoß nochmal genauer bei Sentences nachzuforschen.
Nur:
... | alle | sämtliche ) $de.fhem.Group-SetOnOff{Group}im sentence einbauen und viola landet einer der Werte von de.fhem.Group-SetOnOff in Groups.

Dabei ist mir noch etwas anderes aufgefallen. In der 99_RHASSPY_Intents_Demo.pm wird ja mit:
if ( !eval { $data  = decode_json($rawd) ; 1 } ) {das JSON Format wieder in ein hash umgewandelt. Wenn man dann aber $data an eine sub wie handleIntentSetOnOffGroup() übergibt, knallt es bei den Umlauten - zumindest bei mir, obwohl die sonst keine Probleme machen. Um das zu lösen, muss man die o.Zeile in:
if (defined $rawd && !eval { $data  = decode_json(encode_utf8($rawd)) ; 1 } ) { umbauen.
Sollte man eventuell in der 99_RHASSPY_Intents_Demo.pm ändern.


Beta-User

#76
Zitat von: gregorv am 24 Oktober 2024, 13:19:49das zu lösen, muss man die o.Zeile in:
Code Auswählen Erweitern
if (defined $rawd && !eval { $data  = decode_json(encode_utf8($rawd)) ; 1 } ) { umbauen.
Kannst du bitte mal mit
JSON->new->decode($rawd)testen? Diese ganzen encoding-Anweisungen haben sich in der Vergangenheit immer als üble Sackgassen erwiesen.

EDIT: Siehe auch https://forum.fhem.de/index.php?topic=126088.0 (Unicode first aid).

Das mit "defined" sollte man ggf. direkt im Eingangsbereich lösen und dann eben auch direkt passende Antworten liefern? Im Zusammenhang:

sub DataTest {
        my $name = shift;
        my $rawd = shift // return RHASSPY::getResponse($hash, 'NoValidData');

        my $hash = $defs{$name} // return RHASSPY::getResponse($hash, 'NoDeviceFound');
        my $data;
        if ( !eval { $data  = JSON->new->decode($rawd) ; 1 } ) {
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

gregorv

ZitatDiese ganzen encoding-Anweisungen haben sich in der Vergangenheit immer als üble Sackgassen erwiesen
Kann ich nur bestätigen Perl hat allerdings da wohl besondere Feinheiten! und JA,
JSON->new->decode($rawd)es funktioniert  ???  - überlebt sogar shutdown restart. Bei Perl und encoding weiß man das nie so genau.
Ich hätte gewettet, dass JSON->new->decode() das gleiche ist, wie decode_json() - irgendwo hatte ich gesehen:
Zitat$perl_scalar = decode_json $json_text
or
$perl_scalar = JSON->new->utf8->decode($json_text)
ZitatDas mit "defined" sollte man ggf. direkt im Eingangsbereich lösen
Stimmt, sonst macht er mit nix weiter und es hagelt unpassende Fehlermeldungen.

Frage:
warum wurde da überhaupt JSON genommen?, ein hash kann doch auch Argument sein.

gregorv

Zitatmy $rawd = shift // return RHASSPY::getResponse($hash, 'NoValidData');
funktioniert (zumindest bei meiner 99_myUtils ) nur, wenn man $hash durch $defs{'RHASSPY.IF'} ersetzt (RHASSPY.IF = Bezeichnung meines RHASSPY Devices). $hash ist zu dem Zeitpunkt noch nicht da.
Bei den Demos ist das vermutlich auch so.

Beta-User

Zitat von: gregorv am 24 Oktober 2024, 17:21:07warum wurde da überhaupt JSON genommen?, ein hash kann doch auch Argument sein.
Na ja, wie du an vielen Stellen gemerkt hast, ist es "schillernd", wenn man es mit HASHes (oder nur Referenzen auf solche...?!?) zu tun hat. Z.B. hätte deine Rückreferenzierung über customData nach meinem Verständnis nicht funktionieren dürfen, weil über MQTT eben nur plain text übermittelt wird. Dass Perl anscheinend (!?!) da wieder eine Referenz draus ableitet, ist hochgradig irritierend und zumindest gefühlt komplett fehleranfällig...

Ergo war die Entscheidung, da JSON in die Richtung des Users weiterzugeben nur folgerichtig, denn da kann man "nur" die Konvertierung falsch machen mit der Handhabung der Daten. Mit Referenzen (oder eben nicht...) crasht man schnell das System (oder verändert die Ausgangsdaten, was uU. auch unsupportbare Probleme macht.

Genau das macht aber nun leider decode_json() => ergo kommt es bei nächster Gelegenheit aus der Demo raus, ist einfach ein Rest aus der Zeit vor der Umstellung in RHASSPY selbst (siehe auch meine letzten Kommentare im verlinkten Thread).

Dass sich die Katze in den Schwanz beißt, wenn man $hash braucht, hatte ich schlicht übersehen, in die Demo kommt daher folgerichtigerweise direkt Text; den kann dann jeder nach Belieben anpassen...
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

gregorv

Zitatmeinem Verständnis nicht funktionieren dürfen, weil über MQTT eben nur plain text übermittelt
Ja, das ist auch richtig, hashes dürften für MQTT ein Problem sein - in meinen ESP Projekten verwende ich auch nur JSON als payload.
Aber jetzt dämmert es mir langsam, weshalb Du schon öfter MQTT in diesem Thread erwähnt hast und ich mich immer nur gewundert hatte, weil da MQTT an keiner Stelle eine Rolle spielt.

Der Rhasspy Server spricht ja niemals direkt mit der Blinds().

Dafür gibt es ja die handleCustomIntent() und die bekommt ihre Daten letztlich aus der MQTT Nachricht, die im RHASSPY Modul ankommen und das veranlasst letztlich auch ein publish an den Rhasspy Server. In der handleCustomIntent() (und da ist schon alles im hash Format) wird die Blinds() aufgerufen und die kann daher natürlich auch hashes empfangen und zurück liefern, sie ist ja nur eine Unterfunktion von handleCustomIntent(). Alles danach führt über deren return und diverse Funktionsaufrufe innerhalb des RHASSPY Moduls wieder zu einer Nachricht (publish) mit JSON als paload an den Rhasspy Server.

Zumindest habe ich den Ablauf im Code so verstanden - oder übersehe ich da was? Ich halte das für eine ziemlich geniale Lösung um eigene Wünsche relisieren zu können.

Beta-User

Zitat von: gregorv am 24 Oktober 2024, 21:14:44Zumindest habe ich den Ablauf im Code so verstanden - oder übersehe ich da was?
Was den Ablauf beüglich Intent-Handling angeht, stimmt das soweit: Der Austausch zwischen RHASSPY/FHEM und Rhasspy (Dienst) erfolgt da via MQTT, deswegen ist das (primäre) Interface auch MQTT2_CLIENT (MQTT2_SERVER ist ausdrücklich nicht empfohlen, da Rhasspy intern auch MQTT verwendet - u.a. auch für den Austausch von Audiodaten...)

RHASSPY kommuniziert allerdings auch (wegen anderer Dinge) per HTTP-Post mit Rhasspy, z.B. um die slots zu generieren.

Zitat von: gregorv am 24 Oktober 2024, 21:14:44Ich halte das für eine ziemlich geniale Lösung um eigene Wünsche relisieren zu können.
Ob "genial" die passende Kategorie ist? Es ist jedenfalls eine sehr flexible Lösung, mit der sich FHEM und Sprachsteuerungsbefehle sehr eng verzahnen und an die eigenen Wünsche anpassen lassen.

Das mit den "Intents" verleitet allerdings - grade am Anfang - dazu, für jeden (vermeintlichen) Zweck einen eigenen Intent anzulegen. Das ist - jedenfalls nach meinem derzeitigen Meinungsstand - nicht optimal. Natürlich gibt es "Großkategorien" wie "OnOff", aber wenn man sich da die Entwicklung anschaut, war es irgendwann so, dass mich die Unterscheidung zwischen "Einzeldevice" und "Gruppe" eher behindert hat als das es (gefühlt) hilfreich war. Zwischenzeitlich bevorzuge ich es, anhand des (Nicht-) Vorhandenseins von bestimmten Keys zu unterscheiden, was eigentlich gewollt ist. Macht natürlich andererseits den Code komplexer...

Na ja, jedenfalls muss ich manchmal schmunzeln wenn ich sehe, welche Klimmzüge man machen muss, um anderen Sprachsteuerungen bestimmte Aktionen zu "entlocken" und denke bei mir, dass das mit RHASSPY bestimmt sehr viel einfacher ginge 8) .
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

gregorv

#82
ZitatDas mit den "Intents" verleitet allerdings - grade am Anfang...
Mhhh - ich sehe es eher als persönliche Vorliebe. Dazu zählen sicher auch meine vielen anderen subs in der 99_myUtils wo alle möglichen events gesammelt werden, um passende Aktionen zu veranlassen. Ich weiß, dass das auch mit DOIFs geht, aber eine DOIF Variante, die - um bei den Rolläden zu beiben - diese herunterfährt, wenn es dunkel wird, aber die für die Terrassentür nicht, wenn die offen ist, bei schwerem Sturm aber alle, selbst, wenn es hell ist... und das ganze auch noch abhängig von einstellbaren Leveln für Helligkeit, Zeit oder Windgeschwindigkeit ... Beim Hochfahren ist es noch viel komplexer und spätestens da habe ich die DOIF erst mal ignoriert und über all nur noitfy benutzt um eigene subs aufzurufen.
Sicher, man kann es auch übertreiben - aber es macht Spass.

Ich suche gerade noch die Ursache für ein Problem - wir hatten ja das Thema Codierung schon angesprochen damit scheint es wieder zu klemmen.
Das JSON->new->decode($rawd) hatte ich ja eingesetzt und das Problem ist auch unabhängig davon.
Getestet hatte ich mit der Gruppe "Rollläden", aber wenn ich diese Gruppe auf einem Raum beschränke funktioniert das nur, wenn der Raum keine Umlaute hat - Küche und Büro geht nicht.
Das Problem liegt in der getDevicesByGroup in der Zeile:
next if $room ne 'global' && $allrooms !~ m{\b$room(?:[\b:\s]|\Z)}i; ##no critic qwIch habe in die loop mal ein Log eingebaut und an dieser Stelle sollte die Bedingung zuschlagen:
------------------>allrooms=arbeitszimmer,büro room=büro Tut es aber nicht und läuf durch alle Devices -> Keine Devices gefunden und Ansage Fehlermeldung.

Falls Du dazu gerade eine zündende Idee hast ... - ansonsten knie ich mich da mal rein.

Hinweis:
Im $hash unter rhasspyRooms ist das Büro: "b\303\274ro" (Octet Schreibweise) in $data dagegen "b\x{c3}\x{bc}ro" (HEX Schreibweise) Beide Werte sind gleich.

Beta-User

Zitat von: gregorv am 25 Oktober 2024, 09:56:18Falls Du dazu gerade eine zündende Idee hast ... - ansonsten knie ich mich da mal rein.
Sieht komisch aus, aber im Moment habe ich dazu auch keine Idee und auch keine Zeit zu testen.

Zitat von: gregorv am 25 Oktober 2024, 09:56:18Mhhh - ich sehe es eher als persönliche Vorliebe. Dazu zählen sicher auch meine vielen anderen subs in der 99_myUtils [...] dass das auch mit DOIFs geht, aber
[...]
Sicher, man kann es auch übertreiben - aber es macht Spass.
Na ja, m.E. ist das was substantiell anderes, weil durch die Intents eben gerade eine Vor-Kategorisierung stattfindet, aus der man schwer wieder raus kommt. Gutes Beispiel ist das mit "sage die Zeit an" und "sage das Datum an". Warum sind das zwei Intents? Nur, weil jemand irgendwann mal gedacht hat, man bräuchte dafür getrennte Intents. Heute würde ich das anders lösen: Es ist die Frage nach "irgendeiner" Zeitangabe, und je nachdem, wie man fragt, erwartet man eine andere Antwort. Es ist aber programmtechnisch einfacher zu lösen, wenn man alle diese Varianten in eine Routine reinwirft und dann schaut, was der passende Antwortsatz ist, oder?

DOIF verwende ich bei mir gar nicht, ich verstehe das Modul nicht (und habe weiter den Eindruck, dass sehr viele (auch damit erfahrene) Nutzer ) Probleme haben, das Modul "richtig" zu verwenden... Ist aber nicht unser Thema!

Rollladenautomatisierung ist sowieso ein Spezialthema, das hier AutoShuttersControl erledigt. Da war ich bei der Entwicklung recht intensiv dabei, so dass das meine Bedarfe sehr gut abdeckt.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

gregorv

Bingo, schon gelöst
Ich habe die Zeile:
next if $room ne 'global' && $allrooms !~ m{\b$room(?:[\b:\s]|\Z)}i;durch
next if $room ne 'global' && $allrooms !~ m{(?<!\p{L})$room(?:(?!\p{L})|\Z)}i;Jetzt geht es. Sollte bei standard-SetOnOffGroup() nicht stören obwohl ich vermute, dass es da nie ein Problem mit Umlaut Codierung gab.
Der Grund ist wahrscheinlich, dass bei Einem CustomIntent die Daten in $data erst mal in von hash in JSON und anschließen wieder in hash convertiert werden.
ZitatDOIF verwende ich bei mir gar nicht, ich verstehe das Modul nicht
Volltreffer, geht mir genau so. :)
Ich könnte mich ja mit fremden Federn schmücken aber im Anhang  mal, woher ich das habe.
Du darfst diesen Dateianhang nicht ansehen.
Insgesamt bestimmt5 weitere Vorschläge - den zweiten fand ich passend.

gregorv

Zitatweil durch die Intents eben gerade eine Vor-Kategorisierung stattfindet
Das denke ich auch - ich will meine Blinds() ja auch nicht in das RHASSPY Modul einbauen. Und behalten will die nur so lange, bis die handleSetNumric() das auch kann (oder wie auch immer ein General-Intent heißen wird.

gregorv

@Beta-User
Frage: wo ist eigentlich die andere sub Parse()?

Im RHASSPY Modul ist zwar eine drin und da ist auch eine Fehlermeldung, die ich sehe, aber wenn ich da eine Log Ausgabe einfüge, sehe ich zwar die Fehlermeldung, aber nicht meine Logausgabe. Das passiert in folgendem Fall: Ich spreche das Wake Word und erzwinge dann ein IntentNotRecognized. -> Keine Audio Ausgabe und die Fehlermeldung:
2024.10.25 17:37:58 5: RHASSPY: [RHASSPY.IF] Parse: internal error:  onmessage returned an unexpected value: RHASSPY.IFDas Problem war schon in der ursprünglichen Version, die FHEM etwa im Sommer aktualisiert hatte und ich wollte mal schauen wodurch das zustande kommt.
mehr Details:
2024.10.25 17:37:58 5: RHASSPY: [RHASSPY.IF] Parse (IO: RHASSPY.MQTT2): Msg: hermes/nlu/intentNotRecognized => {"input": "stop terrassentür auf dem kochstudio zu", "siteId": "arbeitszimmer", "id": null, "customData": "Roberta_de_linux_v3_0_0", "sessionId": "arbeitszimmer-Roberta_de_linux_v3_0_0-e12a5432-aad5-4b07-9160-7176497e2ce6"}
2024.10.25 17:37:58 5: Parsed value: 0.75 for key: confidence
2024.10.25 17:37:58 5: Parsed value: arbeitszimmer for key: siteId
2024.10.25 17:37:58 5: Parsed value: stop terrassentür auf dem kochstudio zu for key: input
2024.10.25 17:37:58 5: Parsed value: arbeitszimmer-Roberta_de_linux_v3_0_0-e12a5432-aad5-4b07-9160-7176497e2ce6 for key: sessionId
2024.10.25 17:37:58 5: Parsed value: Roberta_de_linux_v3_0_0 for key: customData
2024.10.25 17:37:58 5: [RHASSPY.IF] handleIntentNotRecognized called, input is stop terrassentür auf dem kochstudio zu
2024.10.25 17:37:58 5: published hermes/dialogueManager/endSession {"customData": "Roberta_de_linux_v3_0_0","intentFilter": null,"sessionId": "arbeitszimmer-Roberta_de_linux_v3_0_0-e12a5432-aad5-4b07-9160-7176497e2ce6","siteId": "arbeitszimmer","text": "Das habe ich leider nicht verstanden"}
2024.10.25 17:37:58 5: RHASSPY: [RHASSPY.IF] Parse: internal error:  onmessage returned an unexpected value: RHASSPY.IF
2024.10.25 17:37:58 5: RHASSPY: [RHASSPY.IF] Parse (IO: RHASSPY.MQTT2): Msg: hermes/dialogueManager/sessionEnded => {"termination": {"reason": "intentNotRecognized"}, "sessionId": "arbeitszimmer-Roberta_de_linux_v3_0_0-
Die Ansage wird erkannt und auch mit 'gepublished' und auch die MQTT payload sieht hat genau die gleichen Elemente wie für Fälle in denen es funktioniert, z.B. "licht im büro an". Aber trotzdem kommt die Fehlermeldung internal error:  onmessage returned an unexpected value: RHASSPY.IF.

Das funktionierende Gegenstück:
2024.10.22 12:43:44 5: published hermes/dialogueManager/endSession {"customData": "Roberta_de_linux_v3_0_0","intentFilter": null,"sessionId": "arbeitszimmer-Roberta_de_linux_v3_0_0-fce5d7e4-3bc2-4176-852d-6a7d65f56848","siteId": "arbeitszimmer","text": "oke"}
2024.10.22 12:43:44 4: [RHASSPY.IF] dispatch result is RHASSPY.IF AR.Licht
2024.10.22 12:43:44 5: RHASSPY: [RHASSPY.IF] Parse (IO: RHASSPY.MQTT2): Msg: hermes/dialogueManager/endSession => {"customData": "Roberta_de_linux_v3_0_0","intentFilter": null,"sessionId": "arbeitszimmer-Roberta_de_linux_v3_0_0-fce5d7e4-3bc2-4176-852d-6a7d65f56848","siteId": "arbeitszimmer","text": "oke"}

Wenn Du mir sagen kannst, wo die Parse() ist, kann ich da mal weiter tracen


Danke, Gregor

Beta-User

#87
Zitat von: gregorv am 25 Oktober 2024, 18:29:10Frage: wo ist eigentlich die andere sub Parse()?
Welche "andere"? Es gibt nur die eine {ParseFn} = \&Parse.

Das "Problem" ist, dass die ein Array erwartet und eben (veraltet) meckert, wenn analyzeMQTTmessage was anderes zurückgibt wie erwartet, also kein Array. Beende deine handleIntentNotRecognized() mal mit:
return ($hash->{NAME});Vermutlich taucht das Problem noch an anderen Stellen auf, in der angehängten Version (sie lädt, viel mehr kann ich im Moment nicht testen) ist das schon geändert und das eine oder andere von deinem inupt (verändert...) eingeflossen.

Deine abgeänderte regex (Thx!) ist noch nicht eingepflegt, sie scheint aber zu funktionieren, von daher hätte ich keine Bedenken, das insgesamt umzustellen.
Wegen der Anpassung deines myUtils-Codes anbei auch ein diff, damit sollte es sich leichter feststellen lassen, was zu ändern wäre (es sind einige Codes geändert).

Falls gewünscht mache ich noch ein paar Kommentare dazu, aber das wird mir frühestens am Sonntag reichen.
Server: HP-elitedesk@Debian 12, aktuelles FHEM@ConfigDB | CUL_HM (VCCU) | MQTT2: ZigBee2mqtt, MiLight@ESP-GW, BT@OpenMQTTGw | ZWave | SIGNALduino | MapleCUN | RHASSPY
svn: u.a Weekday-&RandomTimer, Twilight,  div. attrTemplate-files, MySensors

gregorv

ZitatWelche "andere"? Es gibt nur die eine {ParseFn} = \&Parse.
Ops, war mein Fehler, namlich eine fehlerhafte Log3 Anweisung. Das erschien nicht im Log weshalb ich annahm, dass die Stelle nicht durchlaufen wird.
Vermutlich taucht das Problem noch an anderen Stellen aufja, war mir auch schon aufgefallen - auch bei einer Standard-Ansage. Deshalb habe ich nach einer besseren Stelle als in handleIntentNotRecognized() gesucht. Da wird ja der return von respond() als return übergeben und deshalb habe ich in der respond() am Ende die Zeile:
my $secondAudio = ReadingsVal($hash->{NAME}, "siteId2doubleSpeak_$data->{siteId}",undef) // return [$hash->{NAME}];geändert (return in []) -> Die Fehlermeldung ist jetzt weg, aber leider nicht das Problem, dass die Ansage nicht kommt. Muss also weitersuchen.
Nun sieht das Log so aus:
2024.10.26 11:15:27 5: [RHASSPY.IF] handleIntentNotRecognized called, input is
2024.10.26 11:15:27 5: published hermes/dialogueManager/endSession {"customData": "Roberta_de_linux_v3_0_0","intentFilter": null,"sessionId": "arbeitszimmer-Roberta_de_linux_v3_0_0-6e2b78ac-5f07-43f9-97ba-f67f727a3aaf","siteId": "arbeitszimmer","text": "Das habe ich leider nicht verstanden"}
2024.10.26 11:15:27 5: Parsed value: arbeitszimmer-Roberta_de_linux_v3_0_0-6e2b78ac-5f07-43f9-97ba-f67f727a3aaf for key: sessionId
Negative Auswirkungen auf respond() Aufrufe habe ich bisher nicht festgestellt.

Zitat...viel mehr kann ich im Moment nicht testen...
Ich werde die Version mal aktivieren - bei meinen Spielereinen werden mir eventuelle Problem auffallen. Was die Kommentare angeht, habe ich in meiner Version schon überall Links auf die Posts hier eingebaut, sonst verliere ich selbst den Überblick. Wenn du das als Kommentare haben möchtest, braucht Du das nicht machen.

gregorv

ZitatProblem, dass die Ansage nicht kommt. Muss also weitersuchen.
Gelöst! Ist ein Rhasspy Problem.
Wenn man in der Rhasspy Konfiguration bei Error WAV keinen Eintrag hat, wird nicht nur keine WAV abgespielt, sondern eine Ansage komplett unterdrückt.
Lösung: Im Verzeichnis responses eine leere WAV Datei z.B. Nix.wav erstellen und in Rhasspy
Error WAV    ${RHASSPY_PROFILE_DIR}/responses/Nix.waveinfügen.
Wenn man will kann man da auch eine WAV mit Ping angeben, dann hört man Ping UND die FHEM Ansage von Id 'NoIntentRecognized'

Ich bin bestimmt nicht der erste, der die Ansage NoIntentRecognized vermisst hat.