こんにちは、yutaです。

Dialogflow記事も第4回目となりました。

・第1回:【Dialogflowの使い方】Twitterを連繋させる手順

・第2回:【Dialogflowの使い方】機能の説明と基本的な応答の作り方

・第3回:【DialogFlowの使い方】聞き返しの作り方

今回はFulfillmentについて超基礎編を書きます。

自動応答してくれるボットが真に役に立つようにするには、やっぱり今必要な情報を返してくれるようにあることですよね。

しかし、前回までのEntityとIntentを使ったやり取りだけでは、ボットが外部サイトから必要な情報を取得して返事を返すというようなことはできません。

それを実現しようとするとFulfillmentの利用が必要です。

そこで今回はFulfillment利用の超基礎編ということで、外部からデータを取得するところはまた次回として、とにかくFulfillmentを使って返事をすることを実践していきたいと思います。

具体的には次のような会話を作ります。

[char no="1" char="辰生"]明日の○○の天気は?[/char] [char no="2" char="ロボ"]○○は晴れです(雨です)。[/char]

○○は「京都」と「大阪」固定で、京都の場合は晴れ、大阪の場合は雨とします。

天気の判定に外部サイトの情報を使えるようになればホンモノですね。

では早速

Fulfillmentを使って返事をする

前提条件

まずはここから説明するスクリプトが問題なく動くための前提条件をお話します。

DialogflowのAPIバージョンが2.0であること。

何をいきなり…バージョンの違いなんてあるの?と思われるかも知れませんが、実はあります。

2018年4月17日にAPIバージョン2.0が正式にリリースされました

これにより、もしそれ以前からDialogflowをご利用であるならば、旧APIを利用したままである可能性があります。

その場合は、APIの利用設定を2.0にしていただかなければ説明するスクリプトが正常に動作しません。

理由はAPI1.0と2.0でスクリプトの書き方が大きく変わったからです

※この記事では1.0での書き方については説明していません。

APIの2.0への変更手順は次の通りです。

  1. 左のペインの歯車マークをクリック
  2. 設定「General」の「API VERSION」の項の「V2 API」を選択
  3. 設定を保存
画像はクリックすると大きくなります。

Entityの作成

まずはEntityです。

ここでは、地域だけ作りましょう。

Entity名は「weather_place」とします。

晴れの返事用の京都、雨の返事用の大阪、そして、どちらでもない兵庫を用意しておきましょう。

Intentの作成

続いていて、天気の質問をするIntentを作成します。

Intent名は「Hows_the_weather_of」とします。

地域の入力がない場合は、聞き返すようにしてみましょう。

聞き返しについては詳しくは第3回をご参照ください。

・第3回:【DialogFlowの使い方】聞き返しの作り方

Fulfillmentの作成

いよいよFulfillmentの作成に入ります。

今回は、Cloud Functions for Firebaseを利用するため、Inline Editorを利用してスクリプトを書きます。

Fulfillmentの利用方法には次の2種類あります。

  1. 自前の外部サーバに設置したスクリプトを呼び出して実行する方法
  2. Inline Editorを利用してDialogflow上で直接記述する方法

今回は2の手段を利用します。

自前で環境を用意しなくても利用できるって本当にありがたいですね。

では、実際にコードを書いていきましょう。

まずはFulfillmentのInline Editorを有効にします。

いよいよスクリプトの記述です。

具体的には次のスクリプトを記載します(コピペしていただいて問題ありません)。

'use strict';
const functions = require('firebase-functions');
const { dialogflow } = require('actions-on-google');
const app = dialogflow();

app.intent('Hows_the_weather_of', (conv,{weather_place}) => {
    if (weather_place == '京都'){
        conv.ask('京都は晴れです');
    }else if (weather_place == '大阪'){
        conv.ask('大阪は雨です');
    }else{
        conv.ask('京都と大阪以外わかりません');
    }
});

exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

何を書いているの?という方は、次のように覚えてくださいね。

まず、次の箇所はおまじないです。

'use strict';
const functions = require('firebase-functions');
const { dialogflow } = require('actions-on-google');
const app = dialogflow();

最後の1行も同様です。

exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);

次の箇所が重要になります。

app.intent('Hows_the_weather_of', (conv,{weather_place}) => {
    if (weather_place == '京都'){
        conv.ask('京都は晴れです');
    }else if (weather_place == '大阪'){
        conv.ask('大阪は雨です');
    }else{
        conv.ask('京都と大阪以外わかりません');
    }
});

これは「app[アプリの].intent[インテントが]('インテント名')[指定したインテント名の時],(conv[会話],{Entity名[指定したエンティティを渡して]})=>{}[{}内を実行します]」と書いてあると読んでください。

もし、手順1,2で指定したIntentとEntityの名称が例の通りでない場合は'Hows_the_weather_of'

weather_placeの部分を自分のIntentとEntityの名称に直してください。

weather_placeにはIntentで解析されたEntity「weather_place」の情報がそのまま入っています。

すなわち「京都の天気は?」と聞いたとするとweather_placeは「京都」です。

それが「京都」か「大阪」かそれ以外でconv.ask[会話での返答]の内容を変更しています。

InlineEditorに入力する内容は以上になります。

今回はweather_placeの文字列を条件分岐に使っていますが、例えばこの場所の情報をお天気サイトに引き渡して帰ってきた情報を返答するようにできれば、立派に役に立つボットが出来上がりますね。

IntentのFulfillment利用を有効化する

Fulfillmentの実装ができたらIntentにもどって、対象IntentがFulfillmentを利用できるようにしましょう。

Intent「Hows_the_weather_of」の下部のFulfillmentで「Enable webhook call for this intent」を有効にして保存してください。

以上で完了です。

テストしてみましょう。

テストの実施

まずはウィンドウ右側のTry it now で京都の天気を聞いてみましょう。

すると・・・

あれ?

回答は・・・

実は、Fulfillmentによる回答はこの画面には反映されません。

Try it now下部の「Diagnostic info」ボタンをクリックしてください。

最初に表示される「RAW API RESPONSE」の下部の「webhookStatus」を確認しましょう。

「Webhook execution successful」と出ていたら成功です。

Google Assistantでテスト

さて、正しく動作することはわかりましたが、やっぱり自分が用意した回答を返してほしいですよね。

Try it nowの入力欄のすぐ下にある「See how it works in Google Assistant」のリンクをクリックしてください。

別ウィンドウで「Actions on Google」のSimulatorが立ち上がります。

Simulatorはまず「テスト用アプリにつないで」と入力することでテストが開始できるので、それから天気を聞いてみましょう。

いかがでしょうか?

音声をONにすると返答の声を聴くこともできますよ。

テスト用アプリが起動しない場合

アカウントによっては「テスト用アプリにつないで」を入力してもすぐにテスト用アプリから退出してしまいテストができないケースがあるようです。

調査したところによると、Googleアカウントの「Active Control(アクティビティ管理)」で次の3つを有効にすると使えるようになるようです。

・Web & App Activity(ウェブとアプリのアクティビティ)
・Device Information(端末情報)
・Voice & Audio Activity(音声アクティビティ)

関連リンクにアクティビティ管理を掲載します。

上記3つを有効にして、再チャレンジしてみてください。

【2018/09/11 追記】

Fulfillmentの結果をWeb Demoで確認したい

Google Assistantで動くのはわかったけれども、Fulfillmentによる回答をWeb Demoに返したいそういう場合もあるかと思います。

そんな時はconv.ask();で回答を返している部分を次のように書き換えてみてください。

conv.json(
    JSON.stringify({
        "fulfillmentText": "京都は晴れです。"
    })
);

詳しいことはまだ勉強中で、正確な説明ができないことを先に謝らせていただきます。

どうもconv.ask();はGoogle Assistantで使えるような高級な返答しか返すことができません。

これは、Try it nowで試した結果のRAW API RESPONSEを見るとわかります。

"queryResult": {
    "queryText": "大阪の天気は?",
    "parameters": {
      "weather_place": "大阪"
    },
    "allRequiredParamsPresent": true,
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            "" //★返答が空
          ]
        }
      }
    ],
    "webhookPayload": {
      "google": {
        "userStorage": "{\"data\":{}}",
        "richResponse": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "大阪は雨です" //★ここにしか返答がない
              }
            }
          ]
        },
        "expectUserResponse": true
      }
    },

対して、先に示したconv.json();でFulfillmentTextを渡した場合のRAW API RESPONSEは次の通りになります。

"queryResult": {
    "queryText": "京都の天気は?",
    "parameters": {
      "weather_place": "京都"
    },
    "allRequiredParamsPresent": true,
    "fulfillmentText": "京都は晴れです。", //★ 単純なメッセージが返っている
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            "京都は晴れです。" //★ 単純なメッセージが返っている
          ]
        }
      }
    ],

この状態であるとWeb Demoでも回答を得ることができます。

以上になります!

関連リンク

Googleアカウント アクティビティ管理

・第1回:【Dialogflowの使い方】Twitterを連繋させる手順

・第2回:【Dialogflowの使い方】機能の説明と基本的な応答の作り方

・第3回:【DialogFlowの使い方】聞き返しの作り方