Mettre en oeuvre des composants personnalisés

Pour mettre en oeuvre des composants personnalisés, vous utilisez la trousse SDK Node.js d'Oracle Digital Assistant pour assurer l'interface avec le service de composants personnalisés de Digital Assistant.

Voici comment mettre en oeuvre des composants personnalisés que vous pouvez déployer sur le conteneur intégré de Digital Assistant, Oracle Cloud Infrastructure Functions, un système dorsal Mobile Hub ou un serveur Node.js :

  1. Installer les logiciels pour créer des composants personnalisés.

  2. Créer l'ensemble de composants personnalisés.

  3. Créer un composant personnalisé.

Note

Si vous prévoyez de déployer l'ensemble de composants personnalisés dans un service de composants personnalisés intégré, chaque compétence à laquelle vous ajoutez l'ensemble est comptée comme un service distinct. Le nombre de services de composants personnalisés intégrés qu'une instance peut avoir est limité. Si vous ne connaissez pas la limite, demandez à votre administrateur de service d'obtenir le nombre embedded-custom-component-service-count pour vous comme décrit dans Voir les limites de service dans la console d'infrastructure. Envisagez de regrouper plusieurs composants dans un ensemble afin de réduire le nombre de services de composants intégrés que vous utilisez. Si vous essayez d'ajouter un service de composants après avoir atteint cette limite, la création de celui-ci échoue.

Étape 1 : Installer les logiciels pour créer des composants personnalisés

Pour créer un ensemble de composants personnalisés, vous avez besoin de Node.js, du gestionnaire d'ensembles de Node.js (npm) et de la trousse SDK Node.js de développement de robots d'Oracle Digital Assistant.

Note

Sous Windows, la trousse SDK de développement de robots ne fonctionne pas sous Windows si l'installation du noeud est version 20.12.2 ou supérieure en raison d'une modification incompatible avec le passé dans Node.js. Si vous avez déjà installé Node version 20.12.2 ou supérieure, vous devez le désinstaller, puis installer la version 20.12.1 ou antérieure pour que la trousse SDK Bots Node fonctionne.
  1. Téléchargez Node.js à partir de https://nodejs.org, s'il y a lieu, et installez-le pour un accès global. Le gestionnaire d'ensembles de Node.js (npm) est distribué avec Node.js.

    Pour vérifier si Node.js et npm sont installés, ouvrez une fenêtre de terminal et entrez les commandes suivantes :

    node –v 
    npm –v
  2. Pour installer la trousse SDK Node.js de développement de robots d'Oracle Digital Assistant pour un accès global, entrez cette commande dans une fenêtre de terminal :
    npm install -g @oracle/bots-node-sdk

    Dans un environnement Mac, vous utilisez la commande sudo :

    sudo npm install -g @oracle/bots-node-sdk

    Lorsque vous utilisez l'option -g (accès global), vous avez un accès direct à l'interface de ligne de commande bots-node-sdk. Sinon, utilisez npx @oracle/bots-node-sdk.

  3. Pour vérifier l'installation de votre trousse SDK Node.js de développement de robots d'Oracle Digital Assistant, tapez la commande suivante :
    bots-node-sdk -v
    La commande doit afficher la version de la trousse SDK Node.js de développement de robots d'Oracle Digital Assistant.

Étape 2 : Créer l'ensemble de composants personnalisés

Pour démarrer un projet, vous utilisez la commande bots-node-sdk init à partir de l'interface de ligne de commande (CLI) de la trousse SDK pour créer les fichiers et la structure de répertoire nécessaires à votre structure de composant.

La commande init comporte quelques options, telles que l'utilisation ou non de JavaScript (valeur par défaut) ou de TypeScript, et le nom à donner au fichier JavaScript du composant initial. Ces options sont décrites dans Outils pour développeurs d'interface de ligne de commande. Voici la commande de base pour démarrer un projet JavaScript :

bots-node-sdk init <top-level folder path> --name <component service name>

Cette commande effectue les actions suivantes pour un ensemble JavaScript :

  • Elle crée le dossier de niveau supérieur.

  • Elle crée un dossier components et y ajoute un exemple de fichier JavaScript de composant nommé hello.world.js. C'est ici que vous allez placer vos fichiers JavaScript de composant.

  • Elle ajoute un fichier package.json, qui spécifie main.js comme point d'entrée principal et liste @oracle/bots-node-sdk comme devDependency. Par ailleurs, le fichier de l'ensemble pointe vers les scripts bots-node-sdk.

    {
      "name": "myCustomComponentService",
      "version": "1.0.0",
      "description": "Oracle Bots Custom Component Package",
      "main": "main.js",
      "scripts": {
        "bots-node-sdk": "bots-node-sdk",
        "help": "npm run bots-node-sdk -- --help",
        "prepack": "npm run bots-node-sdk -- pack --dry-run",
        "start": "npm run bots-node-sdk -- service ."
      },
      "repository": {},
      "dependencies": {},
      "devDependencies": {
        "@oracle/bots-node-sdk": "^2.2.2",
        "express": "^4.16.3"
      }
    }
  • Elle ajoute un fichier main.js au dossier de niveau supérieur. Ce fichier exporte les paramètres de l'ensemble et désigne le dossier de niveau supérieur comme emplacement pour les composants.

  • Elle ajoute un fichier .npmignore au dossier de niveau supérieur. Ce fichier sert à l'exportation de l'ensemble de composants. Il doit exclure les fichiers .tgz de l'ensemble. Par exemple : *.tgz.

  • Pour certaines versions du npm, elle crée un fichier package-lock.json.

  • Elle installe toutes les dépendances de l'ensemble dans le sous-dossier node_modules.
Note

Si vous n'utilisez pas la commande bots-node-sdk init pour créer le dossier de l'ensemble, assurez-vous que le dossier de niveau supérieur comporte un fichier .npmignore qui contient une entrée *.tgz. Par exemple :
*.tgz
spec
service-*

Sinon, chaque fois que vous assemblez les fichiers dans un fichier TGZ, vous incluez le fichier TGZ qui existe déjà dans le dossier de niveau supérieur, et votre fichier TGZ continuera de doubler de volume.

Si vous envisagez un déploiement dans le conteneur intégré, votre ensemble doit être compatible avec le noeud 14.17.0.

Étape 3 : Créer un composant personnalisé

Créer le fichier de composant

Utilisez la commande init component de l'interface CLI de la trousse SDK pour créer un fichier JavaScript ou TypeScript avec la structure permettant de travailler avec la trousse SDK Oracle Digital Assistant Node.js pour écrire un composant personnalisé. Le langage que vous avez spécifié lorsque vous avez exécuté la commande init pour créer l'ensemble de composants détermine si un fichier JavaScript ou TypeScript est créé.

Par exemple, pour créer un fichier pour le composant personnalisé, à partir d'une fenêtre de terminal, exécutez la commande CD pour parvenir au dossier de niveau supérieur de l'ensemble et tapez la commande suivante, en remplaçant <component name> par le nom de votre composant :

bots-node-sdk init component <component name> c components

Pour JavaScript, cette commande ajoute <component name>.js à components folder. Pour TypeScript, le fichier est ajouté au dossier src/components. L'argument c indique que le fichier concerne un composant personnalisé.

Il est à noter que le nom du composant ne peut pas dépasser 100 caractères. Vous ne pouvez utiliser que des caractères alphanumériques et des traits de soulignement dans le nom. Vous ne pouvez pas utiliser de tirets. Le nom ne peut pas avoir le préfixe System.. Oracle Digital Assistant ne vous permet pas d'ajouter un service de composants personnalisés avec des noms de composant non valides.

Pour plus d'informations, voir https://github.com/oracle/bots-node-sdk/blob/master/bin/CLI.md.

Ajouter du code aux métadonnées et appeler les fonctions

Votre composant personnalisé doit exporter deux objets :

  • metadata : Cela fournit à la compétence les informations suivantes sur le composant.
    • Nom de composant
    • Propriétés prises en charge
    • Actions de transition prises en charge

    Pour les flux de dialogue basés sur YAML, le composant personnalisé prend en charge les propriétés suivantes par défaut. Ces propriétés ne sont pas disponibles pour les compétences conçues en mode de dialogue visuel.

    • autoNumberPostbackActions : Booléen. Facultative. Lorsqu'elle est réglée à true, les boutons et les options de liste sont numérotés automatiquement. La valeur par défaut est false. Voir Numérotation automatique pour les canaux textuels dans les flux de dialogue YAML.
    • insightsEndConversation : Booléen. Facultative. Lorsqu'elle est réglée à true, la session arrête l'enregistrement de la conversation pour le rapport de données clés. La valeur par défaut est false. Voir Modéliser le flux de dialogue.
    • insightsInclude : Booléen. Facultative. Lorsqu'elle est réglée à true, l'état est inclus dans le rapport de données clés. La valeur par défaut est true. Voir Modéliser le flux de dialogue.
    • translate : Booléen. Facultative. Lorsqu'elle est réglée à true, la traduction automatique est activée pour ce composant. La valeur par défaut est celle de la variable de contexte autotranslation. Voir Services de traduction dans les compétences.
  • invoke : Contient la logique à exécuter. Dans cette méthode, vous pouvez lire et écrire des variables de contexte de compétence, créer des messages de conversation, définir des transitions d'état, effectuer des appels REST, etc. En général, vous utilisez le mot clé async avec cette fonction pour gérer les promesses. La fonction invoke prend l'argument suivant :
    • context, qui nomme la référence à l'objet CustomComponentContext dans la trousse SDK Node.js de Digital Assistant. Cette classe est décrite dans la documentation de la trousse SDK à l'adresse https://oracle.github.io/bots-node-sdk/. Dans les versions antérieures de la trousse SDK, le nom était conversation. Vous pouvez utiliser l'un ou l'autre nom.
    Note

    Si vous utilisez une bibliothèque JavaScript qui ne prend pas en charge les promesses (et n'utilise donc pas le mot clé async), il est également possible d'ajouter un argument done comme rappel que le composant appelle lorsqu'il a terminé le traitement.

Voici un exemple :

'use strict';

module.exports = {

  metadata: {
    name: 'helloWorld',
    properties: {
      human: { required: true, type: 'string' }
    },
    supportedActions: ['weekday', 'weekend']
  },

  invoke: async(context) => {
    // Retrieve the value of the 'human' component property.
    const { human } = context.properties();
    // determine date
    const now = new Date();
    const dayOfWeek = now.toLocaleDateString('en-US', { weekday: 'long' });
    const isWeekend = [0, 6].indexOf(now.getDay()) > -1;
    // Send two messages, and transition based on the day of the week
    context.reply(`Greetings ${human}`)
      .reply(`Today is ${now.toLocaleDateString()}, a ${dayOfWeek}`)
      .transition(isWeekend ? 'weekend' : 'weekday');   
  }
}

Pour en savoir plus et explorer des exemples de code, voir Écriture de composants personnalisés dans la documentation sur la trousse SDK de développement de robots.

Contrôler le flux avec keepTurn et transition

Vous utilisez différentes combinaisons des fonctions de la trousse SDK Bots Node keepTurn et transition pour définir comment le composant personnalisé interagit avec un utilisateur et comment la conversation continue après que le composant retourne le contrôle de flux à la compétence.

  • keepTurn(booléen) indique si la conversation doit passer à un autre état sans inviter d'entrée de l'utilisateur.

    Notez que si vous voulez régler keepTurn à true, vous devez appeler keepTurn après avoir appelé reply, car la reply règle implicitement keepTurn à false.

  • transition(action) fait passer la boîte de dialogue à l'état suivant après l'envoi de toutes les réponses, le cas échéant. L'argument facultatif action nomme l'action (résultat) retournée par le composant.

    Si vous n'appelez pas transition(), la réponse est envoyée, mais la boîte de dialogue conserve l'état et l'entrée d'utilisateur suivante revient à ce composant. En d'autres termes, invoke() est appelé à nouveau.

invoke: async (context) ==> {
   ...
   context.reply(payload);
   context.keepTurn(true);
   context.transition ("success"); 
}

Voici quelques cas d'utilisation courants de keepTurn et transition pour contrôler le flux de dialogue :

Cas d'utilisation Jeu de valeurs pour keepTurn et transition

Un composant personnalisé qui passe à un autre état sans d'abord inviter d'entrée de l'utilisateur.

  1. Le cas échéant, utilisez context.reply(<reply>) pour envoyer une réponse.

  2. Définissez context.keepTurn(true).

  3. Définissez context.transition avec une chaîne supportedActions (par exemple, context.transition("success")) ou sans argument (par exemple, context.transition()).

Par exemple, ce composant personnalisé met à jour une variable avec une liste de valeurs affichée immédiatement par l'état suivant du flux de dialogue.
invoke: async (context) => {
    const listVariableName = context.properties().variableName;
    ...
    // Write list of options to a context variable
    context.variable(listVariableName, list);
   // Navigate to next state without 
   // first prompting for user interaction.
   context.keepTurn(true);
   context.transition();
 }

Un composant personnalisé qui permet à la compétence d'attendre une entrée après le retour du contrôle à la compétence et avant le passage de celle-ci à un autre état.

  1. Le cas échéant, utilisez context.reply(<reply>) pour envoyer une réponse.

  2. Définissez context.keepTurn(false).

  3. Définissez context.transition avec une chaîne supportedActions (context.transition("success")) ou sans argument (context.transition()).

Par exemple :
context.keepTurn(false);
context.transition("success");
Un composant personnalisé qui obtient une entrée de l'utilisateur sans retourner le contrôle de flux à la compétence. Par exemple :
  • Un composant transmet l'entrée utilisateur pour interroger un moteur de recherche dorsal. Si la compétence ne peut contenir qu'un seul résultat, mais que l'interrogation en retourne plusieurs, le composant invite l'utilisateur à filtrer les résultats. Dans ce cas, le composant personnalisé continue de traiter l'entrée de l'utilisateur. Il stocke la conversation jusqu'à ce que le moteur de recherche retourne un résultat unique. Lorsqu'il obtient un seul résultat, le composant appelle context.transition() pour passer à un autre état tel que configuré dans la définition du flux de dialogue.

  • Un composant traite un questionnaire et passe à un autre état suivant uniquement lorsque toutes les questions reçoivent une réponse.

  1. N'appelez pas transition.

  2. Définissez keepTurn(false).

Par exemple, ce composant personnalisé affiche un devis, puis les boutons Yes et No pour demander un autre devis. Il retourne à la compétence lorsque l'utilisateur clique sur No.
  invoke: async (context) => {
    // Perform conversation tasks.
    const tracking_token = "a2VlcHR1cm4gZXhhbXBsZQ==";    
    const quotes = require("./json/Quotes.json");
    const quote = quotes[Math.floor(Math.random() * quotes.length)];
    
    // Check if postback action is issued. If postback action is issued, 
    // check if postback is from this component rendering. This ensures
    // that the component only responds to its own postback actions.     
    if (context.postback() && context.postback().token == tracking_token && context.postback().isNo) {
      context.keepTurn(true);
      context.transition();
    } else {
      // Show the quote of the day.
      context.reply("'" + quote.quote + "'");
      context.reply(" Quote by: " + quote.origin);
      // Create a single message with two buttons to 
      // request another quote or not.
      const mf = context.getMessageFactory();
      const message = mf.createTextMessage('Do you want another quote?')
        .addAction(mf.createPostbackAction('Yes', { isNo: false, token: tracking_token }))
        .addAction(mf.createPostbackAction('No', { isNo: true, token: tracking_token })); 
      context.reply(message);
      // Although reply() automatically sets keepTurn to false, 
      // it's good practice to explicitly set it so that it's
      // easier to see how you intend the component to behave.
      context.keepTurn(false);
    };
  }

Si un composant ne passe pas à un autre état, il doit effectuer le suivi de son propre état, comme le montre l'exemple ci-dessus.

Pour le traitement d'état plus complexe, comme donner à l'utilisateur la possibilité d'annuler si une extraction de données prend trop de temps, vous pouvez créer et utiliser une variable de contexte. Par exemple : context.variable("InternalComponentWaitTime", time). Si vous utilisez une variable de contexte, n'oubliez pas de la réinitialiser ou de la régler à null avant d'appeler context.transition.

Notez que tant que vous n'effectuez pas de transition, toutes les valeurs transmises en tant que propriétés de composant sont disponibles.

L'appel de composant se répète sans entrée de l'utilisateur. Par exemple :

  • Un composant envoie une instruction ping à un service distant pour obtenir le statut d'une commande jusqu'à ce que le statut accepted soit retourné ou que le composant expire. Si le statut accepted n'est pas retourné après le cinquième ping, le composant passe au statut FailedOrder.

  • Le composant personnalisé transfère l'utilisateur à un agent humain. Dans ce cas, l'entrée de l'utilisateur et les réponses sont envoyées à l'agent. Le composant passe à un autre état lorsque l'utilisateur ou l'agent met fin à sa session.

  • N'appelez pas transition.

  • Définissez context.keepTurn(true).

Voici un exemple quelque peu artificiel qui montre comment répéter l'invocation sans attendre l'entrée de l'utilisateur, puis comment effectuer la transition à la fin :
invoke: async (context) => {

  const quotes = require("./json/Quotes.json");
  const quote = quotes[Math.floor(Math.random() * quotes.length)];
  
  // Check if postback action is issued and postback is from this component rendering. 
  // This ensures that the component only responds to its own postback actions.     
  const um = context.getUserMessage()
  if (um instanceof PostbackMessage && um.getPostback() && um.getPostback()['system.state'] === context.getRequest().state && um.getPostback().isNo) {
    context.keepTurn(true);
    context.transition();
  } else {
    // Show the quote of the day.
    context.reply(`'${quote.quote}'`);
    context.reply(`Quote by: ${quote.origin}`);
    // Create a single message with two buttons to request another quote or not.
    let actions = [];

    const mf = context.getMessageFactory();
    const message = mf.createTextMessage('Do you want another quote?')
      .addAction(mf.createPostbackAction('Yes', { isNo: false }))
      .addAction(mf.createPostbackAction('No', { isNo: true }));
    context.reply(message);
    // Although reply() automatically sets keepTurn to false, it's good practice to explicitly set it so that it's
    // easier to see how you intend the component to behave.
    context.keepTurn(false);
  }
}

Accédez au système dorsal

Vous constaterez qu'il existe plusieurs bibliothèques Node.js créées pour faciliter les demandes HTTP et que la liste change fréquemment. Passez en revue les avantages et les inconvénients des bibliothèques actuellement disponibles et choisissez celle qui vous convient le mieux. Nous vous recommandons d'utiliser une bibliothèque qui prend en charge les promesses pour vous permettre de tirer parti de la version async de la méthode invoke, qui a été introduite dans la version 2.5.1, et d'utiliser le mot clé await pour écrire vos appels REST de manière synchrone.

Une option est l'API node fetch pré-installée avec la trousse SDK de développement de robots. Vous trouverez des exemples de code dans la documentation sur la trousse SDK de développement de robots, Accéder au système dorsal à l'aide d'appels REST HTTP.

Utiliser la trousse SDK pour accéder aux données utiles de demande et de réponse

Vous utilisez les méthodes d'instance CustomComponentContext pour obtenir le contexte de l'appel, accéder aux variables et les modifier, et renvoyer les résultats au moteur de dialogue.

Vous trouverez plusieurs exemples de code pour utiliser ces méthodes dans Écriture de composants personnalisés et Messagerie de conversation dans la documentation sur la trousse SDK de développement de robots.

La documentation de référence sur la trousse SDK se trouve à l'adresse https://github.com/oracle/bots-node-sdk.

Composants personnalisés pour les compétences multilingues

Lorsque vous concevez un composant personnalisé, vous devez déterminer si ce composant sera utilisé par une compétence qui prend en charge plusieurs langues.

Si le composant personnalisé doit prendre en charge les compétences multilingues, vous devez savoir si les compétences sont configurées pour la prise en charge linguistique native ou le service de traduction.

Lorsque vous utilisez un service de traduction, vous pouvez traduire le texte de la compétence. Vous disposez des options suivantes :

Pour les compétences linguistiques natives, vous disposez des options suivantes :

  • Transmettez les données à la compétence dans des variables, puis sortez le texte d'un composant de système en transmettant les valeurs des variables à une clé d'ensemble de ressources, comme décrit dans Utiliser un composant de système pour référencer un ensemble de ressources. Avec cette option, le composant personnalisé doit avoir des propriétés de métadonnées pour que la compétence transmette les noms des variables dans lesquelles stocker les données.

  • Utilisez l'ensemble de ressources du composant personnalisé pour rédiger la réponse du composant personnalisé, comme décrit sous Reference Resource Bundles from the Custom Component (Ensembles de ressources de référence du composant personnalisé). Vous utilisez la méthode conversation.translate() pour obtenir la chaîne d'ensemble de ressources à utiliser pour votre appel à context.reply(). Cette option n'est valide que pour les définitions d'ensemble de ressources qui utilisent des paramètres positionnels (numérotés). Il ne fonctionne pas pour les paramètres nommés. Avec cette option, le composant personnalisé doit avoir une propriété de métadonnées pour le nom de la clé d'ensemble de ressources, et les paramètres de la clé d'ensemble de ressources nommée doivent correspondre à ceux utilisés dans l'appel à context.reply().

Voici un exemple d'utilisation de l'ensemble de ressources à partir du composant personnalisé. Dans cet exemple, fmTemplate serait réglé à quelque chose comme ${rb('date.dayOfWeekMessage', 'lundi', '19 juillet 2021')}.

'use strict';

var IntlPolyfill    = require('intl');
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat;

module.exports = {
  metadata: () => ({
    name: 'Date.DayOfWeek',
    properties: {
      rbKey:   { required: true,  type: 'string'    }
    },
    supportedActions: []
  }),
  invoke: (context, done) => {
    const { rbKey } = context.properties();
    if (!rbKey || rbKey.startsWith('${')){
      context.transition();
            done(new Error('The state is missing the rbKey property or it uses an invalid expression to pass the value.'));
    }
    //detect user locale. If not set, define a default
    const locale  = context.getVariable('profile.locale') ? 
      context.getVariable('profile.locale') : 'en-AU';  
    const jsLocale     = locale.replace('_','-');
    //when profile languageTag is set, use it. If not, use profile.locale
    const languageTag = context.getVariable('profile.languageTag')?
                      context.getVariable('profile.languageTag') : jslocale;
   /* =============================================================
      Determine the current date in local format and 
      the day name for the locale
      ============================================================= */
    var now          = new Date();
    var dayTemplate  = new Intl.DateTimeFormat(languageTag,
      { weekday: 'long' });
    var dayOfWeek    = dayTemplate.format(now);
    var dateTemplate = new Intl.DateTimeFormat(languageTag, 
      { year: 'numeric', month: 'long', day: 'numeric'});
    var dateToday    = dateTemplate.format(now);

   /* =============================================================
      Use the context.translate() method to create the ${Freemarker} 
      template that's evaluated when the reply() is flushed to the 
      client.
      ============================================================= */
    const fmTemplate = context.translate(rbKey, dateToday, dayOfWeek );

    context.reply(fmTemplate)
                .transition()
                .logger().info('INFO : Generated FreeMarker => ' 
                + fmTemplate);
    done();  
  }
};

Vérifier le fonctionnement du composant dans les assistants numériques

Un utilisateur peut interrompre le flux d'une conversation avec l'assistant numérique en changeant de sujet. Par exemple, un utilisateur lance un flux pour faire un achat. Il peut l'interrompre pour demander le crédit restant sur une carte-cadeau. Nous appelons cela une incohérence. Pour permettre à l'assistant numérique d'identifier et de gérer les incohérences, appelez la méthode context.invalidInput(payload) lorsque la réponse à un énoncé d'un utilisateur n'est pas comprise dans le contexte du composant.

Dans une conversation numérique, le module d'exécution détermine si une entrée non valide est une incohérence en recherchant des correspondances de réponses dans toutes les compétences. S'il en trouve, le flux est redirigé. Sinon, il affiche le message, s'il est fourni, invite l'utilisateur à effectuer une entrée, puis exécute à nouveau le composant. La nouvelle entrée est transmise au composant dans la propriété text.

Dans une conversation de compétence autonome, le module d'exécution affiche le message, s'il est fourni, invite l'utilisateur à effectuer une entrée, puis exécute à nouveau le composant. La nouvelle entrée est transmise au composant dans la propriété text.

Cet exemple de code appellecontext.invalidInput(payload) chaque fois que l'entrée n'est pas convertie en nombre.

"use strict"
 
module.exports = {
 
    metadata: () => ({
        "name": "AgeChecker",
        "properties": {
            "minAge": { "type": "integer", "required": true }
        },
        "supportedActions": [
            "allow",
            "block",
            "unsupportedPayload"
        ]
    }),
 
    invoke: (context, done) => {
        // Parse a number out of the incoming message
        const text = context.text();
        var age = 0;
        if (text){
          const matches = text.match(/\d+/);
          if (matches) {
              age = matches[0];
          } else {
              context.invalidUserInput("Age input not understood. Please try again");
              done();
              return;
          }
        } else {
          context.transition('unsupportedPayload");
          done();
          return;
        }
 
        context.logger().info('AgeChecker: using age=' + age);
 
        // Set action based on age check
        let minAge = context.properties().minAge || 18;
        context.transition( age >= minAge ? 'allow' : 'block' );
 
        done();
    }
};

Voici un exemple illustrant la façon dont un assistant numérique traite des entrées non valides lors de l'exécution. Pour la première réponse concernant l'âge (twentyfive), aucune correspondance n'est trouvée dans les compétences associées à l'assistant numérique. La conversation affiche donc le message context.invalidUserInput spécifié. Dans la deuxième réponse concernant l'âge (send money), l'assistant numérique trouve une correspondance. Il demande donc s'il doit effectuer un réacheminement vers ce flux.


Une description de components-nonequitur-conversation.png suit
Description de l'illustration components-nonsequitur-conversation.png

Appelez context.invalidInput() ou context.transition(). Si vous appelez les deux opérations, assurez-vous que la variable system.invalidUserInput est toujours définie pour le cas où des messages supplémentaires sont envoyés. Notez également que les composants d'entrée utilisateur (tels que les composants Réponse commune et Résoudre les entités) réinitialisent system.invalidUserInput.

Par exemple, supposons que vous ayez modifié le composant AgeChecker comme présenté ci-dessous et que vous appeliez context.transition() après context.invalidInput().

if (matches) {  age = matches[0]; } else { 
      context.invalidUserInput("Age input not understood. Please try again"); 
      context.transition("invalid"); 
      context.keepTurn(true);
      done();
      return;
}

Dans ce cas, le flux de données doit revenir à askage pour que l'utilisateur reçoive deux messages de sortie – "Age input not understood. Please try again" suivi de "How old are you?". Voici comment cela peut être traité dans un flux de dialogue en mode YAML.

  askage:
    component: "System.Output"
    properties:
      text: "How old are you?"
    transitions:
      next: "checkage"
  checkage:
    component: "AgeChecker"
    properties:
      minAge: 18
    transitions:
      actions:
        allow: "crust"
        block: "underage"
        invalid: "askage"

Exécuter le service de composants dans un environnement de développement

Lors de la phase de développement, vous pouvez démarrer un service local pour exposer l'ensemble de composants personnalisés.

  1. À partir du dossier de niveau supérieur, ouvrez une fenêtre de terminal et exécutez ces commandes pour lancer le service :
    npm install
    npm start
  2. Pour vérifier que le service est en cours d'exécution, entrez l'URL suivante dans un navigateur :
    localhost:3000/components

    Le navigateur affiche les métadonnées du composant.

  3. Si vous avez un accès direct à Internet, vous pouvez accéder à l'environnement de développement à partir d'une compétence :
    1. Installez un tunnel, tel que ngrok ou Localtunnel.
    2. Si vous êtes derrière un mandataire, allez à http://www.whatismyproxy.com/ pour obtenir son adresse IP externe puis, dans la fenêtre de terminal qui servira à démarrer le tunnel, entrez les commandes suivantes :
      export https_proxy=http://<external ip>:80
      export http_proxy=http://<external ip>:80
    3. Démarrez le tunnel et configurez-le pour exposer le port 3000.
    4. Dans Oracle Digital Assistant, allez à l'onglet Components(Composants) de la compétence Icône Components (Composants) et ajoutez un service de composants External (Externe) avec l'URL des métadonnées réglée à https://<tunnel-url>/components.
      Vous pouvez utiliser n'importe quelle valeur pour le nom d'utilisateur et le mot de passe.
Vous pouvez maintenant ajouter des états aux composants du service dans le flux de dialogue et les tester depuis la page Preview (Prévisualiser) de la compétence.