Apprenez à créer votre propre chatbot vocal avec Recast.ai et Voice Kit de Google
Cet article va vous présenter plusieurs concepts de l’intelligence artificielle au travers d’exemples pour créer votre propre chatbot maison. Nous allons aborder les concepts de NLP (Natural Language Processing), de Machine Learning et nous allons voir comment élaborer un assistant vocal étape par étape.
Prenons l’hypothèse que vous ayez l’envie d’avoir un concierge à domicile, pour vos locataires si vous êtes amené à louer votre appartement. Vous souhaitez par exemple pouvoir leur conseiller quelques bons restaurants dans le quartier.
Le résultat final donne ceci :
Pré requis
Pour réaliser cet assistant au niveau matériel nous aurons besoin :
• 1 x Voice Kit de Google
• 1 x RPI 3
Au niveau logiciel, nous utiliserons :
• Pour traduire les commandes vocales en texte : l’API cloud speech de Google (https://console.cloud.google.com)
• Pour gérer les conversations : Recast.ai
• Pour orchestrer les échanges entre les deux : NODE-RED qui sera installé sur le RPI
Installation
Nous n’allons pas rentrer en détail sur l’installation du Voice kit, elle est très bien documentée sur le site de Google : (https://aiyprojects.withgoogle.com/voice). Quand vous aurez terminé l’installation de votre kit et de votre RPI, vous pourrez lancer quelques scripts de tests afin de vérifier le bon fonctionnement de votre assistant. Pour NODE-RED vous trouverez la procédure d’installation sur le site : https://nodered.org/docs/hardware/raspberrypi.html
Nous allons à présent rentrer dans le vif du sujet : créer un assistant vocal !
Schémas d’ensemble
Ce schéma vous présente l’interaction entre les différentes briques que nous allons utiliser :
![]()
Les commandes vocales vont être réceptionnées par le Voice kit qui enverra le son à l’API Cloudspeech de Google pour le convertir en texte. Cette API nous sert donc de moteur NLU (Natural Language Understanding), la commande convertie en texte sera ensuite envoyée au moteur NLP de Recast.ai pour l’analyser. La plateforme Recast.ai permet de créer des « chatbot » avec des fonctionnalités que nous allons utiliser :
• Reconnaître l’intention de la commande et les mots clés (on parle d’entité).
• Entrainer votre chatbot pour améliorer sa compréhension des commandes
• Gérer les conversations avec la notion de « skill » (compétence, savoir faire)
Pour orchestrer tous ces échanges, nous utiliserons Node-RED présenté dans un précédent article.
Dans le schéma, j’ai ajouté la possibilité à l’orchestrateur d’envoyer des commandes au système domotique ou aux objets connectés de la maison, même si dans l’article actuel nous ne montrons pas ce cas d’usage, c’est juste pour schématiser une vue globale des possibilités.
Cas d’usages
Nous allons prendre des cas d’usages et les implémenter de plusieurs façons. La première approche permet de mettre au point un assistant capable de répondre à des questions simples. Exemple : Quelle est la météo ? Quel est ton nom ?
Nous enrichirons cet exemple en allant un cran plus loin afin d’être plus nuancé dans le traitement de la réponse. Pour finir nous mettrons en place une conversation afin de répondre à des questions plus complexes. Exemple : Quel restaurant conseiller pour aller manger dans le quartier ?
Quelques lignes de code
Le clignotement de la LED indique que la box est en écoute.
Quand la LED devient fixe, c’est que la réponse va être fournie.
Quand la LED s’éteint, c’est que la box n’est plus active.
Pour écouter et transmettre à l’API cloudspeech de Google nous utilisons un service python, il a été adapté à partir des exemples fournis dans le kit. Ce sont les seules lignes de code que vous aurez besoin de manipuler..
Le script est placé dans /home/pi/AIY-projects-python/src/script/my_assistant.py
Le code source correspond à ceci :
import aiy.audio
import aiy.cloudspeech
import aiy.voicehat
import requests
import subprocess
recast_url = "http://127.0.0.1:1880/callRecast?param="
def callEngineAI(message):
r = requests.get(recast_url+message)
led = aiy.voicehat.get_led()
led.set_state(aiy.voicehat.LED.OFF)
# aiy.audio.say('some words', lang='en-GB')
aiy.audio.say(r.text)
def main():
aiy.i18n.set_language_code('fr-FR')
recognizer = aiy.cloudspeech.get_recognizer()
button = aiy.voicehat.get_button()
led = aiy.voicehat.get_led()
aiy.audio.get_recorder().start()
while True:
print('Appuyer sur le bouton et parler...')
button.wait_for_press()
led.set_state(aiy.voicehat.LED.BLINK)
print('En écoute...')
text = recognizer.recognize()
led.set_state(aiy.voicehat.LED.ON)
if not text:
print('Désolé, Je ne t\'ai pas entendu.')
else:
#print('Tu as dit "', text, '"')
#callEngineAI(text)
if 'répète après moi' in text:
print('Répète après moi:"', text, '"')
to_repeat = text.replace('répète après moi', '', 1)
aiy.audio.say(to_repeat)
led.set_state(aiy.voicehat.LED.OFF)
elif 'au revoir' in text:
print('Au revoir')
led.set_state(aiy.voicehat.LED.OFF)
aiy.audio.say("Ok, je vais m'éteindre")
subprocess.call(["sudo","shutdown","-h","now"])
break
else:
print('Call callEngineAI: "', text, '"')
callEngineAI(text)
if __name__ == '__main__':
main()
Afin de lancer ce script automatiquement au démarrage de votre assistant, vous pouvez l’inscrire en tant que service :
cd /lib/systemd/system
sudo nano /lib/systemd/system/my_assistant.service
[Unit]
Description=My assistant app
[Service]
ExecStart=/bin/bash -c 'python3 -u src/my_assistant.py'
WorkingDirectory=/home/pi/AIY-projects-python
Restart=always
User=pi
[Install]
WantedBy=multi-user.target
sudo systemctl enable my_assistant.service
1ère étape : répondre à des questions simples
Voici une démonstration de cette première réalisation :
Pour apprendre à utiliser Recast.ai , j’ai utilisé un « noeud » mis à disposition par Viseo. En y ajoutant le token d’authentification de votre chatbot, vous pouvez appeler les API de Recast sans avoir à écrire une seule ligne de code ! (Merci à JP.Encausse créateur de S.a.r.a.h et ses collègues pour ce partage).
Si on veut aller un peu plus loin, il serait utile de pouvoir nuancer la commande en identifiant les mots-clés (« entités »). C’est l’objet de notre deuxième implémentation.
2ème étape : repérer les entités de la commande vocale
Dans ce deuxième exemple nous aurons besoin d’utiliser les API de Recast.ai
Ces API sont documentées ici : https://recast.ai/docs/api-reference/
Voici une démonstration de cette deuxième réalisation :
Pour obtenir en retour plus d’informations sur la commande, nous appelons l’API request. Elle permet en retour de lire les entités et les intentions qui ont été comprises par le chatbot. Pour appeler cette API j’ai créé un sous-noeud pour en simplifier son utilisation par la suite.
Si on veut gérer des cas plus complexes, il faut mettre en place ce qu’on appelle des conversations. C’est l’objet de notre prochaine étape.
3ème étape : gérer une conversation
Dans cette troisième approche, j’ai implémenté plusieurs cas de figures :
• Le premier montre comment répondre aux questions simples au sein d’une conversation.
• Le second gère la météo en gérant deux cas. Selon la demande le chatbot indique la météo du jour ou s’il va pleuvoir dans l’heure.
• Le troisième exemple concerne le cas du restaurant. Nous allons imaginer qu’un locataire souhaite connaître les bons restaurants du quartier. Pour pouvoir répondre le chatbot doit savoir le style de cuisine désiré. Pour envoyer l’adresse, l’assistant doit connaitre le téléphone portable pour pouvoir lui envoyer par SMS.
• Si le chatbot est perdu, la réponse par défaut sera « Et là c’est le bug ! ».
Voici une démonstration de cette troisième réalisation :
Les principes utilisés sont les suivants :
• Une conversation a un token, celui-ci doit être transmis dans chaque requête pour permettre au chatbot de savoir qu’elles sont liées à la même conversation. J’ai regroupé les commandes dans un sous noeud appelé « init dialog ».
• Pour envoyer un message au chatbot, nous faisons appel à l’API « converse ». J’ai créé un sous-noeud appelé « dialog » pour regrouper les commandes.
![]()
Pour créer un token, j’ai utilisé un script python qui s’appuie sur le sdk recastai. et s’installe avec les commandes suivantes :
pip install recastai
nano src/conversation.pi
Le source du script conversation.py qui permet de créer un nouveau token est le suivant :
import sys
import recastai
def main():
payload = sys.argv[1]
my_conversation_token = None
client = recastai.Client('71c52df587ba816e4fea6be69787d15b')
request = client.request
response = request.converse_text(payload)
my_conversation_token = response.conversation_token
print(my_conversation_token)
if __name__ == '__main__':
main()
Si vous souhaitez mettre en place ces exemples dans NODE-RED, vous pouvez faire un copier-coller :
Source NODE-RED première implémentation :
[{"id":"97344880.ddfc1","type":"subflow","name":"day weather","info":"","in":[{"x":156,"y":138,"wires":[{"id":"fe3e4c98.00d3d"}]}],"out":[{"x":1134,"y":118,"wires":[{"id":"16a06c4f.3308e4","port":0},{"id":"b6376939.0bf5","port":0}]}]},{"id":"fe3e4c98.00d3d","type":"template","z":"97344880.ddfc1","name":"Prepare command","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"wget http://www.prevision-meteo.ch/services/json/PARIS -q -O -","output":"str","x":346,"y":136,"wires":[["dd7acf78.82fb58"]]},{"id":"dd7acf78.82fb58","type":"exec","z":"97344880.ddfc1","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Exec curl","x":518,"y":135,"wires":[["135bf690.b70a01"],[],[]]},{"id":"135bf690.b70a01","type":"switch","z":"97344880.ddfc1","name":"Check result","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"Please specify a valid city or a coordinate","vt":"str"},{"t":"else"}],"checkall":"true","outputs":2,"x":677,"y":102,"wires":[["16a06c4f.3308e4"],["721ea662.710f28"]]},{"id":"721ea662.710f28","type":"json","z":"97344880.ddfc1","name":"conversion","pretty":false,"x":844,"y":130,"wires":[["b6376939.0bf5"]]},{"id":"16a06c4f.3308e4","type":"function","z":"97344880.ddfc1","name":"KO","func":"msg.payload = \"Service météo inaccessible\";\nreturn msg","outputs":1,"noerr":0,"x":990.3333740234375,"y":95.00003051757812,"wires":[[]]},{"id":"b6376939.0bf5","type":"function","z":"97344880.ddfc1","name":"OK","func":"today=msg.payload.fcst_day_0.day_long + \", il fait \" + msg.payload.current_condition.tmp + \" degrés et les conditions sont : \" + msg.payload.current_condition.condition + \".\\n\";\ntomorrow=msg.payload.fcst_day_1.day_long + \", la température sera entre \" + msg.payload.fcst_day_1.tmin + \" degrés et \" + msg.payload.fcst_day_1.tmax + \" degrés.\\nLes conditions seront : \" + msg.payload.fcst_day_1.condition + \".\";\n\nmsg.payload = today;\n\nreturn msg","outputs":1,"noerr":0,"x":990.3333740234375,"y":130.00003051757812,"wires":[[]]},{"id":"544cbc07.0db904","type":"comment","z":"97344880.ddfc1","name":"Météo du jour","info":"","x":324.75,"y":55.85711669921875,"wires":[]},{"id":"db8cd9e8.9a5ef","type":"node-recast","z":"5adfa13c.5a4a","name":"call Recast.ai","key":"822f3405.cd8ab","input":"payload","inputType":"msg","output":"payload","outputType":"msg","x":487.3096466064453,"y":259.9642219543457,"wires":[["98604966.04d05","61ffa459.e48034"]]},{"id":"98604966.04d05","type":"debug","z":"5adfa13c.5a4a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":641.3096160888672,"y":230.57136917114258,"wires":[]},{"id":"99ffcff1.f8214","type":"http in","z":"5adfa13c.5a4a","name":"/ call my bot","url":"callRecast","method":"get","upload":false,"swaggerDoc":"","x":149.52394104003906,"y":123.78567504882812,"wires":[["1f625662.6c2252"]]},{"id":"b291eba5.38d0a","type":"http response","z":"5adfa13c.5a4a","name":"","statusCode":"200","headers":{},"x":1333.9412078857422,"y":341.46423721313477,"wires":[]},{"id":"1f625662.6c2252","type":"change","z":"5adfa13c.5a4a","name":"get param","rules":[{"t":"move","p":"payload.param","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":347.52394104003906,"y":123.28567123413086,"wires":[["575f075f.2ce268","db8cd9e8.9a5ef"]]},{"id":"575f075f.2ce268","type":"debug","z":"5adfa13c.5a4a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":510.5952606201172,"y":123.10709762573242,"wires":[]},{"id":"6659e401.7840ec","type":"change","z":"5adfa13c.5a4a","name":"otherwize get description","rules":[{"t":"move","p":"payload.description","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":964.0598602294922,"y":458.67868423461914,"wires":[["93b0c61e.f70af8"]]},{"id":"b2d219e6.d316","type":"function","z":"5adfa13c.5a4a","name":"Et là c'est le bug !","func":"msg.payload = \"Et là c'est le beug\"\nreturn msg;","outputs":1,"noerr":0,"x":940.4526824951172,"y":283.0357093811035,"wires":[["93b0c61e.f70af8"]]},{"id":"4e348102.425328","type":"switch","z":"5adfa13c.5a4a","name":"check confidence","property":"payload.confidence","propertyType":"msg","rules":[{"t":"lte","v":"0.4","vt":"str"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":673.5596771240234,"y":359.0832862854004,"wires":[["9e996157.67fa6"],["d27afea7.1c06c"]]},{"id":"9e996157.67fa6","type":"function","z":"5adfa13c.5a4a","name":"Je n'ai pas compris","func":"msg.payload = \"Je ne suis pas sûr d'avoir compris ta question\"\nreturn msg;","outputs":1,"noerr":0,"x":940.8215789794922,"y":352.0118751525879,"wires":[["93b0c61e.f70af8"]]},{"id":"d27afea7.1c06c","type":"switch","z":"5adfa13c.5a4a","name":"check intent","property":"payload.slug","propertyType":"msg","rules":[{"t":"regex","v":"ask-weather","vt":"str","case":true},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":726.2028656005859,"y":432.0832862854004,"wires":[["a61dffef.440828"],["6659e401.7840ec"]]},{"id":"f69495d6.716f7","type":"debug","z":"5adfa13c.5a4a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1346.4227752685547,"y":392.148868560791,"wires":[]},{"id":"61ffa459.e48034","type":"switch","z":"5adfa13c.5a4a","name":"check if null","property":"payload","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"false","repair":false,"outputs":2,"x":659.6668548583984,"y":291.642765045166,"wires":[["b2d219e6.d316"],["4e348102.425328"]]},{"id":"dcd663a2.580938","type":"inject","z":"5adfa13c.5a4a","name":"","topic":"test","payload":"dis moi une blague","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":233.1668243408203,"y":217.14284896850586,"wires":[["db8cd9e8.9a5ef"]]},{"id":"f2883da4.5cdd58","type":"inject","z":"5adfa13c.5a4a","name":"test:quel temps fait il ?","topic":"test","payload":"quel temps fait-il ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":235.16685485839844,"y":261.28561782836914,"wires":[["db8cd9e8.9a5ef"]]},{"id":"a61dffef.440828","type":"subflow:97344880.ddfc1","z":"5adfa13c.5a4a","name":"","x":920.0480194091797,"y":393.4642677307129,"wires":[["93b0c61e.f70af8"]]},{"id":"acfd0afc.eafb2","type":"inject","z":"5adfa13c.5a4a","name":"test:quel est ton nom ?","topic":"test","payload":"quel est ton nom ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":235.88111877441406,"y":307.5713539123535,"wires":[["db8cd9e8.9a5ef"]]},{"id":"93b0c61e.f70af8","type":"function","z":"5adfa13c.5a4a","name":"log","func":"\nreturn msg;","outputs":1,"noerr":0,"x":1169.4529266357422,"y":370.42847061157227,"wires":[["f69495d6.716f7","b291eba5.38d0a"]]},{"id":"dc92155.2f8d7e8","type":"comment","z":"5adfa13c.5a4a","name":"get intent","info":"","x":478.73817443847656,"y":223.28570938110352,"wires":[]},{"id":"7e8cb418.806334","type":"comment","z":"5adfa13c.5a4a","name":"dialog with my bot Johnny !","info":"","x":199.1666717529297,"y":79.16667175292969,"wires":[]},{"id":"822f3405.cd8ab","type":"node-recast-config","z":"","name":"token","lang":""}]
Source NODE-RED seconde implémentation :
[{"id":"5c6424b7.ffeabc","type":"subflow","name":"request","info":"","in":[{"x":156,"y":106,"wires":[{"id":"ad830797.c1ee6"}]}],"out":[{"x":867,"y":102,"wires":[{"id":"79abf718.067db8","port":0}]}]},{"id":"512ec158.6c8cd8","type":"exec","z":"5c6424b7.ffeabc","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"call recast.api/request","x":547,"y":102,"wires":[["79abf718.067db8"],[],[]]},{"id":"ad830797.c1ee6","type":"template","z":"5c6424b7.ffeabc","name":"Prepare command","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"curl -H \"Authorization: Token 71c52df587ba816e4fea6be69787d15b\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"text\":\"{{payload}}\", \"language\":\"fr\"}' \\\n -X POST \"https://api.recast.ai/v2/request\"","output":"str","x":332.44036865234375,"y":104.27386474609375,"wires":[["512ec158.6c8cd8"]]},{"id":"79abf718.067db8","type":"json","z":"5c6424b7.ffeabc","name":"","property":"payload","action":"","pretty":false,"x":725.625,"y":101.8779296875,"wires":[[]]},{"id":"e7b9366.e55ac48","type":"debug","z":"1dee03c5.f49574","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":670.1485595703125,"y":194.51493072509766,"wires":[]},{"id":"6389c72b.3f94d8","type":"comment","z":"1dee03c5.f49574","name":"get intent & entities","info":"","x":165,"y":82,"wires":[]},{"id":"618e612f.b18bd8","type":"subflow:5c6424b7.ffeabc","z":"1dee03c5.f49574","name":"","x":506.0178527832031,"y":193.9077606201172,"wires":[["e7b9366.e55ac48"]]},{"id":"684acba0.867924","type":"inject","z":"1dee03c5.f49574","name":"","topic":"test","payload":"dis moi une blague","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":258.2321472167969,"y":142.2143096923828,"wires":[["618e612f.b18bd8"]]},{"id":"a08752e6.577ce8","type":"inject","z":"1dee03c5.f49574","name":"test:quel temps fait il ?","topic":"test","payload":"quel temps fait-il ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":260.232177734375,"y":186.3570785522461,"wires":[["618e612f.b18bd8"]]},{"id":"6a2cd174.35f0a8","type":"inject","z":"1dee03c5.f49574","name":"test:quel est ton nom ?","topic":"test","payload":"quel est ton nom ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":260.9464416503906,"y":232.64281463623047,"wires":[["618e612f.b18bd8"]]}]
Source NODE-RED troisième implémentation :
[{"id":"fbd6dad5.34a1b","type":"subflow","name":"current weather","info":"","in":[{"x":136,"y":134,"wires":[{"id":"7ff8d11c.fe0e98"}]}],"out":[{"x":1164,"y":144,"wires":[{"id":"24208a46.890f1e","port":0},{"id":"667258aa.b59b28","port":0}]}]},{"id":"239fd328.e8428c","type":"comment","z":"fbd6dad5.34a1b","name":"Va-t-il pleuvoir dans l'heure ?","info":"","x":400,"y":56,"wires":[]},{"id":"b3d35dee.2f8d4","type":"exec","z":"fbd6dad5.34a1b","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Exec curl","x":531,"y":134,"wires":[["777ea494.f7a22c"],[],[]]},{"id":"24208a46.890f1e","type":"function","z":"fbd6dad5.34a1b","name":"OK","func":"if(msg.payload.isAvailable===true) {\n arrayLength = msg.payload.niveauPluieText.length;\n retour = \"\";\n for(var i=0;i<arrayLength;i++)\n retour = retour + msg.payload.niveauPluieText[i] + \"\\n\";\n msg.payload = retour;\n}else{\n msg.payload = \"Pas de météo sur cette localité\";\n}\nreturn msg","outputs":1,"noerr":0,"x":1007.3333740234375,"y":117.25,"wires":[[]]},{"id":"786e5520.e21dec","type":"json","z":"fbd6dad5.34a1b","name":"conversion","pretty":false,"x":862,"y":117.24996948242188,"wires":[["24208a46.890f1e"]]},{"id":"7ff8d11c.fe0e98","type":"template","z":"fbd6dad5.34a1b","name":"Prepare command","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"curl -s \"http://www.meteofrance.com/mf3-rpc-portlet/rest/pluie/751170\"","output":"str","x":357,"y":134,"wires":[["b3d35dee.2f8d4"]]},{"id":"777ea494.f7a22c","type":"switch","z":"fbd6dad5.34a1b","name":"Check result","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"niveauPluieText","vt":"str"},{"t":"else"}],"checkall":"true","outputs":2,"x":692,"y":144.24996948242188,"wires":[["786e5520.e21dec"],["667258aa.b59b28"]]},{"id":"667258aa.b59b28","type":"function","z":"fbd6dad5.34a1b","name":"KO","func":"msg.payload = \"Service météo horaire inaccessible\";\nreturn msg","outputs":1,"noerr":0,"x":1005.3333740234375,"y":151.25,"wires":[[]]},{"id":"97344880.ddfc1","type":"subflow","name":"day weather","info":"","in":[{"x":156,"y":138,"wires":[{"id":"fe3e4c98.00d3d"}]}],"out":[{"x":1134,"y":118,"wires":[{"id":"16a06c4f.3308e4","port":0},{"id":"b6376939.0bf5","port":0}]}]},{"id":"fe3e4c98.00d3d","type":"template","z":"97344880.ddfc1","name":"Prepare command","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"wget http://www.prevision-meteo.ch/services/json/PARIS -q -O -","output":"str","x":346,"y":136,"wires":[["dd7acf78.82fb58"]]},{"id":"dd7acf78.82fb58","type":"exec","z":"97344880.ddfc1","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Exec curl","x":518,"y":135,"wires":[["135bf690.b70a01"],[],[]]},{"id":"135bf690.b70a01","type":"switch","z":"97344880.ddfc1","name":"Check result","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"Please specify a valid city or a coordinate","vt":"str"},{"t":"else"}],"checkall":"true","outputs":2,"x":677,"y":102,"wires":[["16a06c4f.3308e4"],["721ea662.710f28"]]},{"id":"721ea662.710f28","type":"json","z":"97344880.ddfc1","name":"conversion","pretty":false,"x":844,"y":130,"wires":[["b6376939.0bf5"]]},{"id":"16a06c4f.3308e4","type":"function","z":"97344880.ddfc1","name":"KO","func":"msg.payload = \"Service météo inaccessible\";\nreturn msg","outputs":1,"noerr":0,"x":990.3333740234375,"y":95.00003051757812,"wires":[[]]},{"id":"b6376939.0bf5","type":"function","z":"97344880.ddfc1","name":"OK","func":"today=msg.payload.fcst_day_0.day_long + \", il fait \" + msg.payload.current_condition.tmp + \" degrés et les conditions sont : \" + msg.payload.current_condition.condition + \".\\n\";\ntomorrow=msg.payload.fcst_day_1.day_long + \", la température sera entre \" + msg.payload.fcst_day_1.tmin + \" degrés et \" + msg.payload.fcst_day_1.tmax + \" degrés.\\nLes conditions seront : \" + msg.payload.fcst_day_1.condition + \".\";\n\nmsg.payload = today;\n\nreturn msg","outputs":1,"noerr":0,"x":990.3333740234375,"y":130.00003051757812,"wires":[[]]},{"id":"544cbc07.0db904","type":"comment","z":"97344880.ddfc1","name":"Météo du jour","info":"","x":324.75,"y":55.85711669921875,"wires":[]},{"id":"73ff3e8e.1500d","type":"subflow","name":"dialog","info":"","in":[{"x":164,"y":118,"wires":[{"id":"b1877146.18e528"}]}],"out":[{"x":866,"y":125,"wires":[{"id":"634d3b8d.9e33e4","port":0}]}]},{"id":"dcc05f26.da644","type":"exec","z":"73ff3e8e.1500d","command":"","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"call recast.api/dialog","x":560,"y":119,"wires":[["634d3b8d.9e33e4"],[],[]]},{"id":"b1877146.18e528","type":"template","z":"73ff3e8e.1500d","name":"Prepare command","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"curl -H \"Authorization: Token 71c52df587ba816e4fea6be69787d15b\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"message\": {\"content\":\"{{payload}}\",\"type\":\"text\"}, \"conversation_id\": \"{{global.conversation_token}}\"}' \\\n -X POST \"https://api.recast.ai/build/v1/dialog\"","output":"str","x":323.10711669921875,"y":119.607177734375,"wires":[["dcc05f26.da644"]]},{"id":"634d3b8d.9e33e4","type":"json","z":"73ff3e8e.1500d","name":"","property":"payload","action":"","pretty":false,"x":738.625,"y":123.294677734375,"wires":[[]]},{"id":"d580fc28.71aab8","type":"subflow","name":"init dialog","info":"","in":[{"x":145.33331298828125,"y":103,"wires":[{"id":"3a0b51a.7f5d02e"}]}],"out":[{"x":1161.6666259765625,"y":98.66668701171875,"wires":[{"id":"507f653b.5e7674","port":0}]}]},{"id":"10fd2230.46672e","type":"exec","z":"d580fc28.71aab8","command":"/home/pi/AIY-projects-python/src/conversation.py","addpay":true,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"init dialog","x":543.6667785644531,"y":102.33332824707031,"wires":[["d7f62ae.f4ebf58"],[],[]]},{"id":"d7f62ae.f4ebf58","type":"string","z":"d580fc28.71aab8","name":"set global var","methods":[{"name":"trim","params":[]}],"prop":"payload","propout":"conversation_token","object":"msg","objectout":"global","x":733.8751525878906,"y":101.60401916503906,"wires":[["507f653b.5e7674"]]},{"id":"3a0b51a.7f5d02e","type":"change","z":"d580fc28.71aab8","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"message","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":346.833251953125,"y":104.33331298828125,"wires":[["10fd2230.46672e"]]},{"id":"507f653b.5e7674","type":"change","z":"d580fc28.71aab8","name":"","rules":[{"t":"move","p":"message","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":960,"y":98.66668701171875,"wires":[[]]},{"id":"dcc3ce49.ee03e","type":"inject","z":"607e0e83.a2db2","name":"test:quel temps fait-il aujourd'hui ?","topic":"test","payload":"quel temps fait-il aujourd'hui ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":192.82125854492188,"y":566.285400390625,"wires":[["1dd13035.c2d908"]]},{"id":"edab227f.488648","type":"http in","z":"607e0e83.a2db2","name":"/ call my bot","url":"callRecast","method":"get","upload":false,"swaggerDoc":"","x":152.85711669921875,"y":135.142822265625,"wires":[["df30c445.1ecc18"]]},{"id":"df30c445.1ecc18","type":"change","z":"607e0e83.a2db2","name":"get param","rules":[{"t":"move","p":"payload.param","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":316.02374267578125,"y":134.64281463623047,"wires":[["1dd13035.c2d908","a0891beb.80dd7"]]},{"id":"eb7cce92.c4901","type":"inject","z":"607e0e83.a2db2","name":"test:va-t-il pleuvoir dans l'heure ?","topic":"test","payload":"Va-t-il pleuvoir dans l'heure ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":197.52383422851562,"y":527.3094787597656,"wires":[["1dd13035.c2d908"]]},{"id":"dfb16dec.a71a58","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"maintenant","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":240.95242309570312,"y":437.57452392578125,"wires":[["1dd13035.c2d908"]]},{"id":"a61cf3e8.367ce","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"météo","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":259.5595703125,"y":400.8123779296875,"wires":[["1dd13035.c2d908"]]},{"id":"e2dacaea.1043f8","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1078.71435546875,"y":126.4197998046875,"wires":[]},{"id":"6ba99830.d2b3","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"ok johnny","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":719.321533203125,"y":127.47911834716797,"wires":[["357e11cc.5391f6"]]},{"id":"4822fc3a.79f6ac","type":"comment","z":"607e0e83.a2db2","name":"dialog with my bot Johnny !","info":"","x":205.86904907226562,"y":83.13385009765625,"wires":[]},{"id":"357e11cc.5391f6","type":"subflow:d580fc28.71aab8","z":"607e0e83.a2db2","name":"","x":919.071533203125,"y":127.21727752685547,"wires":[["e2dacaea.1043f8"]]},{"id":"f3464089.0ee51","type":"subflow:73ff3e8e.1500d","z":"607e0e83.a2db2","name":"","x":708.9603881835938,"y":450.47125244140625,"wires":[["31a97ebe.fa8bea","d91562a6.fdb908"]]},{"id":"4041e1a2.44881","type":"switch","z":"607e0e83.a2db2","name":"if ask weather","property":"payload.results.conversation.memory.context","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1164.833251953125,"y":266.2530212402344,"wires":[["a33986d6.e5518"],["2675f719.75756"]]},{"id":"5e1fa649.205328","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"du jour","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":254.28558349609375,"y":475.96710205078125,"wires":[["1dd13035.c2d908"]]},{"id":"2675f719.75756","type":"switch","z":"607e0e83.a2db2","name":"switch context","property":"payload.results.conversation.memory.context","propertyType":"msg","rules":[{"t":"eq","v":"now","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1385.6666259765625,"y":293.3961181640625,"wires":[["f514f00d.401018"],["8fd17b2b.b8a3c8"]]},{"id":"c8fd1ace.8c931","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1076.1431884765625,"y":163.32445526123047,"wires":[]},{"id":"42b3bce9.c1247c","type":"inject","z":"607e0e83.a2db2","name":"get conversation_token","topic":"","payload":"conversation_token","payloadType":"global","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":748.57177734375,"y":164.96722412109375,"wires":[["c8fd1ace.8c931"]]},{"id":"1dd13035.c2d908","type":"switch","z":"607e0e83.a2db2","name":"if token not init","property":"conversation_token","propertyType":"global","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":546.0316772460938,"y":457.36419677734375,"wires":[["f3464089.0ee51"],["24e72254.ea79ae"]]},{"id":"24e72254.ea79ae","type":"subflow:d580fc28.71aab8","z":"607e0e83.a2db2","name":"","x":628.8888549804688,"y":514.6974411010742,"wires":[["f3464089.0ee51"]]},{"id":"1a509149.499d27","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"météo du jour","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":239.7142333984375,"y":270.20538330078125,"wires":[["1dd13035.c2d908"]]},{"id":"8fd17b2b.b8a3c8","type":"subflow:97344880.ddfc1","z":"607e0e83.a2db2","name":"","x":1572.6666259765625,"y":314.0001220703125,"wires":[["cdee81e7.032ca"]]},{"id":"f514f00d.401018","type":"subflow:fbd6dad5.34a1b","z":"607e0e83.a2db2","name":"","x":1576.6666259765625,"y":270.0001220703125,"wires":[["cdee81e7.032ca"]]},{"id":"31a97ebe.fa8bea","type":"switch","z":"607e0e83.a2db2","name":"switch skill","property":"payload.results.conversation.skill","propertyType":"msg","rules":[{"t":"eq","v":"ask-weather","vt":"str"},{"t":"eq","v":"ask-timedadreturn","vt":"str"},{"t":"eq","v":"ask-restaurant","vt":"str"},{"t":"eq","v":"smalltalk","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":5,"x":881.222412109375,"y":449.9443359375,"wires":[["4041e1a2.44881"],[],["67a45104.b1d578"],["201314f.30f45ec"],["e3deb339.9a1ac"]]},{"id":"4e58edc6.9c611c","type":"http response","z":"607e0e83.a2db2","name":"","statusCode":"200","headers":{},"x":2046.7779541015625,"y":385.61114501953125,"wires":[]},{"id":"e3deb339.9a1ac","type":"function","z":"607e0e83.a2db2","name":"Et là c'est le bug !","func":"msg.payload = \"Et là c'est le beug\"\nreturn msg;","outputs":1,"noerr":0,"x":1112.5555419921875,"y":824.72216796875,"wires":[["15a70f73.fb5fc9","ead95919.d45538"]]},{"id":"a33986d6.e5518","type":"function","z":"607e0e83.a2db2","name":"get message","func":"msg.payload = msg.payload.results.messages[0].content;\nreturn msg;","outputs":1,"noerr":0,"x":1377.6666259765625,"y":227.5001220703125,"wires":[["2766439c.39b754","b1137590.264d78"]]},{"id":"2766439c.39b754","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1567.6666259765625,"y":185.16677856445312,"wires":[]},{"id":"15a70f73.fb5fc9","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1314.9998779296875,"y":863.6112060546875,"wires":[]},{"id":"d91562a6.fdb908","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":859.031982421875,"y":512.7063598632812,"wires":[]},{"id":"8b938acc.8ad908","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"dis moi une blague","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":244.19046020507812,"y":228.97616577148438,"wires":[["1dd13035.c2d908"]]},{"id":"b6d13e85.0e29e8","type":"function","z":"607e0e83.a2db2","name":"get message","func":"msg.payload = msg.payload.results.conversation.memory.context.description;\nreturn msg;","outputs":1,"noerr":0,"x":1311.44482421875,"y":652.3332824707031,"wires":[["907249e0.1c92b","1830ca15.1ef316"]]},{"id":"6d480f7e.080fd8","type":"comment","z":"607e0e83.a2db2","name":"init token manually","info":"","x":716.5714111328125,"y":82.6666488647461,"wires":[]},{"id":"c588fa03.800968","type":"comment","z":"607e0e83.a2db2","name":"call Recast.ai API","info":"","x":676.6507568359375,"y":410.11114501953125,"wires":[]},{"id":"f112c359.12372","type":"inject","z":"607e0e83.a2db2","name":"test:quel est ton nom ?","topic":"test","payload":"quel est ton nom ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":221,"y":312,"wires":[["1dd13035.c2d908"]]},{"id":"d10f1449.37ed18","type":"inject","z":"607e0e83.a2db2","name":"test:quel temps fait il ?","topic":"test","payload":"Quel temps fait-il ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":219.3809814453125,"y":364.21405029296875,"wires":[["1dd13035.c2d908"]]},{"id":"3190e5ec.fc04ba","type":"inject","z":"607e0e83.a2db2","name":"test:peux tu me servir une bière ?","topic":"test","payload":"peux tu me servir une bière ?","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":337.364990234375,"y":796.7618408203125,"wires":[["1dd13035.c2d908"]]},{"id":"201314f.30f45ec","type":"switch","z":"607e0e83.a2db2","name":"if smalltalk","property":"payload.results.conversation.memory.context","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1125.33349609375,"y":678.3333129882812,"wires":[["b6d13e85.0e29e8"],["7a0dfe1e.bf0bb"]]},{"id":"a0891beb.80dd7","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":495.6666259765625,"y":135.33333587646484,"wires":[]},{"id":"360b6d53.081662","type":"inject","z":"607e0e83.a2db2","name":"test:peux-tu me conseiller un restaurant","topic":"test","payload":"peux-tu me conseiller un restaurant","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":239.12701416015625,"y":625.28564453125,"wires":[["1dd13035.c2d908"]]},{"id":"41392bbe.a6a6dc","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"bistro","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":332.0159606933594,"y":665.7935791015625,"wires":[["1dd13035.c2d908"]]},{"id":"df31d3e8.96ada","type":"inject","z":"607e0e83.a2db2","name":"","topic":"test","payload":"pizzeria","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":338.46038818359375,"y":703.238037109375,"wires":[["1dd13035.c2d908"]]},{"id":"67a45104.b1d578","type":"switch","z":"607e0e83.a2db2","name":"if ask restaurant","property":"payload.results.conversation.memory.genre","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1139.55517578125,"y":457.6666564941406,"wires":[["5b154c55.8fedb4"],["25f63b75.4114a4"]]},{"id":"5b154c55.8fedb4","type":"function","z":"607e0e83.a2db2","name":"get message","func":"msg.payload = msg.payload.results.messages[0].content;\nreturn msg;","outputs":1,"noerr":0,"x":1518.555419921875,"y":449.3332824707031,"wires":[["87515a0b.ef2b1","4d44d82a.fc5b58"]]},{"id":"87515a0b.ef2b1","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1714.2222900390625,"y":401.6665954589844,"wires":[]},{"id":"4d44d82a.fc5b58","type":"link out","z":"607e0e83.a2db2","name":"","links":["a7dd435b.1abc88"],"x":1701.0556640625,"y":449.9166259765625,"wires":[]},{"id":"a7dd435b.1abc88","type":"link in","z":"607e0e83.a2db2","name":"return","links":["4d44d82a.fc5b58","b1137590.264d78","c46c1729.82ed1","92a2848b.63631","58631799.8b3298","6d7c7668.796ac","65477f41.df3b9"],"x":1955.6112060546875,"y":386.0555419921875,"wires":[["4e58edc6.9c611c"]]},{"id":"b1137590.264d78","type":"link out","z":"607e0e83.a2db2","name":"","links":["a7dd435b.1abc88"],"x":1623.333251953125,"y":229.0000991821289,"wires":[]},{"id":"c46c1729.82ed1","type":"link out","z":"607e0e83.a2db2","name":"","links":["a7dd435b.1abc88"],"x":1754.3331298828125,"y":705.7777709960938,"wires":[]},{"id":"d223c22f.5baf9","type":"inject","z":"607e0e83.a2db2","name":"06 01 02 03 04","topic":"test","payload":"06 01 02 03 04","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":339.46038818359375,"y":741.2381591796875,"wires":[["1dd13035.c2d908"]]},{"id":"25f63b75.4114a4","type":"switch","z":"607e0e83.a2db2","name":"if genre & phone present","property":"payload.results.conversation.memory.phone","propertyType":"msg","rules":[{"t":"null"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":1289.22216796875,"y":550.3334045410156,"wires":[["5b154c55.8fedb4"],["d031e9a.072ac98"]]},{"id":"907249e0.1c92b","type":"function","z":"607e0e83.a2db2","name":"reset token","func":"global.set(\"conversation_token\",null);\nreturn msg","outputs":1,"noerr":0,"x":1538.3333740234375,"y":705.7778930664062,"wires":[["c46c1729.82ed1"]]},{"id":"c971a47e.c44068","type":"function","z":"607e0e83.a2db2","name":"get message","func":"genre = msg.payload.results.conversation.memory.genre.value;\nphone = msg.payload.phone;\nmsg.payload = \"Je t'envoie l'adresse d'un restaurant\";\n/*\" + genre + \" au \" + phone;*/\nreturn msg;","outputs":1,"noerr":0,"x":1678.22216796875,"y":518.6665954589844,"wires":[["b0e7e684.bc19f8"]]},{"id":"92a2848b.63631","type":"link out","z":"607e0e83.a2db2","name":"","links":["a7dd435b.1abc88"],"x":1970.5556640625,"y":483.111328125,"wires":[]},{"id":"b0e7e684.bc19f8","type":"function","z":"607e0e83.a2db2","name":"reset token","func":"global.set(\"conversation_token\",null);\nreturn msg","outputs":1,"noerr":0,"x":1850.221923828125,"y":515,"wires":[["92a2848b.63631","dc6982c1.c9cd1"]]},{"id":"dc6982c1.c9cd1","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":2020.888671875,"y":516.3333740234375,"wires":[]},{"id":"1830ca15.1ef316","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1499.9998779296875,"y":651.7778930664062,"wires":[]},{"id":"cdee81e7.032ca","type":"function","z":"607e0e83.a2db2","name":"reset token","func":"global.set(\"conversation_token\",null);\nreturn msg","outputs":1,"noerr":0,"x":1773,"y":296.33343505859375,"wires":[["74bd8dc8.bafb5c","6d7c7668.796ac"]]},{"id":"74bd8dc8.bafb5c","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1961,"y":254.33343505859375,"wires":[]},{"id":"6d7c7668.796ac","type":"link out","z":"607e0e83.a2db2","name":"","links":["a7dd435b.1abc88"],"x":1895,"y":294.33343505859375,"wires":[]},{"id":"7a0dfe1e.bf0bb","type":"function","z":"607e0e83.a2db2","name":"Et là c'est le bug !","func":"msg.payload = \"Et là c'est le beug\"\nreturn msg;","outputs":1,"noerr":0,"x":1329.9998779296875,"y":705.7778930664062,"wires":[["567209bb.f90e1","907249e0.1c92b"]]},{"id":"65477f41.df3b9","type":"link out","z":"607e0e83.a2db2","name":"","links":["a7dd435b.1abc88"],"x":1751.9998779296875,"y":821.7778930664062,"wires":[]},{"id":"567209bb.f90e1","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1538.9998779296875,"y":743.7778930664062,"wires":[]},{"id":"d031e9a.072ac98","type":"string","z":"607e0e83.a2db2","name":"trim","methods":[{"name":"replaceAll","params":[{"type":"str","value":" "},{"type":"str","value":""}]},{"name":"trim","params":[]}],"prop":"payload.results.conversation.memory.phone.raw","propout":"payload.phone","object":"msg","objectout":"msg","x":1491.72216796875,"y":556.0000305175781,"wires":[["c971a47e.c44068","c48a1b8b.b92e1","904ab856.4d5fc"]]},{"id":"c48a1b8b.b92e1","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":1655.72216796875,"y":603,"wires":[]},{"id":"ead95919.d45538","type":"function","z":"607e0e83.a2db2","name":"reset token","func":"global.set(\"conversation_token\",null);\nreturn msg","outputs":1,"noerr":0,"x":1523.9998779296875,"y":823.7778930664062,"wires":[["65477f41.df3b9"]]},{"id":"96fb8cb7.6a028","type":"comment","z":"607e0e83.a2db2","name":"Return message","info":"","x":2021.1666259765625,"y":348.3333740234375,"wires":[]},{"id":"ac594ebf.4bfe78","type":"http request","z":"607e0e83.a2db2","name":"send SMS","method":"GET","ret":"txt","url":"http://10.0.0.23:1880/sendsms?phone={{payload.phone}}&msg={{payload.restaurant}}","tls":"","x":2119.77783203125,"y":555.5555419921875,"wires":[[]]},{"id":"904ab856.4d5fc","type":"switch","z":"607e0e83.a2db2","name":"switch genre","property":"payload.results.conversation.memory.genre.value","propertyType":"msg","rules":[{"t":"regex","v":"bistro","vt":"str","case":true},{"t":"regex","v":"pizzeria","vt":"str","case":true}],"checkall":"true","repair":false,"outputs":2,"x":1677.8890380859375,"y":562.0000305175781,"wires":[["f92ae7d2.f9e578"],["a2e80a11.7d646"]]},{"id":"a2e80a11.7d646","type":"function","z":"607e0e83.a2db2","name":"if pizzeria","func":"msg.payload.restaurant = \"Adresse d'une bonne pizzeria dans le quartier..\";\nreturn msg;","outputs":1,"noerr":0,"x":1840.333251953125,"y":593.3334045410156,"wires":[["2556a995.043886"]]},{"id":"f92ae7d2.f9e578","type":"function","z":"607e0e83.a2db2","name":"if bistro","func":"msg.payload.restaurant = \"Adresse d'un bon bistro dans le quartier..\";\nreturn msg;","outputs":1,"noerr":0,"x":1841.333251953125,"y":555.8888854980469,"wires":[["2556a995.043886"]]},{"id":"2556a995.043886","type":"string","z":"607e0e83.a2db2","name":"","methods":[{"name":"replaceAll","params":[{"type":"str","value":"'"},{"type":"str","value":" "}]}],"prop":"payload.restaurant","propout":"payload.restaurant","object":"msg","objectout":"msg","x":1979,"y":556,"wires":[["ac594ebf.4bfe78","8afd949b.e06aa"]]},{"id":"8afd949b.e06aa","type":"debug","z":"607e0e83.a2db2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":2108,"y":604,"wires":[]}]
Sur Recast, si vous voulez voir de plus prêt le chatbot utilisé dans cet article, vous pouvez y accéder en allant sur la plateforme de la communauté. Ce chatbot se nomme « Johnny » car il parait qu’il faut toujours trouver un nom à chatbot.
![]()
Machine learning, changement de paradigme
Le principe du Machine learning est d’entraîner son moteur d’IA avec pleins d’exemples, pour qu’il puisse de lui-même en trouver les caractéristiques communes et devenir capable de traiter des formulations qu’on n’aurait pas prévu. En terme de conception de programme, cette approche est un changement de paradigme. On ne programme plus des algo qui déterminent tous les cas à l’avance. On prévoit des comportements en fonction d’analyses probalistiques qui peuvent évoluer. L’entraînement est donc un process itératif.
Ce qui est intéressant de savoir c’est qu’en 2012 le machine learning a permis d’obtenir de meilleurs résultats pour faire de la reconnaissance d’image. Pour autant on ne sait pas démontrer pourquoi cela fonctionne mieux ! Donc il faut rester réservé sur l’engouement du machine learning, car si cela se trouve d’ici peu, on trouvera une approche encore plus efficace !
Entraîner son chatbot
Concernant notre assistant vocal, évidemment il est très jeune. Il mérite d’être entrainé pour le rendre plus costaud.
Dans cette dernière vidéo nous allons voir comment fonctionne cette notion d’entraînement avec Recast. À ce stade pour rechercher un restaurant l’utilisateur dit « peux tu me conseiller un restaurant, puis pizzeria ». Si à la place il disait « je cherche un restaurant » et « j’adore la pizza » il est probable que notre assistant ne comprenne pas cette intention. Le but de l’entraînement va être d’apprendre au chatbot suffisamment de formulations pour qu’il interprète avec justesse l’intention de l’utilisateur.
Voici en vidéo, comment on procède :
Conclusion
Google a fait très fort en proposant ce Voice Kit en permettant de s’approprier la technologie de l’intelligence artificielle. A moins de 100 euros l’investissement, on est vraiment sur une démarche d’innovation frugale.
L’intérêt de développer sa propre solution c’est de pouvoir choisir les briques de service et de définir soi-même les règles de fonctionnement. Dans le cas présent, j’ai choisi de devoir appuyer sur le bouton afin de ne pas avoir un système qui vous écoute toute la journée… et qui se met à dire d’un seul coup « Désolé je n’ai pas compris » alors que vous n’étiez absolument pas en train de lui demander quoique ce soit. J’ai également choisi que l’orchestration se fasse en local via le RPI, ce qui sécurise fortement les interactions avec les autres objets connectés de son domicile.
L’objet de cet article était d’utiliser juste ce qui était nécessaire pour arriver à faire un assistant vocal.. Objectif atteint ! Concernant les API de Google ou de Recast nous les avons juste survolé. Ces plateformes ont beaucoup d’autres fonctionnalités qui méritent votre attention.
Pour aller plus loin
Le fait que les moteurs NLU et NLP soient dans le cloud, sont des risques de fuites d’informations privées. Une prochaine étape serait d’installer en local le NLU, sur le RPI. Dans les solutions possibles pour y arriver, il y a le Vision Kit de Google qui intègre une carte GPU avec Tensorflow (mais en rupture de stock). Il y a la clé de Movidius qui utilise la même GPU. Une autre piste est de s’appuyer sur l’approche de Snips.ai.
Pour le moteur NLP, je vois un intérêt à passer par le cloud pour s’appuyer sur une communauté comme celle de Recast. Car en mettant en publics ses « skills », on partage son savoir-faire. Pouvoir faire un « fork » d’un cas de figure déjà abordé fait gagner du temps, mais surtout c’est un moyen de voir différentes approches pour faire le « design » d’une conversation.
The post S’initier à l’IA avec un assistant vocal fait maison appeared first on Domotique Info.