Dialogflow のチュートリアルが間違ってた話


はじめに

Dialogflow とは Google が提供している自然言語による対話をビルドするツールです。前々から試したいと思っていたので、今回チュートリアルを実装してみました。ところが Basic Fulfillment and Conversation Setup というパートを実装しているとき、チュートリアル通りに実装しているにも関わらずエラーが発生しました。

エラー内容

エラーが発生したのは上述のチュートリアルの最初の部分

Then create an index.js file in the project directory you just created, with the following code:

/*
* HTTP Cloud Function.
*
* @param {Object} req Cloud Function request context.
* @param {Object} res Cloud Function response context.
*/
exports.helloHttp = function helloHttp (req, res) {
  response = "This is a sample response from your webhook!" //Default response from the webhook to show it's working


  res.setHeader('Content-Type', 'application/json'); //Requires application/json MIME type
  res.send(JSON.stringify({ "speech": response, "displayText": response 
  //"speech" is the spoken version of the response, "displayText" is the visual version
  }));
};

というコードです。Dialogflow の agent からの問い合わせに対し、決め打ちのレスポンスを返すだけの単純なスクリプトです。しかしこれを実装し、Dialogflow のテストを行うと、こんな JSON が返ってきます(responseID など固有の値は * に置き換えています)。

{
  "responseId": "**********",
  "queryResult": {
    "queryText": "東京の天気は",
    "parameters": {
      "geo-city": "東京",
      "date": ""
    },
    "allRequiredParamsPresent": true,
    "fulfillmentText": "すみません、天気は分かりません",
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            "すみません、天気は分かりません"
          ]
        }
      }
    ],
    "outputContexts": [
      {
        "name": "**********",
        "lifespanCount": 5,
        "parameters": {
          "geo-city": "東京",
          "date.original": "",
          "date": "",
          "geo-city.original": "東京"
        }
      }
    ],
    "intent": {
      "name": "**********",
      "displayName": "AskWeatherIntent"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {
      "webhook_latency_ms": 324
    },
    "languageCode": "ja"
  },
  "webhookStatus": {
    "code": 3,
    "message": "Webhook call failed. Error: Failed to parse webhook JSON response: Cannot find field: speech in message google.cloud.dialogflow.v2.WebhookResponse."
  }
}

???なぜチュートリアル通りの実装なのにこんなことになるのか、JSON は返ってきているので関数自体は動いているはず。。。

解決策

調べたところ、以下のような記事が見つかりました。

https://stackoverflow.com/questions/48211405/what-json-response-format-to-use-for-v2beta1-fulfillment-webhook?rq=1
https://productforums.google.com/forum/#!topic/dialogflow/zWLIMnQIOP0

どうやら Dialogflow のバージョン違いにより、チュートリアルのようなレスポンスは無効なようです。正しい実装は以下のようになります。

exports.weatherWebhook = function weatherWebhook (req, res) {
  response = "This is a sample response from your webhook!" //Default response from the webhook to show it's working


  res.setHeader('Content-Type', 'application/json'); //Requires application/json MIME type
  res.send(JSON.stringify({
    "fulfillmentText": response,
    }
  ));
};

この関数をデプロイしてテストすると、無事以下のような JSON が返ってきます。

{
  "responseId": "**********",
  "queryResult": {
    "queryText": "東京の天気は",
    "parameters": {
      "date": "",
      "geo-city": "東京"
    },
    "allRequiredParamsPresent": true,
    "fulfillmentText": "This is a sample response from your webhook!",
    "fulfillmentMessages": [
      {
        "text": {
          "text": [
            "This is a sample response from your webhook!"
          ]
        }
      }
    ],
    "outputContexts": [
      {
        "name": "**********",
        "lifespanCount": 5,
        "parameters": {
          "date.original": "",
          "date": "",
          "geo-city.original": "東京",
          "geo-city": "東京"
        }
      }
    ],
    "intent": {
      "name": "**********",
      "displayName": "AskWeatherIntent"
    },
    "intentDetectionConfidence": 1,
    "diagnosticInfo": {
      "webhook_latency_ms": 329
    },
    "languageCode": "ja"
  },
  "webhookStatus": {
    "message": "Webhook execution successful"
  }
}

無事サンプルを動かすことができました。

まとめ

こういうチュートリアルで詰まると混乱するので、現行のバージョンに合わせて修正してもらいたいものです。まあプログラマならちゃんとドキュメントを読め、ということかもしれませんが。。。