Search code examples
flutterdartdialogflow-es

Unable to correctly parse Dialogflow fulfillmentMessages


I'm having an issue parsing DialogFlow responses in a Flutter app when BOTH default response and Facebook integration responses are defined.

Setup: DEFAULT response contains a simple custom payload Dialogflow console Response section

Facebook integration response is set of quick replies.

Facebook integration tab

The JSON representation of both the above responses can be examined when the Intent is downloaded, as below.

        "messages": [
    {
      "type": "quick_reply",
      "platform": "facebook",
      "condition": "",
      "title": "What can I help you with today?",
      "replies": [
        "Facebook option 1",
        "Facebook option 2"
      ]
    },
    {
      "type": "custom_payload",
      "condition": "",
      "payload": {
        "replies": [
          "option 1",
          "option 2"
        ],
        "text": "this is some text!"
      }
    }
  ],

In this simple Flutter app, I connect to DialogFlow and send a query that is mapped to the above intent. Since the response to detectIntent() is of type List, I print the length of the List and key/value of each Message in the List.

    var request = Dialogflow.getRequestTextInput(query, "en-US");
var response = await df.detectIntent(request, sessionPath);

List<GoogleCloudDialogflowV2IntentMessage> payloads = response.queryResult.fulfillmentMessages;
debugPrint("Got response length: ${payloads.length}");
debugPrint(response.toString());

GoogleCloudDialogflowV2IntentMessage firstEntry = payloads[0];
Map<String, dynamic> payload0 = firstEntry.payload;
payload0.forEach((key, value) => debugPrint("Key: $key  Value: $value"));

debugPrint("Printing second entry");
GoogleCloudDialogflowV2IntentMessage secondEntry = payloads[1];
Map<String, dynamic> payload1 = secondEntry.payload;
payload1.forEach((key, value) => debugPrint("Key: $key  Value: $value"));

debugPrint("Printing third entry");
GoogleCloudDialogflowV2IntentMessage thirdEntry = payloads[2];
Map<String, dynamic> payload2 = thirdEntry.payload;
payload2.forEach((key, value) => debugPrint("Key: $key  Value: $value"));

Here are the scenarios and my observations for each scenario:

Scenario 1: Slider button for using responses from Default tab as first responses is ENABLED. Observations:

  • Count of responses returned is 3
  • Printing first element of list => key/value of custom payload is printed
  • Printing second element of list => program throws an Unhandled exception(The method 'forEach' was called on null). This makes sense because there is no payload object in the Facebook response (see JSON).

Console output - scenario 1

Scenario 2: Slider button for using responses from Default tab as first responses is DISABLED. Observations:

  • Count of responses returned is 2. Why?
  • The program then throws an Unhandled exception(The method 'forEach' was called on null).

console output - scenario 2

Scenario 3: Delete the Facebook response, so the only response for the intent is the custom payload in Default tab. Observations:

  • Response count is 2.
  • Printing first two elements of the response list returns duplicates, i.e. identical key/value pairs.
  • Attempting to print the third element throws exception(RangeError), which makes sense since array only has 2 elements)

console output - scenario 3

My questions:

  • Why are the lengths/counts different in each scenario? Is there a way to introspect the different response objects to figure out what each is composed of?

  • It appears the order of elements in the response differs, based on whether the slider button is Enabled/Disabled. Why? If enabled (count=3): Element 0 has the custom payload, Element 1 has the Facebook quick reply payload, Element 2 has the custom payload (duplicate). If disabled (count=2): Element 0 has the Facebook quick reply payload, Element 1 has the custom payload.

  • The response list often contains duplicates. Scenario 3 above is one example. Another example is, say for Scenario 1, I query the title (instead of payload). Now all 3 elements are printed, with the first and third elements duplicated. Console output - scenario 1a


Solution

  • Just to be clear, the length that you are counting are the objects inside response.queryResult.fulfillmentMessages.

    Below is the raw printed response.queryResult.fulfillmentMessages for reference of the bulleted answers:

    Got response length:3
    [payload {
      fields {
        key: "replies"
        value {
          list_value {
            values {
              string_value: "option 1"
            }
            values {
              string_value: "option 2"
            }
          }
        }
      }
      fields {
        key: "text"
        value {
          string_value: "this is some text!"
        }
      }
    }
    platform: FACEBOOK
    , quick_replies {
      title: "What can I help you with today?"
      quick_replies: "Facebook option 1"
      quick_replies: "Facebook option 2"
    }
    platform: FACEBOOK
    , payload {
      fields {
        key: "replies"
        value {
          list_value {
            values {
              string_value: "option 1"
            }
            values {
              string_value: "option 2"
            }
          }
        }
      }
      fields {
        key: "text"
        value {
          string_value: "this is some text!"
        }
      }
    }
    ]
    

    Will answer your 3 questions based on the order of the bullets.

    • You can just print the raw response.queryResult.fulfillmentMessages to examine the differences in the total number of objects. In the above example the 3 objects are the ff:

    index[0] will be the payload object of the Default Response

    index[1] will be the quick_replies inside facebook platform

    index[2] will be the payload object inside facebook platform.

    • When you disable the "Use responses from the DEFAULT tab as the first responses." slider button, this means that, from the above example, payload object of the Default Response will be omitted that's why the count of length will be 2 only. Namely, the quick_replies inside facebook platform and the payload object inside facebook platform.

    • The elements are not duplicate. Based your sample screenshot, the first key-value are the payload of the Default Response while the second key-value are the payload of the Facebook Platform. As you can see on my above sample raw output, it has an indicator "platform: FACEBOOK" which means the custom payload response is for facebook platform.