機械翻訳について

カスタム・コンポーネントの実装

カスタム・コンポーネントを実装するには、Oracle Digital Assistant Node.js SDKを使用して、Digital Assistantカスタム・コンポーネント・サービスとインタフェースします。

Digital Assistant埋込みコンテナ、「Oracle Cloud Infrastructure関数」「モバイル・ハブ」バックエンドまたはNode.jsサーバーにデプロイできるカスタム・コンポーネントを実装する方法を次に示します:

  1. 「カスタム・コンポーネントをビルドするためのソフトウェアをインストール」

  2. 「カスタム・コンポーネント・パッケージの作成」

  3. 「カスタム・コンポーネントの作成およびビルド」

ノート:

カスタム・コンポーネント・パッケージを埋込みカスタム・コンポーネント・サービスにデプロイする場合、パッケージを追加する各スキルは個別のサービスとしてカウントされます。 インスタンスに含めることができる埋込みカスタム・コンポーネント・サービスの数に制限があります。 この制限がわからない場合は、「インフラストラクチャ・コンソールでのサービス制限の表示」の説明に従ってembedded-custom-component-service-countを取得するようにサービス管理者に依頼してください。 使用する埋込みコンポーネント・サービスの数を最小限に抑えるために、パッケージごとに複数のコンポーネントをパッケージ化することを検討してください。 この制限を満たした後にコンポーネント・サービスを追加しようとすると、サービスの作成に失敗します。

ステップ1: カスタム・コンポーネントをビルドするためのソフトウェアのインストール

カスタム・コンポーネント・パッケージをビルドするには、Node.js、ノード・パッケージ・マネージャ、およびOracle Digital Assistant Bots Node.js SDKが必要です。

ノート:

Windowsでは、Node.jsでの下位互換性のない変更のためにノード・インストールがバージョン20.12.2以上である場合、Bots Node SDKはWindowsで機能しません。 すでにノード・バージョン20.12.2以上がインストールされている場合は、それをアンインストールしてから、Bots Node SDKが機能するようにバージョン20.12.1またはそれ以前のバージョンをインストールする必要があります。
  1. https://nodejs.orgからNode.jsをまだダウンロードしていない場合は、グローバル・アクセスのためにインストールします。 ノード・パッケージ・マネージャ(npm)は、Node.jsに配布されます。

    Node.jsとnpmがインストールされているかどうかをテストするには、端末ウィンドウを開いて次のコマンドを入力します:

    node –v 
    npm –v
  2. グローバル・アクセス用のOracle Digital AssistantボットNode.js SDKをインストールするには、端末ウィンドウに次のコマンドを入力します:
    npm install -g @oracle/bots-node-sdk

    Macでは、次のsudoコマンドを使用します:

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

    -g (グローバル)オプションを使用する場合、bots-node-sdkコマンドライン・インタフェースに直接アクセスできます。 それ以外の場合は、npx @oracle/bots-node-sdkを使用します。

  3. Oracle Digital AssistantボットNode.js SDKのインストールを確認するには、次のコマンドを入力します:
    bots-node-sdk -v
    コマンドはOracle Digital Assistant Bots Node.js SDKバージョンを印刷する必要があります。

ステップ2: カスタム・コンポーネント・パッケージの作成

プロジェクトを開始するには、SDKのコマンド・ライン・インタフェース(CLI)のbots-node-sdk initコマンドを使用して、コンポーネント構造に必要なファイルおよびディレクトリ構造を作成します。

initコマンドには、JavaScript (デフォルト)またはTypeScriptのどちらを使用するか、初期コンポーネントJavaScriptファイルに名前を付けるかなど、いくつかのオプションがあります。 これらのオプションについては、「CLI開発者ツール」を参照してください。 JavaScriptプロジェクトを起動するための基本的なコマンドを次に示します:

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

このコマンドは、JavaScriptパッケージに対する次のアクションを完了します:

  • 最上位フォルダを作成します。

  • componentsフォルダを作成し、hello.world.jsというサンプル・コンポーネントJavaScriptファイルを追加します。 コンポーネントJavaScriptファイルを配置する場所です。

  • package.jsonファイルを追加します。このファイルでは、main.jsをメイン・エントリ・ポイントとして指定し、@oracle/bots-node-sdkdevDependencyとしてリストします。 パッケージ・ファイルには、一部の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"
      }
    }
  • パッケージ設定をエクスポートして、コンポーネントのロケーションのコンポーネント・フォルダを指すmain.jsファイルを最上位フォルダに追加します。

  • .npmignoreファイルを最上位フォルダに追加します。 このファイルは、コンポーネント・パッケージをエクスポートする際に使用されます。 パッケージから.tgzファイルを除外する必要があります。 たとえば: *.tgz

  • Npmの一部のバージョンでは、package-lock.jsonファイルを作成します。

  • すべてのパッケージ依存性をnode_modulesサブフォルダにインストールします。

ノート:

bots-node-sdk initコマンドを使用してパッケージ・フォルダを作成しない場合は、最上位フォルダに*.tgzエントリを含む.npmignoreファイルが含まれていることを確認します。 たとえば:
*.tgz
spec
service-*

そうしないと、ファイルをTGZファイルにパックするたびに、最上位フォルダにすでに存在するTGZファイルが含まれ、TGZファイルのサイズが2倍になります。

埋込みコンテナにデプロイする場合、パッケージはノード14.17.0と互換性がある必要があります。

ステップ3: カスタム・コンポーネントの作成およびビルド

各カスタム・コンポーネントをパッケージにビルドするステップを次に示します:

  1. コンポーネントJavaScriptファイルを作成します。

  2. metadataファンクションおよびinvokeファンクションにコードを追加します。

  3. バックエンドにアクセスします。

  4. SDKを使用して、リクエスト・ペイロードおよびレスポンス・ペイロードにアクセスします。

  5. コンポーネントがデジタル・アシスタントで機能することを確認します。

コンポーネント・ファイルの作成

SDK CLIのinit componentコマンドを使用して、Oracle Digital Assistant Node.js SDKを操作してカスタム・コンポーネントを書き込むためのフレームワークを備えたJavaScriptまたはTypeScriptファイルを作成します。 initコマンドを実行してコンポーネント・パッケージを作成するときに指定した言語によって、JavaScriptファイルまたはTypeScriptファイルが作成されるかどうかが決まります。

たとえば、カスタム・コンポーネントのファイルを作成するには、ターミナル・ウィンドウからCDをパッケージの最上位フォルダまで作成し、次のコマンドを入力します。<component name>をコンポーネント名で置き換えます:

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

JavaScriptの場合、このコマンドは<component name>.jscomponents folderに追加します。 TypeScriptの場合、ファイルはsrc/componentsフォルダに追加されます。 c引数は、ファイルがカスタム・コンポーネント用であることを示します。

コンポーネント名は100文字を超えることはできません。 名前に使用できるのは、英数字とアンダースコアのみです。 ハイフンは使用できません。 また、System.プレフィクスを持つ名前も使用できません。 Oracle Digital Assistantでは、無効なコンポーネント名を含むカスタム・コンポーネント・サービスを追加することはできません。

詳細は、https://github.com/oracle/bots-node-sdk/blob/master/bin/CLI.mdを参照してください。

メタデータへのコードの追加および関数の起動

カスタム・コンポーネントは、次の2つのオブジェクトをエクスポートする必要があります:

  • metadata: これにより、スキルに次のコンポーネント情報が提供されます。
    • コンポーネント名
    • サポートされるプロパティ
    • サポートされている遷移アクション

    「YAMLベースの場合」ダイアログ・フローでは、カスタム・コンポーネントはデフォルトで次のプロパティをサポートしています。 これらのプロパティは、ビジュアル・ダイアログ・モードで設計されたスキルでは使用できません。

  • invoke: これには実行するロジックが含まれます。 このメソッドでは、スキル・コンテキスト変数の読取りおよび書込み、会話メッセージの作成、状態遷移の設定、RESTコールの作成などを実行できます。 通常は、この関数とともにasyncキーワードを使用して約束を処理します。 invoke関数は、次の引数を取ります:
    • context: Digital Assistant Node.js SDKのCustomComponentContextオブジェクトへの参照を指定します。 このクラスは、SDKのドキュメント(https://oracle.github.io/bots-node-sdk/)で説明されています。 以前のバージョンのSDKでは、名前はconversationでした。 どちらの名前も使用できます。

    ノート:

    Promisesをサポートしていない(したがって、asyncキーワードを使用していない) JavaScriptライブラリを使用している場合は、処理が終了したときにコンポーネントによって起動されるコールバックとしてdone引数を追加することもできます。

次に例を示します。

'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');   
  }
}

さらに学習してコード例を確認するには、Bots Node SDKのドキュメントの「カスタム・コンポーネントの記述」を参照してください。

keepTurnおよび遷移を使用したフローの制御

Bots Node SDKのkeepTurn関数とtransition関数の様々な組合せを使用して、カスタム・コンポーネントがユーザーと対話する方法、およびコンポーネントがフロー制御をスキルに戻した後に会話を続行する方法を定義します。

  • keepTurn(boolean)は、最初にユーザー入力を要求せずに会話を別の状態に遷移するかどうかを指定します。

    keepTurnをtrueに設定する場合、replykeepTurnfalseに暗黙的に設定するため、replyのコール後にkeepTurnをコールする必要があります。

  • transition(action)では、すべての返信(ある場合)が送信された後、ダイアログが次の状態に遷移します。 オプションのaction引数は、コンポーネントが返すアクション(結果)の名前です。

    transition()をコールしない場合、レスポンスは送信されますが、ダイアログは状態のままであり、後続のユーザー入力はこのコンポーネントに戻ります。 つまり、invoke()は再度コールされます。

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

keepTurnおよびtransitionを使用してダイアログ・フローを制御する一般的なユースケースを次に示します:

ユース・ケース keepTurnとtransitionに設定される値

ユーザーに入力を求めるプロンプトを表示せずに別の状態に遷移するカスタム・コンポーネント。

  1. 該当する場合は、context.reply(<reply>)を使用して返信を送信します。

  2. context.keepTurn(true)の設定。

  3. supportedActions文字列(例、context.transition("success")を使用するか、引数なし(context.transition())でcontext.transitionを設定します。

たとえば、このカスタム・コンポーネントは、変数を値のリストで更新し、ダイアログ・フローの次の状態ですぐに表示されるようにします。
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();
 }

コントロールがスキルに戻った後、スキルが別の状態に遷移する前に、スキルが入力を待機できるようにするカスタム・コンポーネント。

  1. 該当する場合は、context.reply(<reply>)を使用して返信を送信します。

  2. context.keepTurn(false)の設定。

  3. supportedActions文字列(context.transition("success")を使用するか、引数なし(context.transition())でcontext.transitionを設定します。

たとえば:
context.keepTurn(false);
context.transition("success");
フロー制御をスキルに戻さずにユーザー入力を取得するカスタム・コンポーネント。 たとえば:
  • コンポーネントは、ユーザー入力を渡してバックエンド検索エンジンに問い合せます。 スキルが単一の結果にのみ対応できるが、問合せで複数のヒットが返される場合、コンポーネントは結果をフィルタ処理するための追加の入力をユーザーに求めます。 この場合、カスタム・コンポーネントはユーザー入力の処理を続行します。つまり、検索エンジンが単一のヒットを返すまで会話を保持します。 単一の結果が得られると、コンポーネントはcontext.transition()をコールして、ダイアログ・フロー定義で定義されている別の状態に移行します。

  • コンポーネントは質問リストを処理し、すべての質問に回答したときにのみ別の次の状態に遷移します。

  1. transitionを呼び出しません。

  2. keepTurn(false)の設定。

たとえば、このカスタム・コンポーネントは見積を出力し、YesおよびNoボタンを表示して別の見積をリクエストします。 ユーザーが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);
    };
  }

コンポーネントが別の状態に遷移しない場合は、前述の例に示すように、独自の状態を追跡する必要があります。

データ取得に時間がかかりすぎる場合に取り消すオプションをユーザーに提供するなど、より複雑な状態処理の場合は、コンテキスト変数を作成して使用できます。 たとえば: context.variable("InternalComponentWaitTime", time) コンテキスト変数を使用する場合は、context.transitionをコールする前に、必ずリセットするかnullに設定してください。

遷移しないかぎり、コンポーネント・プロパティとして渡されるすべての値が使用可能であることに注意してください。

コンポーネントの起動は、ユーザー入力なしで繰り返されます。 たとえば:

  • コンポーネントは、ステータスがacceptedとして返されるか、コンポーネントがタイムアウトするまで、リモート・サービスにオーダーのステータスをpingします。 5番目のping後にacceptedステータスが返されない場合、コンポーネントはfailedOrderステータスで遷移します。

  • カスタム・コンポーネントは、ユーザーをライブ・エージェントに渡します。 この場合、ユーザー入力とレスポンスはエージェントにディスパッチされます。 ユーザーまたはエージェントがセッションを終了すると、コンポーネントは別の状態に遷移します。

  • transitionを呼び出しません。

  • context.keepTurn(true)の設定。

次に、ユーザー入力を待機せずに起動を繰り返す方法と、終了時に遷移する方法を示す、ある程度の矛盾した例を示します:
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);
  }
}

バックエンドへのアクセス

HTTPリクエストを簡単にするために構築されたNode.jsライブラリがいくつかあり、リストは頻繁に変更されます。 現在使用可能なライブラリの長所と短所を確認し、最適な動作を決定する必要があります。 約束をサポートするライブラリを使用して、バージョン2.5.1で導入されたinvokeメソッドのasyncバージョンを利用し、awaitキーワードを使用してRESTコールを同時に記述することをお薦めします。

1つのオプションは、Bots Node SDKで事前インストールされている「ノード・フェッチ」 APIです。 Bots Node SDKドキュメントの「HTTP RESTコールを使用したバックエンドへのアクセス」には、いくつかのコード例が含まれています。

SDKを使用したリクエストおよびレスポンス・ペイロードへのアクセス

CustomComponentContextインスタンス・メソッドを使用して、起動のコンテキストを取得し、変数にアクセスして変更し、結果をダイアログ・エンジンに送り返します。

これらのメソッドの使用については、ボット・ノードSDKのドキュメントで「カスタム・コンポーネントの記述」および「会話メッセージ」にあるいくつかのコード例を参照してください

SDKリファレンス・ドキュメントは、https://github.com/oracle/bots-node-sdkにあります。

多言語スキルのカスタム・コンポーネント

カスタム・コンポーネントを設計するときは、コンポーネントを複数の言語をサポートするスキルで使用するかどうかを考慮する必要があります。

カスタム・コンポーネントが複数言語スキルをサポートする必要がある場合は、ネイティブ言語サポートまたは翻訳サービスにスキルが構成されているかどうかを確認する必要があります。

翻訳サービスを使用すると、スキルからテキストを翻訳できます。 次のオプションがあります。

ネイティブ言語スキルの場合、次のオプションがあります:

  • データを変数内のスキルに戻し、「システム・コンポーネントを使用したリソース・バンドルの参照」で説明されているように、変数の値をリソース・バンドル・キーに渡してシステム・コンポーネントからテキストを出力します。 このオプションでは、データを格納する変数の名前を渡すには、カスタム・コンポーネントにスキルのメタデータ・プロパティが必要です。

  • 「カスタム・コンポーネントからのリソース・バンドルの参照」の説明に従って、カスタム・コンポーネントからのリソース・バンドルを使用してカスタム・コンポーネント応答を構成します。 conversation.translate()メソッドを使用して、context.reply()へのコールに使用するリソース・バンドル文字列を取得します。 このオプションは、位置(番号付き)パラメータを使用するリソース・バンドル定義でのみ有効です。 名前付きパラメータでは使用できません。 このオプションでは、カスタム・コンポーネントにリソース・バンドル・キーの名前のメタデータ・プロパティが必要であり、名前付きリソース・バンドル・キー・パラメータは、context.reply()へのコールで使用されるパラメータと一致する必要があります。

カスタム・コンポーネントからのリソース・バンドルの使用例を次に示します。 この例では、fmTemplate${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();  
  }
};

コンポーネントがデジタル・アシストで動作することを確認

デジタル・アシスタントの会話では、ユーザーが件名を変更することで会話フローを切断できます。 たとえば、ユーザーが購入のためのフローを開始した場合、そのフローが中断され、ギフト・カードのクレジット金額を尋ねられる可能性があります。 このことは、再実行以外にコールします。 デジタル・アシスタントで未シーケンスの動作を識別して処理できるようにするには、ユーザー発話レスポンスがコンポーネントのcontextに理解されていない場合は、context.invalidInput(payload)メソッドを呼び出します。

デジタル会話では、ランタイムはすべてのスキルでレスポンスの一致を検索して、無効な入力が非シーケンスであるかどうかを判断します。 一致するものが見つかると、フローがルート変更されます。 そうでない場合は、メッセージが表示され、入力を求められてから、コンポーネントを再度実行します。 新しい入力は、textプロパティでコンポーネントに渡されます。

スタンドアロン・スキルの会話では、実行時にメッセージが表示され(提供されている場合)、ユーザーに入力を要求してから、コンポーネントを再度実行します。 新しい入力は、textプロパティでコンポーネントに渡されます。

この例のコードは、入力が数値に変換されないときは常にcontext.invalidInput(payload)を呼び出します。

"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();
    }
};

次に、デジタル・アシスタントが実行時に無効な入力を処理する方法の例を示します。 初回のレスポンス(twentyfive)には、デジタル・アシスタントに登録されているスキルに一致するものがないため、会話では指定のcontext.invalidUserInputメッセージが表示されます。 2回目のレスポンス(send money)では、デジタル・アシスタントは一致を検出し、そのフローへのルートを変更する必要があるかどうかを尋ねます。


components-nonsequitur-conversation.pngの説明は以下のとおりです
「図components-nonsequitur-conversation.pngの説明」

context.invalidInput()またはcontext.transition()を呼び出す必要があります。 両方の操作を呼び出す場合は、追加のメッセージが送信された場合でもsystem.invalidUserInput変数が引き続き設定されていることを確認してください。 また、ユーザー入力コンポーネント(共通レスポンス・コンポーネントやエンティティの解決コンポーネントなど)がsystem.invalidUserInputをリセットします。

たとえば、次に示すようにAgeCheckerコンポーネントを変更し、context.invalidInput()のあとにcontext.transition()を呼び出します。

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

この場合、ユーザーが2つの出力メッセージを取得するように、データ・フローをaskageに戻す必要があります。 - "年齢入力が理解されていません。 年齢はいくつですか?"に続けて再試行してください。 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"

開発環境でのコンポーネント・サービスの実行

開発フェーズ中に、ローカル・サービスを起動してカスタム・コンポーネント・パッケージを公開できます。

  1. 最上位レベルのフォルダから、ターミナル・ウィンドウを開いて、次のコマンドを実行してサービスを起動します:
    npm install
    npm start
  2. サービスが実行中であることを確認するには、ブラウザに次のURLを入力します:
    localhost:3000/components

    ブラウザにコンポーネント・メタデータが表示されます。

  3. インターネットに直接アクセスできる場合は、スキルから開発環境にアクセスできます:
    1. ngrokやLocaltunnelなどのトンネルをインストールします。
    2. プロキシの背後である場合は、プロキシの外部IPアドレスを取得するためにhttp://www.whatismyproxy.com/に移動し、トンネルの起動に使用するターミナル・ウィンドウで次のコマンドを入力します:
      export https_proxy=http://<external ip>:80
      export http_proxy=http://<external ip>:80
    3. トンネルを起動して、ポート3000を公開するように構成します。
    4. Oracle Digital Assistantで、スキルのコンポーネント「Components」アイコンタブに移動し、メタデータURLがhttps://<tunnel-url>/componentsに設定された「外部」コンポーネント・サービスを追加します。
      ユーザー名とパスワードには任意の値を使用できます。
これで、サービス・コンポーネントの状態をダイアログ・フローに追加し、スキルの「プレビュー」ページからテストできます。