Actions on Google Node.js クライアント ライブラリ(Dialogflow)を使用してフルフィルメントを構築する

JavaScript でフルフィルメント Webhook を作成する場合は、Actions on Google プラットフォームにアクセスしてやり取りするために Actions on Google Node.js クライアント ライブラリを使用することをおすすめします。

概要

Node.js クライアント ライブラリは Actions on Google 用のフルフィルメント ライブラリであり、次の機能を提供します。

  • テキストやリッチなマルチメディア レスポンスなど、Actions on Google のすべての機能をサポート 。
  • Conversation HTTP / JSON Webhook API をラップする、JavaScript の慣用的な抽象レイヤを提供します。
  • フルフィルメントと Actions on Google プラットフォーム間の低レベルの通信情報を処理します。
  • 次のような使い慣れたパッケージ管理ツールでインストール可能 npm または yarn
  • サーバーレス コンピューティング プラットフォームにフルフィルメント Webhook を簡単にデプロイできる Cloud Functions for Firebase など AWS Lambda など。また、クラウド サービス プロバイダや自分で管理する自己ホスト環境でフルフィルメント Webhook をホストすることもできます。
  • Node.js v6.0.0 以降と互換性があります。

クライアント ライブラリは、 Dialogflow の Actions on Google への統合 Actions SDK を使用します。

クライアント ライブラリを使用するための詳細なコードサンプルを見るには、サンプルページをご覧ください。

API リファレンスを見る

API リファレンスは、Actions on Google Node.js クライアント ライブラリの GitHub ページでホストされています。

また、クライアント ライブラリ コードをダウンロードしたディレクトリから次のコマンドを実行することで、リファレンスのローカルコピーを生成することもできます。

yarn docs

生成されたドキュメントには、クライアント ライブラリ コードをダウンロードしたディレクトリの docs フォルダからアクセスできます。

仕組みを理解する

クライアント ライブラリを使用する前に、Actions on Google からフルフィルメントに送信されたユーザー リクエストを処理するためにフルフィルメント Webhook がクライアント ライブラリをどのように使用するかを理解しておくことをおすすめします。

JavaScript でフルフィルメント Webhook を作成する場合は、作成したコードを Google の Cloud Functions for Firebase や AWS Lambda などのサーバーレス コンピューティング環境にデプロイしてホストできます。また、Express ウェブ フレームワークを使用することで、追加作業なしでコードを自分でホストすることもできます。

ランタイム環境内において、フルフィルメント Webhook はクライアント ライブラリの関数を呼び出してユーザー リクエストを処理し、ユーザーへの出力となるレスポンスを Actions on Google に送り返します。

フルフィルメント Webhook がクライアント ライブラリを使用して処理する主なタスクを以下に簡単にまとめます。

図 1. Node.js クライアント ライブラリのアーキテクチャの概要
<ph type="x-smartling-placeholder">
    </ph>
  1. ユーザーからのリクエストの受信: ユーザーが Google アシスタントに質問すると、 Actions on Google プラットフォームが、HTTP リクエストをフルフィルメント Webhook に送信します。リクエスト 含まれる JSON ペイロードには、インテントと、 ユーザー入力のテキスト、ユーザーのデバイスのサーフェス機能。 JSON ペイロード コンテンツのその他の例については、 Dialogflow Webhook の形式 会話 Webhook 形式 ご覧ください。
  2. フレームワークの呼び出し形式の検出: サポートされているフレームワークの場合、クライアント ライブラリはフレームワークの呼び出し形式を自動的に検出し(たとえば、リクエストの送信元が Express ウェブ フレームワークか、AWS Lambda かを検出する)、Actions on Google プラットフォームとの通信をシームレスに処理することができます。
  3. サービス ハンドラ処理: クライアント ライブラリでは、Dialogflow と Actions SDK 用の Conversation HTTP / JSON Webhook API がサービス関数として表されています。フルフィルメント Webhook は適切なサービスを使用して、 グローバル app インスタンスを作成します。app インスタンスは HTTP リクエストのハンドラとして機能するとともに、サービスの具体的なプロトコルを理解しています。
  4. 会話処理: クライアント ライブラリでは、会話ごとの情報が、app インスタンスに関連付けられた Conversation オブジェクトとして表されています。フルフィルメント Webhook では、Conversation オブジェクトを使用して次のことを行えます。 複数の会話にまたがる保存データや状態情報の取得、レスポンスの送信 マイクを閉じてください。
  5. ミドルウェア処理: クライアント ライブラリを使用して独自の会話サービス ミドルウェアを作成できます。これはデベロッパーが定義する関数で構成され、クライアント ライブラリによってインテント ハンドラが呼び出される前に自動的に実行されます。フルフィルメント Webhook はこのミドルウェアを使用して、Conversation オブジェクトにプロパティやヘルパークラスを追加できます。
  6. インテント ハンドラ処理: クライアント ライブラリを使用して、フルフィルメント Webhook によって認識されるインテント用のハンドラを定義できます。Dialogflow では、 クライアント ライブラリがリクエストを適切なインテント ハンドラに Dialogflow コンソール。Actions SDK の場合は、送信された intent プロパティに基づいてルーティングされます。 Actions on Google のツールです。
  7. ユーザーへのレスポンスの送信: レスポンスを作成するために、フルフィルメント Webhook が Conversation#ask() 関数を呼び出します。ask() 関数は、次のように設定します。 レスポンスを段階的に作成できます。レスポンスは、JSON ペイロードを含む HTTP リクエストにシリアル化されて Actions on Google に送信されます。close() 関数は ask() 関数と同じように動作しますが、会話を閉じる点が異なります。

ローカル開発環境の設定

フルフィルメント Webhook を実装する前に、必ずクライアント ライブラリを最初にインストールしてください。

クライアント ライブラリをインストールする

クライアント ライブラリをローカルの開発環境にインストールする最も簡単な方法は、npmyarn などのパッケージ マネージャーを使用することです。

インストールするには、ターミナルから次のいずれかのコマンドを実行します。

  • npm を使用する場合: npm install actions-on-google
  • yarn を使用する場合: yarn add actions-on-google

プロジェクト フォルダを準備する

フルフィルメント Webhook をデプロイする場所(Google の Cloud Functions)に応じて、 (自己ホスト型 Express など)を使用する場合は、 特定のプロジェクト フォルダ構造を使用して、ファイルを保存します。

たとえば、Cloud Functions for Firebase を使用している場合、 必要なプロジェクト フォルダを作成してから、 Node.js と Firebase CLI を設定 し、 Firebase for Cloud Functions を初期化します。Cloud Functions for Firebase の場合、通常は /functions/index.js ファイルでフルフィルメント Webhook を作成します。

app インスタンスを作成する

Actions on Google では、リクエストとレスポンスのやり取りに特定のメッセージ形式を使用する フルフィルメント Webhook を使用します。これは、会話型モデルを構築しているかどうかによって異なります。 Dialogflow または Actions SDK を使用したアクション スマートホーム アクションの作成などです。

これらの異なるリクエスト / レスポンス プロトコルを表すために、クライアント ライブラリには次の 3 つのサービス関数が用意されています。

会話 Webhook プロトコルは Dialogflow と Actions SDK の両方の会話サービスによって使用されますが、メッセージのラップ方法はそれぞれ異なります。

サービスを使用して app インスタンスを作成します。app インスタンスは、 グローバルな状態とフルフィルメントのロジックを サービス固有のプロトコルを使用できます。

app インスタンスのプロパティを設定し、そのメソッドを呼び出すことで、 フルフィルメント Webhook の動作を指示します。また、app インスタンスはサーバーレス コンピューティング環境(Cloud Functions for Firebase など)に簡単に接続できます。これにより、JavaScript 関数を HTTP リクエストのハンドラとして使用できます。

フルフィルメント Webhook で app インスタンスを作成する手順は次のとおりです。

  1. require() 関数を呼び出して「actions-on-google」をインポートするモジュールと 必要なサービスを読み込みます。たとえば、次のスニペットは、 dialogflow サービスと、レスポンスの作成に使用される一部の要素を読み込む場合があります。 dialogflow という名前の定数に代入します。

    // Import the service function and various response classes
    const {
      dialogflow,
      actionssdk,
      Image,
      Table,
      Carousel,
    } = require('actions-on-google');

    ここで、actions-on-google は、プロジェクト フォルダの package.json ファイルで指定された依存関係を指します(例については、こちらのサンプルの package.json ファイルをご覧ください)。

    app インスタンスを取得するときに、必要に応じてクラスを指定できます。 リッチ レスポンス ヘルパー インテント、使用するその他の Actions on Google 機能が含まれています。対象: 読み込み可能な有効なクラスの完全なリストについては、 会話レスポンス およびヘルパー インテント 説明します。

  2. 読み込んだサービスを呼び出して app インスタンスを作成します。たとえば、

    const app = dialogflow();
    です。

  3. 初期化時に app インスタンスを構成するには、 options オブジェクトを、サービスを呼び出す際の最初の引数として指定します。(参照: DialogflowOptions をご覧ください)。 たとえば、次のスニペットは、JSON ファイルから未加工の JSON ペイロードを { debug: true } フラグを設定して、ユーザー リクエストやレスポンスに対応します。

const app = dialogflow({
  debug: true
});

イベントのハンドラを設定する

アクションとのユーザー インタラクションのライフサイクル中にクライアント ライブラリによって作成された Actions on Google 関連のイベントを処理するには、クライアント ライブラリを使用して、ユーザー リクエストを処理してレスポンスを返すハンドラを作成します。

クライアント ライブラリが認識する以下の主な種類のイベントについて、そのハンドラとして機能する関数を作成できます。

  • インテント イベント: インテントは、ユーザーが特定の機能を要求したときに Actions on Google がフルフィルメントに送信する一意の識別子です。Dialogflow を使用している場合、これは Dialogflow がユーザークエリを Dialogflow エージェント内のインテントと照合する処理に対応します。
  • エラーイベント: JavaScript またはクライアント ライブラリのエラーが発生すると、 app インスタンスの catch 関数を使用して、エラー例外を処理できます。 適切に分類します単一の catch 関数を実装して、 処理すべきエラーが表示されます
  • フォールバック イベント: フォールバック イベントは、Actions on Google が認識できないクエリをユーザーが送信したときに発生します。app を使用できます。 インスタンスの fallback 関数を呼び出して、汎用のフォールバック ハンドラを登録し、 受信フルフィルメントに一致するインテント ハンドラがない場合はトリガーされる リクエストできます。単一の fallback 関数を実装して、 使用します。Dialogflow は他のどのインテントとも一致しない場合に特定のフォールバック インテントをトリガーすることができます。Dialogflow を使用している場合、そのフォールバック インテントに対応するインテント ハンドラを作成する必要があります。

ユーザーがアクションにリクエストを送信するたびに、app インスタンスは Conversation その会話セッションを表すオブジェクトです。このオブジェクトへのアクセスには、 インテント ハンドラ関数で渡される conv 変数名を 渡します。通常は、ハンドラ内で conv オブジェクトを使用してユーザーにレスポンスを送信します。

ユーザークエリにパラメータを含め、アクションでそのパラメータを抽出してレスポンスを絞り込むこともできます。

インテントのハンドラを設定する

インテントのハンドラを設定するには、appintent() 関数を呼び出します。 構成されますたとえば、Dialogflow を使用している場合は、 DialogflowApp#intent() 使用します。引数にインテント名を指定し、ハンドラ関数を提供します。

Dialogflow を使用している場合、エージェント内のすべてのインテントに対してハンドラを設定する必要はありません。その代わりに、Dialogflow に組み込まれたレスポンス ハンドラを利用して、独自のハンドラ関数を実装せずに自動的にインテントを処理できます。たとえば、デフォルトのウェルカム インテントは、この方法で Dialogflow に処理を委任できます。

次の例は、「greeting」インテントと「bye」インテントのインテント ハンドラを示します。匿名ハンドラ関数は conv 引数を受け取って情報を返します。 conv.ask() 関数を使用して、ユーザーにシンプルな文字列レスポンスを返します。

app.intent('Default Welcome Intent', (conv) => {
  conv.ask('How are you?');
});

app.intent('bye', (conv) => {
  conv.close('See you later!');
});

close() 関数は ask() と類似していますが、 会話は終了します。

インテントのハンドラを作成する方法の詳細については、インテント ハンドラを作成するをご覧ください。

エラーイベントのハンドラを設定する

エラーのハンドラを設定するには、app インスタンスの catch() 関数を呼び出します。(たとえば、Dialogflow を使用している場合は、 DialogflowApp#catch() function.)

次の例は、シンプルな catch エラーハンドラで、エラーを シンプルな文字列レスポンスを返して、ユーザーにプロンプトを表示します。 conv.ask() 関数を実行します。

app.catch((conv, error) => {
  console.error(error);
  conv.ask('I encountered a glitch. Can you say that again?');
});

フォールバック イベントのハンドラを設定する

対応するインテントがない場合に汎用的なフォールバック ハンドラを フルフィルメントのリクエストを受信したら、次の fallback() 関数を呼び出します。 app インスタンス。(たとえば、Dialogflow を使用している場合は、DialogflowApp#fallback() 関数がこれに該当します)。

次の例は、簡単なフォールバック ハンドラとして単純な conv.ask() 関数を使用してユーザーにプロンプトを表示する文字列レスポンス:

app.fallback((conv) => {
  conv.ask(`I couldn't understand. Can you say that again?`);
});

インテント ハンドラを作成する

このセクションでは、クライアント ライブラリを使用してインテント ハンドラを実装するときの一般的なユースケースを取り上げます。クライアント ライブラリが 詳細は「インテント ハンドラ処理」を参照してください。セクション 仕組みを理解する

パラメータとコンテキストにアクセスする

Dialogflow を使用する場合は、 パラメータコンテキストを使用して、 会話フローを制御します。

パラメータは、重要な単語、フレーズ、またはユーザークエリの値を捕捉するのに役立ちます。Dialogflow は実行時にユーザークエリから対応するパラメータを抽出します。フルフィルメント Webhook でこれらのパラメータの値を処理して、ユーザーにどのように応答するかを決定できます。

ユーザーがアクションにリクエストを送信するたびに、DialogflowApp インスタンス parameters を作成します。 Dialogflow がそこから抽出したパラメータ値を表す リクエストできます。このオブジェクトには params 変数名を介してアクセスします。

次のコードは、name プロパティにアクセスする方法を ユーザーがリクエストを送信すると、params オブジェクトが作成されます。

app.intent('Default Welcome Intent', (conv, params) => {
  conv.ask(`How are you, ${params.name}?`);
});

同じことを行う別のスニペットを次に示します。中かっこ ({})JavaScript の分解を実行 parameters オブジェクトから name プロパティを取得し、ローカル変数として variable:

app.intent('Default Welcome Intent', (conv, {name}) => {
  conv.ask(`How are you, ${name}?`);
});

次のスニペットでは、パラメータ名は full-name ですが、 非構造化され、name というローカル変数に代入されます。

app.intent('Default Welcome Intent', (conv, {'full-name': name}) => {
  conv.ask(`How are you, ${name}?`);
});

コンテキストは Dialogflow の高度な機能です。コンテキストを使用すると、会話の状態、フロー、分岐を管理できます。クライアント ライブラリでは、 DialogflowConversation#contexts 渡されます。次のスニペットは、コンテキストをプログラムで設定する方法を示しています。 コンテキスト オブジェクトを取得する方法を以下に示します。

app.intent('intent1', (conv) => {
  const lifespan = 5;
  const contextParameters = {
    color: 'red',
  };
  conv.contexts.set('context1', lifespan, contextParameters);
  // ...
  conv.ask('...');
});

app.intent('intent2', (conv) => {
  const context1 = conv.contexts.get('context1');
  const contextParameters = context1.parameters;
  // ...
  conv.ask('...');
});

app.intent('intent3', (conv) => {
  conv.contexts.delete('context1');
  // ...
  conv.ask('...');
});

ヘルパー インテントの結果にアクセスする

便宜上、クライアント ライブラリには、 ヘルパー インテント クラス 一般的な種類のユーザーデータがラップされます。これらの さまざまな Actions on Google の結果を表すクラスが含まれる ヘルパー インテント。ヘルパー インテントは、会話を続けるためにユーザーからの入力が必要な場合に、「ユーザーに入力を求める」部分の処理を Google アシスタントに任せるときに使用します。

例: 確認ヘルパーの結果

確認ヘルパー インテントを使用すると、 ユーザーにはい/いいえの確認を求め、結果を得る。 次のスニペットは、Webhook がレスポンスをどのようにカスタマイズするかを示しています。 確認ヘルパー インテントから返された結果に対して行われます。1 つの より完全な例については、 Confirmation クラスのリファレンス ドキュメントをご覧ください。

// Create Dialogflow intent with `actions_intent_CONFIRMATION` event
app.intent('get_confirmation', (conv, input, confirmation) => {
  if (confirmation) {
    conv.close(`Great! I'm glad you want to do it!`);
  } else {
    conv.close(`That's okay. Let's not do it now.`);
  }
});

次のスニペットは、フルフィルメント Webhook がレスポンスをカスタマイズする方法を示しています。 基づいてユーザー入力に基づいて カルーセル。カルーセルコンポーネントを使用すると ユーザーが選択できるオプションがアクションに表示されます。詳細については、 完全な例については、Carousel をご覧ください。 クラスのリファレンス ドキュメントをご覧ください。

app.intent('carousel', (conv) => {
  conv.ask('Which of these looks good?');
  conv.ask(new Carousel({
    items: {
      car: {
        title: 'Car',
        description: 'A four wheel vehicle',
        synonyms: ['automobile', 'vehicle'],
      },
      plane: {
        title: 'Plane',
        description: 'A flying machine',
        synonyms: ['aeroplane', 'jet'],
      }
    }
  }));
});

// Create Dialogflow intent with `actions_intent_OPTION` event
app.intent('get_carousel_option', (conv, input, option) => {
  if (option === 'one') {
    conv.close(`Number one is a great choice!`);
  } else {
    conv.close(`Number ${option} is a great choice!`);
  }
});

会話レスポンス オブジェクトを構成する

クライアント ライブラリには、 会話レスポンス クラス リッチ レスポンスや、アクションから送信できるマルチメディア要素を表します。 通常、これらのレスポンスや要素は、ユーザーがコンテンツを送信する必要がない場合に、 会話を続けることができます。

例: 画像

次のスニペットは、フルフィルメント Webhook が Image 自動的に BasicCard レスポンスに添付されます。 使用できます。

app.intent('Default Welcome Intent', (conv) => {
  conv.ask('Hi, how is it going?');
  conv.ask(`Here's a picture of a cat`);
  conv.ask(new Image({
    url: '/web/fundamentals/accessibility/semantics-builtin/imgs/160204193356-01-cat-500.jpg',
    alt: 'A cat',
  }));
});

非同期関数呼び出しを行う

Actions on Google Node.js クライアント ライブラリは、非同期プログラミング用に設計されています。インテント ハンドラは、フルフィルメント Webhook がレスポンスの生成を完了したときに解決される Promise を返すことができます。

次のスニペットは、フルフィルメント Webhook が「greeting」インテントを受け取った場合に非同期関数呼び出しを行い、Promise オブジェクトが返されてからメッセージで応答する方法を示します。このスニペットでは、外部 API 呼び出しの Promise が解決されて初めて、フルフィルメント Webhook から会話レスポンスが返されることが Promise によって保証されます。

この例では、天気データを取得するために実在しない API を使用しています。

/**
 * Make an external API call to get weather data.
 * @return {Promise<string>}
 */
const forecast = () => {
  // ...
};

app.intent('Default Welcome Intent', (conv) => {
  return forecast().then((weather) => {
    conv.ask('How are you?');
    conv.ask(`Today's weather is ${weather}.`);
  });
});

次の合理化されたコード スニペットも結果は同じですが、ECMA 2017(Node.js バージョン 8)で導入された async await 機能を使用しています。用途 Cloud Functions for Firebase で使用する場合は、必ず 正しいバージョンの firebase-tools 正しい構成になっている必要があります

app.intent('Default Welcome Intent', async (conv) => {
  const weather = await forecast();
  conv.ask('How are you?');
  conv.ask(`Today's weather is ${weather}.`);
});

会話データを保存する

このクライアント ライブラリを使用すると、フルフィルメント Webhook で 会話のデータ保存を 使用できます。データ ストレージに使用できる主なオブジェクトは次のとおりです。

次のスニペットは、フルフィルメント Webhook が 定義した任意のプロパティ(someProperty)を作成し、 Conversation#user.storage 渡されます。より詳細な例については、 Conversation#user.storage クラスのリファレンス ドキュメントをご覧ください。

app.intent('Default Welcome Intent', (conv) => {
  conv.user.storage.someProperty = 'someValue';
  conv.ask('...');
});

Conversation#user を使用できます。 オブジェクトを使用して、文字列識別子と文字列 ID を含む、ユーザーに関する情報 保護します。conv.user.name.displayconv.user.email では conv.ask(new Permission) をリクエストする必要があります。 Google ログインの場合はそれぞれ NAME と conv.ask(new SignIn) です。

const {Permission} = require('actions-on-google');
app.intent('Default Welcome Intent', (conv) => {
  if (conv.user.last.seen) {
    conv.ask('Welcome back! How are you?');
  } else {
    conv.ask('Nice to meet you! How are you doing?');
  }
});

app.intent('permission', (conv) => {
  conv.ask(new Permission({
    context: 'To greet you personally',
    permissions: 'NAME',
  }));
});

// Create Dialogflow intent with `actions_intent_PERMISSION` event
app.intent('get_permission', (conv, input, granted) => {
  if (granted) {
    conv.close(`Hi ${conv.user.name.display}!`);
  } else {
    // User did not grant permission
    conv.close(`Hello!`);
  }
});

ミドルウェアによるスケーリング

ミドルウェアを介してクライアント ライブラリを拡張できます。

ミドルウェア層はデベロッパーが定義する関数で構成され、クライアント ライブラリによってインテント ハンドラが呼び出される前に自動的に実行されます。ミドルウェア レイヤを使用すると、Conversation を変更できます。 機能を追加します。

Dialogflow サービスと Actions SDK サービスが app.middleware() 関数を公開する これにより、Conversation にプロパティまたはヘルパークラスを追加できます。 構成されます

次のスニペットは、ミドルウェアの使用方法の例を示します。

class Helper {
  constructor(conv) {
    this.conv = conv;
  }

  func1() {
    this.conv.ask(`What's up?`);
  }
}

app.middleware((conv) => {
  conv.helper = new Helper(conv);
});

app.intent('Default Welcome Intent', (conv) => {
  conv.helper.func1();
});

アプリをエクスポートする

ウェブ フレームワークまたはサーバーレス コンピューティング プラットフォーム用のフルフィルメント Webhook を公開するには、次の手順を行います。 app オブジェクトを一般公開されている Webhook としてエクスポートする必要があります。クライアント ライブラリは、難しい設定なしに、さまざまな環境へのデプロイをサポートしています。

次のスニペットは、各種ランタイム内で app をエクスポートする方法を示します。

例: Cloud Functions for Firebase

const functions = require('firebase-functions');
// ... app code here
exports.fulfillment = functions.https.onRequest(app);

例: Dialogflow インライン エディタ

const functions = require('firebase-functions');

// ... app code here

// Exported function name must be 'dialogflowFirebaseFulfillment'
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

例: 自己ホスト型 Express サーバー(単純)

const express = require('express');
const bodyParser = require('body-parser');  

// ... app code here

express().use(bodyParser.json(), app).listen(3000);

例: 自己ホスト型 Express サーバー(複数のルート)

const express = require('express');
const bodyParser = require('body-parser');

// ... app code here

const expressApp = express().use(bodyParser.json());

expressApp.post('/fulfillment', app);

expressApp.listen(3000);

例: AWS Lambda API ゲートウェイ

// ... app code here

exports.fulfillment = app;