La chose la plus importante à comprendre dans rhasspy, ce sont les sentences et les intents. C’est dans la partie “Sentences” de rhasppy que nous allons configurer les phrases que devra reconnaître notre assistant, mais aussi ce qu’on appelle les intents.
Petite définition rapide d’une intent
Alors, une intent, c’est le diminutif d’intention.
En, fait après le speech to text, c’est à dire une fois que notre phrase a été transcrite sous forme de texte, il nous faut un outil qui comprenne le ou les intentions de l’utilisateur, et une fois l’intention de l’utilisateur comprise, qui mette cette intention dans un format compréhensible par tous mes outils.
Par exemple, lorsque je pose la question “Quelle heure est-il ?”, on peut dire que mon intention c’est de récupérer l’heure. Hé bien je vais créer dans mon outil de détection d’intent, une intent qui va s’appeler “recupHeure
“
Mais si je poste la question “Peux tu me donner l’heure ?”, l’intention est la même. Comment gérer cela ? Hé bien on va regrouper toutes les phrases possibles pour une intent dans notre outil de détection d’intent.
L’outil de détection d’intent
Il y’a 2 outils de détection d’intent dans rhasspy : Fsticuffs
et Fuzzywuzzy
. Je te laisse aller lire cet article pour connaitre la différence entre les 2.
Dans le but d’expliquer les différentes possibilités de syntaxe des sentences, j’ai choisi de prendre Fsticuffs
. En effet, celui-ci nécessite de lister toutes les phrases possibles même si il y en a des centaines de milliers.
L’outil de gestion des intents
Je n’ai pas choisi d’outil de gestion des intents dans ce TP. En effet, la gestion des intents n’étant pas du ressort de rhasspy, je n’ai pas inclus cette partie.
Néanmoins, toutes les portes sont ouvertes. Par défaut tu as home assistant, mais tu peux aussi avoir Jeedom grâce au plugin de KiboOst. De mon côté c’est Node-Red avec connecteur MQTT.
Et si tu as un réseau de snips existants, alors tu pourras basculer tranquillement de l’un à l’autre grâce à la compatibilité avec le protocole Hermes-MQTT.
Les sentences
Les sentences et les intents sont stockées dans le fichier sentences.ini
. On peut configurer ce fichier en allant sur l’onglet dédié aux sentences
Il y a déjà des intents pré-configurées. Mais regardons dans un premier temps les 3 premières lignes
[GetTime]
quelle heure est-il
il est quelle heure
On voit qu’on demande à notre outil de détection d’intent de détecter l’intention GetTime (récupérer heure) lorsqu’il croise les phrases listées.
Le format des intents
On en déduit donc que le format est
[nom_intent]
phrase 1
phrase 2
phrase 3
....
Le nom de notre intent (sans espace, ni accent, ni caractère spécial) est mis entre crochet [] . Ensuite, on y met la liste complète des phrases possibles .
Ok, maintenant que l’on sait comment créer une intent, voyons ce que ça donne avec une intent qui s’appelle “AllumerLumiere
“
Il me faudrait des phrases comme :
[AllumerLumiere]
allume la lumière
Met de la lumière
Allume la lumière du salon
Met de la lumière dans le salon
Allume la lumière de la cuisine
Met de la lumière dans la cuisine
Bon, on voit vite les limites. il va falloir écrire des centaines de phrases possibles. Comment peut-on optimiser ça ?
Les parties optionnelles
Le premier truc qui serait pratique serait du texte optionnel. Dans notre liste de phrase ci-dessus, il serait intéressant de mettre la pièce comme optionnelle. C’est à dire que l’on est pas obligé de donner une pièce pour allumer la lumière. Si l’utilisateur ne donne pas de pièce, alors ce n’est pas grave, notre détecteur d’intent utilisera le nom d’une pièce par défaut.
ça donnerait :
[AllumerLumiere]
Allume la lumière [du salon]
Met de la lumière [dans le salon]
Allume la lumière [de la cuisine]
Met de la lumière [dans la cuisine]
Comme tu es malin, tu auras bien compris qu’on ne peut pas mettre quelque chose d’optionnel au début car sinon, il va considérer ça comme le nom d’une nouvelle intent. Du coup, pour quand même mettre quelque chose d’optionnel en début de phrase, on va “échapper” notre crochet ouvrant avec \ . Par exemple : \[s'il te plait] allume la lumière
Les alternatives
Dans notre nouvelle liste des phrases optimisées ci dessus, on voit que le prefix de la pièce n’a que peu d’intérêt dans l’intention. Il a plusieurs valeurs possibles.
dans le
dans la
du
de la
des
de
dans l
on va mettre toutes les alternatives possibles entre parenthèse () et on va séparer chaque alternative par le caractère | (ALT-GR+6
pour un clavier français)
ce qui nous donnerait maintenant ces nouvelles phrases
[AllumerLumiere]
Allume la lumière [(dans le | dans la | du | de la | des de | dans l) salon]
Allume la lumière [(dans le | dans la | du | de la | des de | dans l) cuisine]
Met de la lumière [(dans le | dans la | du | de la | des de | dans l) salon]
Me de la lumière [(dans le | dans la | du | de la | des de | dans l) cuisine]
Du coup, on peut faire la même chose avec “Allume la” et “Met de la”.
[AllumerLumiere]
(Allume la | Mets de la) lumière [(dans le | dans la | du | de la | des de | dans l) cuisine]
(Allume la | Mets de la) lumière [(dans le | dans la | du | de la | des de | dans l) salon]
Il nous reste encore une dernière chose à améliorer. C’est la gestion de pièces.
Les listes de slots
Dans notre nouvelle liste des phrases optimisées ci dessus, on voit que la liste des pièces sera toujours la même quelle que soit l’intent que l’on souhaite détecter. Par exemple :
- Donne moi dans la température dans le bureau.
- Allume la lumière dans le bureau
On voit bien que dans les 2 cas, la liste des pièces possibles au lieu de bureau est la même quelle que soit l’intent.
Ce serait donc plus pratique si on pouvait créer nos listes qui reviennent régulièrement. Hé bien on peut le faire grâce aux listes de slots. Pour créer ton premier slot piece
, c’est dans cet article.
Vu qu’on a créé notre liste de slots piece
, nous allons mettre à jour nos nouvelles phrases et ça donne
[AllumerLumiere]
(Allume la | Mets de la) lumière [(dans le | dans la | du | de la | des de | dans l) ($piece)]
Et voilà, nous avons réussi à écrire une phrase qui en générera des centaines pour notre outil de détection d’intent.
Nom d’un slot dans l’intent (tag)
Généralement, dans l’intention de l’utilisateur, il y a souvent des informations qui doivent être récupérées car utiles pour répondre au mieux à ce qui est demandé.
En fait, il y a un autre outil qui rentre en jeux c’est l’outil qui va traiter l’intent une fois qu’elle a été découverte. C’est lui qui va pour chaque intent, avoir besoin d’un certain nombre d’information. Par exemple, pour l’intent AllumerLumiere
, il peut avoir besoin du nom de la pièce, du pourcentage à laquelle la lumière doit s’allumer ou bien même de la couleur. Toutes ces infos là, si elles sont données par l’utilisateur, il faut les identifier et les tagger.
Typiquement, le nom de la pièce est une information utile. Elle doit donc être taggée comme tel dans notre intent. Et pour ça, on va créer ce qu’on appelle un slot et lui donner un nom, c’est à dire le tagger.
pour ça, on va mettre entre accolade le nom de slot (de son tag), et ce juste à côté de ce qu’on souhaite taggé
[AllumerLumiere]
(Allume la | Mets de la) lumière [(dans le | dans la | du | de la | des de | dans l) ($piece){house_room}]
Ce qui est intéressant, c’est cette partie du code
($piece){house_room}
Là, on dit que si une pièce qui est listée dans notre liste de slots rhasspy est présente, alors on veut qu’elle soit taggée avec house_room
comme nom de tag.
Du coup, dans mon outil de gestion des intents, si je vois l’intent AllumerLumiere
et un paramètre du nom de house_room
, je sais que c’est en fait la pièce à traiter.
La substitution
Dans certain cas, on peut être amené à remplacer un mot par un autre. Typiquement, quand on veut utiliser des synonymes. “Bureau
“, “Bureau de ced
” et “Bureau de Cédric
” sont le même lieu. Ce lieu, dans mon outil de gestion des intents, il le connait sous le nom de “bureau
“.
Donc, dans ma liste de slot piece
, je vais pouvoir remplacer les lignes
bureau
bureau de ced
bureau de cédric
par la ligne
(bureau | bureau de ced | bureau de cédric):bureau
A chaque fois qu’il verra soit “bureau
“, soit “bureau de ced
” ou soit “bureau de cédric
“, il remplacera par “bureau
“.
C’est un exemple d’utilisation. Il y en a d’autres ! 🙂
Tester une intent
pour cela, rien de plus simple, on retourne sur la page d’accueil, on entre une phrase et on clique sur le bouton bleu pour vérifier si notre intent est bien reconnue (avec tous ses slots)
Exemple de sentence et d’intents
Alors, qu’on soit bien d’accord, je te donne des idées que tu devras adapter à tes intents. Copier-coller sans savoir ce qu’attend ton outil de gestion d’intent est inutile. Et surtout ces exemples sont pour fsticuffs. Si tu essayes avec Fuzzywuzzy, l’entrainement sera trop long et partira en timeOut.
Ils ne sont pas spécialement optimisés,
Intent pour les lumières
exemple d’intent pour allumer et éteindre les lumières avec l’intensité et les couleurs en optionnelles
[AllumerLumiere]
(allumer | allume | met) (la | le | l) (lumière | ampoule | spot) [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}] [(à) (1..100){intensity_pourcent} [pourcent]] [(en| de la couleur) ($color){lights_color}]
(allumer | allume | met) (la | le | l) (lumière | ampoule | spot) (du | de | de la | des | dans l| dans la | dans le)($piece){house_room} (en| de la couleur) ($color){lights_color} (à) (1..100){intensity_pourcent} (pourcent | pourcents)
[EteindreLumiere]
(éteins | ferme | éteint) (la | le | l) (lumière | ampoule | spot) [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}]
Intent pour la température
Voici une intent pour récupérer la température d’une pièce.
[GetTemperature]
quelle est la température [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}]
combien fait il [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}]
Peux tu me dire combien il fait [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}]
Peux tu me dire la température [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}]
Intent pour les volets
Et dernier exemple, un intent pour ouvrir et fermer les volets
[OuvrirVolet]
(Ouvre | ouvrir | monte) ((le | les) (volet | volets){windows_devices}) [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}] [(à) (1..100){intensity_pourcent} [pourcent]] [($quantity_state){window_state}]
[FermerVolet]
(Ferme | fermer | descend) ((le | les) (volet | volets){windows_devices}) [(du | de | de la | des | dans l| dans la | dans le)($piece){house_room}] [(à) (1..100){intensity_pourcent} [pourcent]] [($quantity_state){window_state}]
Poster un Commentaire