GoogleCloudPlatform
Webhook
chatbot
api.ai
dialogflow

Dialogflowで応答文の一部にwebhookの結果を設定する方法

ボットアドベントカレンダー1日目です。このカレンダーには、チャットボットに限らず、株取引、Wiki更新、仮想世界の様々な場所で活躍するボットを作った/作ろうとしている方のエントリを歓迎します。ボット関連のサービスのちょっとしたネタでも構いません。後半まだまだ空きがありますので、是非。

さて1日目は、Dialogflow(旧api.ai)のwebhook(外部API)連携について書きます。

本記事は、Fulfillmentについてある程度ご存知であることを前提とした記事になっています。そもそもFulfillmentについての日本語情報が少ない中恐縮ですが、ご了承ください。

要は、(認証、)リクエストを受け取り、正常レスポンス異常レスポンスを返すようなWeb APIを、Googleのサーバから見える位置に置いて、DialogflowのFulfillmentメニューでURL(や認証情報)を指定してENABLEDスライドを動かし、利用したいIntentでUse webhookにチェックを入れれば、利用可能になります。

一応公式にチュートリアルがありますが、話を難しくしている感があります。仕様に沿ったAPIを自分で作ってサーバーレス系のクラウドサービスに置く方が簡単かもしれません。ちなみに私はAzure Functionの「HttpTrigger - C#」をF1プランで使っています。Dialogflowのwebhookとして利用できる簡単な関数(run.csx)のサンプルをGistに置きました

やりたいこと

DialogflowでFulfillmentを普通に設定すると、webhookからのレスポンス本文のspeechに書いてある内容がそのまま表示されてしまいます。例えば、以下をwebhookから返すとしましょう。

{"speech":"大吉だよ!"}

ボットは「大吉だよ!」と応答します。

fixedspeech.png

「大吉」の部分は仕方ないにせよ、ボット様の気分(ランダム)によって、多少は表現をアレンジしてみたいものです。しかし、speechに設定する方法だと、webhookから返ってきたものがそのまま応答になります。結局、応答文に関する処理をwebhookに盛り込むことになってしまい、何のためにDialogflowを使っているのかわからなくなってきます。webhookには、外部APIとのパイプ役に徹してもらいたいものです。

そこで思いつくのは、Responseセクションに変数を書いておいたら、そこにwebhookから何か設定してもらえるんじゃないか、ということでしょう。「大吉」だけwebhookに返してもらって、あとはDialogFlowがランダムに文章を選択して返してくれないかなー、という期待です。

want.png

上の画面キャプチャは、「イメージ」です。実際にはこのような設定を行いませんので、ご注意ください。

実現方法

webhookからのレスポンスにfollowupEventを入れて、新しいイベントを起こします。すると、そのイベント名で待ち受けている別のIntentに結果が送られます。そのIntentに、変数を定義しておきます。その変数に、webhookからイベントの引数として送られた内容をアサインします。Responseに変数のプレースホルダを含めた文章を設定しておくことで、プレースホルダの部分が変数の内容(=イベントの引数で受け取った内容)で置換され、ユーザに送り返されます。

flow.png

同じIntentがユーザの発言とイベントの両方を受け付けることはできないため、イベントを受ける専用のIntentが必要となっています。

webhook返却後の処理を行うIntentの作成

新しいIntentを作成します。名前は元のIntentと全然関係ないもので構いませんが、元の名称の末尾に.Responseなどとつけた名前にしておくと、Dialogflow画面上での管理がしやすくなると思います。

User saysは空欄のままとします。Eventsという文字をクリックすると入力欄が開きます。そこに、後でイベント名として使う文字列を設定します。Actionはボットのクライアントから使わない限りは空欄で結構です。

contexts.png

ここでは、unseiという名前の変数を作って、そこに「大吉」などとwebhookで入れてもらうようにするための設定を行います。

val.png

PARAMETER NAMEにはunseiENTITYには@sys.anyVALUEには#イベント名.unseiと入力します。REQUIREDIS LISTはチェックを入れないままで結構です。

そして、Responseの部分に、応答文を入れます。これは「やりたいこと」でお見せしたのとほぼ同じです。「$ + PARAMETER NAMEで入力した文字列」の部分が、webhookの結果で置換されることになります。

スクリーンショット 2017-11-25 0.31.41.png

FulfillmentUse webhookにチェックを入れる必要はありません。この点は、元のIntentと異なりますので、注意してください。

Webhookスクリプト/プログラムの変更

レスポンス本文が、以下のような感じになるように、webhookを修正して保存します。

{  
   "followupEvent":{  
      "name":"LOCAL_WEBHOOK_RECEIVED",
      "data":{  
         "unsei":"大吉"
      }
   }
}

Azure Functionで実装した例をGistに置いておきます

試してみる

それでは、右側のチャット欄でテストしてみましょう。

1.png

2.png

3.png

適当にランダムに返答が来るようになりました。

補足:Use webhook for slot-fillingとは?

Use webhookの隣にUse webhook for slot-fillingというオプションがあります。いかにもこの目的のためのオプションのように見えますし、このオプションを使ったやり方でもできることはあります。しかし、コンテキストが残存してしまって変なことになる可能性が高く、公式フォーラムの議論の中で多くの人がfollowUpEventを使うことを勧めています。このため、本記事ではこのオプションを使わずにfollowUpEventを使う方法を紹介しました。