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 :
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.
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.
É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 componentset 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écifiemain.jscomme point d'entrée principal et liste@oracle/bots-node-sdkcommedevDependency. Par ailleurs, le fichier de l'ensemble pointe vers les scriptsbots-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.jsau 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 .npmignoreau dossier de niveau supérieur. Ce fichier sert à l'exportation de l'ensemble de composants. Il doit exclure les fichiers.tgzde 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.
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é
Voici les étapes permettant de créer chaque composant personnalisé de votre ensemble :
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 componentsPour 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é- asyncavec cette fonction pour gérer les promesses. La fonction- invokeprend l'argument suivant :- context, qui nomme la référence à l'objet- CustomComponentContextdans 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- donecomme 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 appelerkeepTurnaprès avoir appeléreply, car lareplyrègle implicitementkeepTurnà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 facultatifactionnomme 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. | 
 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.  | 
| 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. | 
 Par exemple :  | 
| Un composant personnalisé qui obtient une entrée de l'utilisateur sans retourner le contrôle de flux à la compétence. Par exemple :
                                        
 | 
 Par exemple, ce composant personnalisé affiche un devis, puis les boutons  YesetNopour demander un autre devis. Il retourne à la compétence lorsque l'utilisateur clique surNo.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 :  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 : 
 | 
 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 :  | 
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 :
- 
Réglez la propriété translateà Vrai dans l'état du composant personnalisé pour traduire la réponse du composant, comme décrit dans Envoyer des réponses directement au service de traduction.
- 
Envoyez des données brutes à la compétence dans des variables et utilisez les valeurs des variables dans un composant système qui compose la sortie. Réglez la propriété translatede ce composant à Vrai. Voir Utiliser un composant système pour transmettre le message au service de traduction.
- 
Envoyez des données brutes à la compétence dans des variables et utilisez les valeurs des variables dans un composant système qui utilise la clé d'ensemble de ressources pour la langue. Voir Utiliser un composant de système pour référencer un ensemble de ressources. 
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.
                     

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.
 et ajoutez un service de composants
 et ajoutez un service de composants