IoT et interface naturelle

Créer des applications technologiques c'est bien, mais les rendre accessibles de manière naturelle aux utilisateurs, c'est mieux!

Voici donc un exemple de comment mettre en place un cas d'usage complet : un chatbot ("robot conversationnel" !) vocal capable de récupérer les données émises par des objets.

chatbot iot cumulocity ai

Scénario fonctionnel

  • Un utilisateur pose une question à l'assistant vocal Google
  • Une fois interprétée, la version textuelle est transmise à un chatbot
  • Le chatbot comprend l'action à déclencher à partir de mots-clés
  • Une requête est envoyée vers la plateforme IoT pour récupérer les données
  • Le chatbot répond à l'utilisateur de manière naturelle en incluant une visualisation pertinente des données

Mise en place

Concrètement, ce genre de solution peut être mis en place à l'aide d'outils simples enchainés les uns aux autres. Pour la partie vocale, l'assistant de Google pour smartphone fait très bien le travail de reconnaissance. Le chatbot ainsi que son intelligence artificielle apportés par le service Recast.ai permettent d'apporter une fluidité très appréciée dans l'interaction homme-machine. Son atout principal repose sur le fait qu'il permet d'étendre un robot pré-entrainé, par exemple à faire la conversation, pour lui ajouter des compétences spécifiques à notre besoin. Cela garanti que même lorsque votre robot ne sera pas en mesure de reconnaitre une action correspondant à votre scénario, il répondra de manière naturelle en mode conversation.

L'autre grand intérêt de la solution Recast.ai est qu'elle est très orientée vers les développeurs, et fourni donc plusieurs types d'interfaces pour activer son robot selon les besoins : via des "BotConnector" vers les applications de messageries les plus répandues (Facebook, Slack, Tweeter, Skype...) mais également via une interface REST. Et la customisation du robot passe par l'écriture de code Javascript/NodeJS, hébergé par Recast.ai eux-mêmes.

Pour démarrer rapidement la mise en place de votre bot, vous pouvez suivre cette documentation, expliquant de A à Z toutes les étapes.

Retour d'expérience

Pour vous faciliter la tâche, voici quelques astuces afin d'optimiser l'élaboration de votre bot. Cet exemple s'appui sur les extraits de code issus de la documentation citée précédemment. Le code du bot ressemble donc à cela :


const recastai = require('recastai').default;
const client = new recastai(process.env.REQUEST_TOKEN);
const request = require('request');
const axios = require('axios');

export const bot = (body, response, callback) => {
    console.log(body);

// response, the response object from the server in case of a local run
// callback, the object called in case of a bot hosting run

    if (body.message) {
        // pour gérer les appels par BotConnector (Slack...)
        client.connect.handleMessage({body}, response, replyMessage);
    } else if (body.text) {
        // pour gérer les appels par API REST en direct
        replyMessage(null, body.text, callback);
    } else {
        callback('Requete vide?!');
    }
};

function replyMessage(message, textMessage, callback) {
    if (message) {
        console.log("handling BotConnector message");
    } else {
        console.log("handling API message");
    }
    const recastaiReq = new recastai.request(process.env.REQUEST_TOKEN, process.env.LANGUAGE);
    const contentMessage = message ? message.content : textMessage;
    recastaiReq.analyseText(contentMessage)
            .then(recastaiRes => {
    var varcontent = "";
                // get the intent detected
                var intent = recastaiRes.intent();
                if (intent) {
                    console.log("intent:" + intent.slug + "/" + intent.confidence);
                    if (intent.slug === 'c8y_geoloc' && intent.confidence > 0.7) {
                        if (recastaiRes.get('asset-type') && recastaiRes.get('number')) {
                            // type d'objet recherché (par ex 'caisse')
                            var asset = recastaiRes.get('asset-type').raw;
                            // id de l'objet
                            var number = recastaiRes.get('number').raw;

                            axios.get('',
                                    {
                                        headers: {"Authorization": "Basic ..."} 
                                    })
                                    .then(response => {
                                        var body = response.data;

                                        if (body.managedObject) {
                                            //... do stuff
                                            return message ? message.reply([{type: 'text', content: varcontent}]).then() :
                                                   callback(null, {result: varcontent, intent: intent.slug, data: dataResp});
                                        } else {
                                            varcontent = 'Je n\'ai rien trouvé!';
                                            return message ? message.reply([{type: 'text', content: varcontent}]).then() :
                                                    callback(null, {result: varcontent, intent: intent.slug});
                                        }
                                    })
                                    .catch(error => {
                                        varcontent = 'Il y a eu un problème...';
                                        return message ? message.reply([{type: 'text', content: varcontent + error}]) :
                                                callback(error, null);
                                    });
                        } else {
                            varcontent = 'Je ne sais pas quoi chercher...';
                            return message ? message.reply([{type: 'text', content: varcontent}]).then() :
                                    callback(null, {result: varcontent, intent: intent.slug});
                        }
                    } else {
                        // on fait appel au moteur de conversation, pour conserver l'intelligence par defaut du bot
                        const converseReq = new recastai.request(process.env.REQUEST_TOKEN, process.env.LANGUAGE);

                        return converseReq.converseText(contentMessage)
                                .then(function (res2) {
                                    // ...extract the reply...
                                    varcontent = res2.reply();

                                    return message ? message.reply([{type: 'text', content: varcontent}]).then() :
                                            callback(null, {result: varcontent, intent: 'null'});
                                })
                                .catch(err => {
                                    console.error('Something went wrong', err);
                                    return message ? message.reply([{type: 'text', content: 'Something went wrong' + err}]) :
                                            callback(err, null);
                                });
                    }
                } else {
                    return message ? message.reply([{type: 'text', content: varcontent}]) :
                            callback(null, {result: varcontent, intent: 'null'});
                }
            })
            .catch(err => {
                console.error('Something went wrong', err);
                return message ? message.reply([{type: 'text', content: 'Something went wrong' + err}]) :
                        callback(err, null);
            });
}

Gestion des exceptions

Il est primordial que toutes les éventuelles exceptions soient correctement gérées afin que dans tous les cas, une réponse soit renvoyée, même s'il s'agit d'un message d'erreur (plus ou moins "naturel" ;), sans quoi la requête HTTP qui a appelée votre bot restera bloquée en attente d'une réponse...

Exploiter au mieux l'API Message

La plateforme Recast.ai met à disposition une API très utile permettant de créer automatiquement une réponse à un message issu d'une conversation via une messagerie instantanée (Tweeter, Slack...) tout en préservant les notions de conversation, réponse à un utilisateur spécifique, contexte du message etc, tout ceci de manière transparente via l'utilisation de la méthode message.reply(). Ainsi, quelle que soit l'origine du message ou sa forme, votre contenu sera toujours correctement interprété par la plateforme cible.

Vous avez maintenant tout ce qu'il faut pour mettre en place une interface naturelle dans votre projet!


Fichier(s) joint(s) :

0 commentaires: