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
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écifiemain.js
comme point d'entrée principal et liste@oracle/bots-node-sdk
commedevDependency
. 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.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
.
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 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 estfalse
. 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 estfalse
. 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 esttrue
. 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 contexteautotranslation
. 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 fonctioninvoke
prend l'argument suivant :context
, qui nomme la référence à l'objetCustomComponentContext
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 étaitconversation
. 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 argumentdone
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 appelerkeepTurn
après avoir appeléreply
, car lareply
rè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 facultatifaction
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. |
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
Yes et No pour demander un autre devis. Il retourne à la compétence lorsque l'utilisateur clique sur No .
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é
translate
de 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.