ボットアドベントカレンダー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":"大吉だよ!"}
ボットは「大吉だよ!」と応答します。
「大吉」の部分は仕方ないにせよ、ボット様の気分(ランダム)によって、多少は表現をアレンジしてみたいものです。しかし、speech
に設定する方法だと、webhookから返ってきたものがそのまま応答になります。結局、応答文に関する処理をwebhookに盛り込むことになってしまい、何のためにDialogflowを使っているのかわからなくなってきます。webhookには、外部APIとのパイプ役に徹してもらいたいものです。
そこで思いつくのは、Responseセクションに変数を書いておいたら、そこにwebhookから何か設定してもらえるんじゃないか、ということでしょう。「大吉」だけwebhookに返してもらって、あとはDialogFlowがランダムに文章を選択して返してくれないかなー、という期待です。
上の画面キャプチャは、「イメージ」です。実際にはこのような設定を行いませんので、ご注意ください。
実現方法
webhookからのレスポンスにfollowupEvent
を入れて、新しいイベントを起こします。すると、そのイベント名で待ち受けている別のIntentに結果が送られます。そのIntentに、変数を定義しておきます。その変数に、webhookからイベントの引数として送られた内容をアサインします。Responseに変数のプレースホルダを含めた文章を設定しておくことで、プレースホルダの部分が変数の内容(=イベントの引数で受け取った内容)で置換され、ユーザに送り返されます。
同じIntentがユーザの発言とイベントの両方を受け付けることはできないため、イベントを受ける専用のIntentが必要となっています。
webhook返却後の処理を行うIntentの作成
新しいIntentを作成します。名前は元のIntentと全然関係ないもので構いませんが、元の名称の末尾に.Response
などとつけた名前にしておくと、Dialogflow画面上での管理がしやすくなると思います。
User says
は空欄のままとします。Events
という文字をクリックすると入力欄が開きます。そこに、後でイベント名として使う文字列を設定します。Action
はボットのクライアントから使わない限りは空欄で結構です。
ここでは、unsei
という名前の変数を作って、そこに「大吉」などとwebhookで入れてもらうようにするための設定を行います。
PARAMETER NAME
にはunsei
、ENTITY
には@sys.any
、VALUE
には#イベント名.unsei
と入力します。REQUIRED
やIS LIST
はチェックを入れないままで結構です。
そして、Response
の部分に、応答文を入れます。これは「やりたいこと」でお見せしたのとほぼ同じです。「$
+ PARAMETER NAME
で入力した文字列」の部分が、webhookの結果で置換されることになります。
Fulfillment
のUse webhook
にチェックを入れる必要はありません。この点は、元のIntentと異なりますので、注意してください。
Webhookスクリプト/プログラムの変更
レスポンス本文が、以下のような感じになるように、webhookを修正して保存します。
{
"followupEvent":{
"name":"LOCAL_WEBHOOK_RECEIVED",
"data":{
"unsei":"大吉"
}
}
}
Azure Functionで実装した例をGistに置いておきます。
試してみる
それでは、右側のチャット欄でテストしてみましょう。
適当にランダムに返答が来るようになりました。
補足:Use webhook for slot-filling
とは?
Use webhook
の隣にUse webhook for slot-filling
というオプションがあります。いかにもこの目的のためのオプションのように見えますし、このオプションを使ったやり方でもできることはあります。しかし、コンテキストが残存してしまって変なことになる可能性が高く、公式フォーラムの議論の中で多くの人がfollowUpEvent
を使うことを勧めています。このため、本記事ではこのオプションを使わずにfollowUpEvent
を使う方法を紹介しました。