DialogflowのWebhookでGoogle AssistantにBasic Cardのレスポンスを返す


Google Assistantでは応答メッセージだけを返すSimple Responses以外に、スマホの画面向けに画像やURLのリンクを付けた応答メッセージ返すRich Responsesという種類のレスポンスがあります。

詳細は公式ドキュメントを参照。
Responses  |  Actions on Google  |  Google Developers

Basic Cardの場合、このように応答メッセージに加えてサイトの情報を表示してリンク先に誘導することができます。

DialogflowのWebhookでこのような応答を作る場合、大きく2種類の手段があります。

  • Firebaseで用意されているNodeのライブラリを使う
  • 自前でJsonのレスポンスを作って返す

今回は(Firebaseを使わなかったので)後者の手段を選びたかったのですが、Dialogflowのドキュメントにはあまり説明が書かれておらず少し苦労したのでまとめます。

Fulfillment  |  Dialogflow

Simple Responsesの場合は以下のように speechdisplayText にメッセージを入れて返すだけです。

response.setHeader("Content-Type", "application/json")
response.send(JSON.stringify({'speech':"これはテストです",'displayText':"これはテストです"})

しかし、Rich Responsesのほうは上記Dialogflowのドキュメントによると書式付きメッセージということになるのでおそらく data にJsonオブジェクトを作って返してやる必要がありますが、あまり説明がありません。DialogflowはSlackやFaebookとも連携できる仕組みなのでそれぞれのサービスに合わせるということだとは思いますが、フォーラムでもうまくいかないということで議論されているようです。

Google Assistant rich message responses - Integrations - Dialogflow (API.AI) Forums

このフォーラムの内容を参考に以下の記述でBasic Cardを作ることができました。上記で紹介した Action on Googleの公式ドキュメント のBasic Cardのところで書かれているサンプルコードを当てはめると以下のようになります。

 response.setHeader("Content-Type", "application/json")
  response.send(
    JSON.stringify({
      "speech": "This is a simple response for a carousel",
      "data": {
        "google": {
          "expectUserResponse": true,
          "richResponse": {
            "items": [
              {
                "simpleResponse": {
                  "textToSpeech": "This is a simple response for a carousel"
                }
              },
              {
                "basicCard": {
                  "title": "Math & prime numbers",
                  "formattedText": "42 is an even composite number. It\n    is composed of three distinct prime numbers multiplied together. It\n    has a total of eight divisors. 42 is an abundant number, because the\n    sum of its proper divisors 54 is greater than itself. To count from\n    1 to 42 would take you about twenty-one…",
                  "image": {
                    "url": "https://example.google.com/42.png",
                    "accessibilityText": "Image alternate text"
                  },
                  "buttons": [
                    {
                      "title": "Read more",
                      "openUrlAction": {
                        "url": "https://example.google.com/mathandprimes"
                      }
                    }
                  ]
                }
              }
            ],
            "suggestions": []
          }
        },
        "possibleIntents": [
          {
            "intent": "actions.intent.TEXT"
          }
        ]
      }
    })
  );

Simple Responsesの場合とは違い、 displayText は指定せず、 data の中に google.richResponse.items という配列を作り、その中に displayText 相当の
simpleResponse を作り、 basicCard を追加します。 List Selector などの他の種類のレスポンスも同じように実現できると思われます(試してませんが)。

フォーラムに書かれている このコメント を参考にしました。