Google chat custom cards using dialogflow fulfilment webhook - dialogflow-es

I am trying to integrate DialogFlow bot with Hangouts Chat (for G Suite). I have enabled the integration on DialogFlow and the basic intents are working fine.
In order to perform backend operations using fulfillment, I have created a firebase cloud function and added this as the webhook URL on DialogFlow fulfillment page.
I have written the cloud function code to identify the intent, and to generate the Webhook response format for a simple text response. This is working, and I am seeing the firestore data being modified in response to the intent.
However for a more complicated intent, I wish to use more of the dynamic card based response that Chat offers. In order to achieve this, I have looked at the documentation for dialogflow card response.
I saw this following code at https://cloud.google.com/dialogflow/docs/integrations/hangouts. When I paste this into the dialogflow intent editor UI under hangouts custom payload (after disabling webhook integration), it works
{
"hangouts": {
"header": {
"title": "Pizza Bot Customer Support",
"subtitle": "pizzabot#example.com",
"imageUrl": "..."
},
"sections": [{
"widgets": [{
"keyValue": {
"icon": "TRAIN",
"topLabel": "Order No.",
"content": "12345"
}
},
{
"keyValue": {
"topLabel": "Status",
"content": "In Delivery"
}
}]
},
{
"header": "Location",
"widgets": [{
"image": {
"imageUrl": "https://dummyimage.com/600x400/000/fff"
}
}]
},
{
"header": "Buttons - i could leave the header out",
"widgets": [{
"buttons": [{
"textButton": {
"text": "OPEN ORDER",
"onClick": {
"openLink": {
"url": "https://example.com/orders/..."
}
}
}
}]
}]
}]
}
}
This is exactly what I need, but I need this response from the webhook. I'm not getting the correct response format to map between the two.
When I try to integrate the same code with the webhook, I am not getting any reply on hangouts chat. When I check the history section on dialogflow UI, here is the response structure as mentioned in Raw interaction log
{
"queryText": "<redacted>",
"parameters": {},
"intent": {
"id": "<redacted>",
"displayName": "<redacted>",
"priority": 500000,
"webhookState": "WEBHOOK_STATE_ENABLED"
},
"intentDetectionConfidence": 1,
"diagnosticInfo": {
"webhook_latency_ms": 284
},
"languageCode": "en",
"slotfillingMetadata": {
"allRequiredParamsPresent": true
},
"id": "<redacted>",
"sessionId": "<redacted>",
"timestamp": "2020-07-30T12:05:29.094Z",
"source": "agent",
"webhookStatus": {
"webhookUsed": true,
"webhookPayload": {
"hangouts": {
"header": {
"subtitle": "pizzabot#example.com",
"title": "Pizza Bot Customer Support",
"imageUrl": "..."
},
"sections": [
{
"widgets": [
{
"keyValue": {
"content": "12345",
"topLabel": "Order No.",
"icon": "TRAIN"
}
},
{
"keyValue": {
"topLabel": "Status",
"content": "In Delivery"
}
}
]
},
{
"widgets": [
{
"image": {
"imageUrl": "https://dummyimage.com/600x400/000/fff"
}
}
],
"header": "Location"
},
{
"widgets": [
{
"buttons": [
{
"textButton": {
"text": "OPEN ORDER",
"onClick": {
"openLink": {
"url": "https://example.com/orders/..."
}
}
}
}
]
}
],
"header": "Buttons - i could leave the header out"
}
]
}
},
"webhookStatus": {
"message": "Webhook execution successful"
}
},
"agentEnvironmentId": {
"agentId": "<redacted>",
"cloudProjectId": "<redacted>"
}
}
I also found this link on chat docs which explains how to show an interactive card based UI https://developers.google.com/hangouts/chat/how-tos/cards-onclick. However I'm not able to understand how to integrate the same with the webhook.
UPDATE
I have followed a tutorial at https://www.leeboonstra.com/Bots/custom-payloads-rich-cards-dialogflow/ and was able to get the card response to show up using the sample code they mention. It is using this deprecated library (https://github.com/dialogflow/dialogflow-fulfillment-nodejs). Here is the code for that to work,
let payload = new Payload("hangouts", json, {
rawPayload: true,
sendAsMessage: true,
});
agent.add(payload);
Here the json variable should be the previous JSON structure I have mentioned. So now, I'm able to map to the correct response format using the deprecated API. However, I'm not able to get the button to send the right response to the back end. Here is the buttons field that I modified from the previous json,
"buttons": [
{
"textButton": {
"text": "Click Me",
"onClick": {
"action": {
"actionMethodName": "snooze",
"parameters": [
{
"key": "time",
"value": "1 day"
},
{
"key": "id",
"value": "123456"
}
]
}
}
}
}
]

As far as I know, responding to a Google Chat (formerly Hangouts Chat) button isn't possible when using the direct Dialogflow integration.
The problem is that the button response can be sent one of two ways:
An event will be sent back to the bot code indicating the click.
Using the onClick.openLink.url property, as most of your test show.
This will take the person clicking it to the URL in question. But once there, you're taken out of the bot flow.
However, the documentation for the Hangouts Chat integration with Dialogflow doesn't provide any information about how this event is passed to Dialogflow, and the last time I tested it - it isn't.
You can write your own integration using Google Chat's API on something like Cloud Functions or Apps Script and have your script call Dialogflow's Detect Intent API to determine what Intent would be triggered by the user (and determine replies or call the webhook for additional processing). Under this scheme, you can choose how to handle the onClick event. Making your own integration also provides you a way to do Incoming Webhooks, which isn't possible when using the Dialogflow integration.

Related

Accumulating response parameters in Dialogflow conversation and then making a web-hook request by combining all parameters

I am making a basic travel chatbot using Dialogflow. Suppose that I get the boarding location in one response, landing location in 2nd response and the date of travel in third response from bot. Now I want to accumulate all three parameters and make a custom webhook response to some flight API. What's the correct way to do this?
Currently what I've done is increase the life span of each of the context to 15(max conversation length possible let's say) and then extract the parameters from outputContexts parameter from json. The json response has been attached below.
Another use case can be getting city and date in 2 follow up conversations and then making a combined web-hook response to fetch weather forecast.
{
"responseId": "some id",
"queryResult": {
"queryText": "London",
"action": "get_flights",
"parameters": {
"geo-city1": "London"
},
"allRequiredParamsPresent": true,
"fulfillmentText": "Here is a webhook response.",
"fulfillmentMessages": [
{
"text": {
"text": [
"Here is a webhook response."
]
}
}
],
"outputContexts": [
{
"name": "projects/project name/agent/sessions/some id/contexts/awaiting_flight_boolean",
"lifespanCount": 13,
"parameters": {
"date-time": "2020-11-14T12:00:00+05:30",
"geo-city1.original": "London",
"geo-city1": "London",
"date-time.original": "2 days from now"
}
},
{
"name": "projects/project name/agent/sessions/some id/contexts/await_landing_city",
"lifespanCount": 11,
"parameters": {
"geo-city1.original": "London",
"date-time.original": "2 days from now",
"BotName": "",
"from.original": "Dubai",
"date-time": "2020-11-14T12:00:00+05:30",
"geo-city1": "London",
"BotName.original": "",
"from": "Dubai"
}
},
{
"name": "projects/project name/agent/sessions/some id/contexts/awaiting_date_of_travel",
"lifespanCount": 12,
"parameters": {
"geo-city1": "London",
"from": "Dubai",
"geo-city1.original": "London",
"from.original": "Dubai",
"date-time.original": "2 days from now",
"date-time": "2020-11-14T12:00:00+05:30"
}
},
{
"name": "projects/project name/agent/sessions/some id/contexts/awaiting_boarding_location",
"lifespanCount": 14,
"parameters": {
"geo-city1": "London",
"geo-city1.original": "London"
}
}
],
"intent": {
"name": "projects/project name/agent/intents/some id",
"displayName": "BoardingTheFlight"
},
"intentDetectionConfidence": 1,
"languageCode": "en"
}
}
I am unable to come up with a better soultion as I am new to dialogflow. Can someone tell the correct/easier way to do this?
As you are new to the Dialogflow, I would like to recommend you Understand fulfillment by integrating Dialogflow with Calendar codelab, where you will be able to see the correct process of setting up fulfillment.
Your solution seems to be correct, additionally you can check this tutorial which is similar to your scenario.
Dialogflow also has some examples of requests and replies on Github.

Assistant sends fulfillment request in conversation webhook format instead of Dialogflow webook format

I tried to build the Dialogflow fulfillment with Java SDK and integrates the agent with Google Assistant.
However, when I try it on simulator, sometimes I got the webhook request in Conversation webhook format instead of Dialogflow webhook format, often happens when I touch input in suggestion chips.
What's the reason behind that? Why my fulfillment backend aren't getting the Dialogflow webhook format instead? Any settings I could have done on the Actions console or Dialogflow? Or shall I make a new request to Dialogflow agent when I receive the conversation webook request?
Request from Assistant:
{
"user": {
...
},
"conversation": {
...
},
"inputs": [
{
"intent": "actions.intent.TEXT",
"rawInputs": [
{
"inputType": "TOUCH",
"query": "瑜伽"
}
],
"arguments": [
{
"name": "text",
"rawText": "瑜伽",
"textValue": "瑜伽"
}
]
}
],
"surface": {
...
},
"isInSandbox": true,
"requestType": "SIMULATOR"
}

Dialogflow Fulfillment responses doesnt seems to work with richresponses(Basic Card) and OutputContext or Follow-up Event

I am trying to setup a bot using dialogflow/webhook. my webhook returns the response for basic text message along with contextoutputs(esp. I am interested in parameters passed from webhooks). This works. But when i use the Basic card response of V2 along with outputcontext, Actions-on-google simulator says, "My test app isn't responding right now. Try again soon." But this works, if i remove outputcontext from the response. Please help
Steps Worked:
1. DialogFlow Testing
Basic Message (FulfillmentText) and contextoutput works fine
Card and contextOutput - not working
Card and followupEvent - Works
2. Actions on Google
Basic Message (FulfillmentText) and contextoutput works fine
Card and contextOutput - not working
Card and followupEvent - not working
Attached the response
{
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "This is sample Response"
}
},
{
"basicCard": {
"title": "testbot",
"formattedText": "This is sample Response",
"image": {
"url": "example.com/image.png",
"accessibilityText": "samplebot"
},
"buttons": [
{
"title": "example",
"openUrlAction": {
"url": "http://example.com"
}
}
]
}
}
]
}
}
},
"outputContexts": [{
"name": "projects/<projectid>/agent/sessions/<sessionid>/contexts/<contextname>",
"lifespanCount": 1,
"parameters": {
"param1": "123",
"param2": "456"
}
}]
}```
I assume you've used the sample code in your action. However, unless you changed the url fields, your action can not find the imageUrl and openUrlAction.
If you change url fields with actual(not "http://example.com") links, your app will respond properly.
Also make sure you've added necessary classes.
e.g.
const { dialogflow, BasicCard, Image, Button } = require('actions-on-google');

Webhook call failed. Error: Failed to parse webhook JSON response: Cannot find field: messages in message google.cloud.dialogflow.v2.Intent.Message

I built a bot using Dialogflow and connected it to a local webhook (now accessing it through ngrok). I am able to receive the response from Dialogflow but I am unable to replay to it. I followed the JSON structure as shown here - Test response from webhook. But I am getting the following error in Dialogflow.
Webhook call failed. Error: Failed to parse webhook JSON response:
Cannot find field: messages in message
google.cloud.dialogflow.v2.Intent.Message.
Following is the reply that I sent to Dialogflow -
{
"messages":[
{
"speech":"Text response",
"type":0
}
]
}
Please tell me what should be the exact format of the reply that I should send to Dialogflow.
From v1 to v2, the response object almost change completely. For just simple text, you can use like:
{
"fulfillmentText": "Text response",
"fulfillmentMessages": [
{
"text": {
"text": ["Text response"]
}
}
],
"source": "<Text response>"
}
I faced same issue,resolved using below json on dialogflow :
I made a simple node program which accepts a post response and returns json of the format accepted by Dialogflow.You may send your request in any way you like. check on Fulfillment status tab :
The field messageswas renamed/refactored to fulfillmentMessages - "can not find" means that it is not a property in the definition.
This is some comparable result accepted by v2:
{
"fulfillmentText": "response text",
"fulfillmentMessages": [{"simpleResponses": {"simpleResponses": [ {
"textToSpeech": "response text",
"displayText": "response text"
}]}}]
}
Messages alone is not sufficient. Refer to Dialogflow V2 webhook fulfillment documentation for complete list of parameters expected and format of JSON.
Are you sure you are using V2 of the DialogFlow APIs?
Use the Webhook Playground to Get the appropriate response for either the Dialogflow API or the Actions SDK which is depricated but still works. There is also the yet newer and different API for the Google Actions Builder/SDK framework as per :
DiaglowFlow JSON Response:
{
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Webhook worked.",
"displayText": "Webhook worked."
}
}
]
}
}
}
}
Actions SDK Response:
{
"expectUserResponse": true,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Webhook worked.",
"displayText": "Webhook worked."
}
}
]
}
},
"possibleIntents": [
{
"intent": "actions.intent.TEXT"
}
]
}
]
}
Action Builder/SDK. Note that the session id needs to be returned.
{
"session": {
"id": "example_session_id",
"params": {}
},
"prompt": {
"override": false,
"firstSimple": {
"speech": "Hello World.",
"text": ""
}
},
"scene": {
"name": "SceneName",
"slots": {},
"next": {
"name": "actions.scene.END_CONVERSATION"
}
}
}

Fulfillment response for Dialog flow

Just started with the DialogFlow building an app. I have hosted a service in Java on cloud (not using the firebase). Basically, I receive the data from the agent and send the response back as Json. For simple query its working as expected. Like if I say "My name is X", the service will respond as "Hello X" and it will be played on the Response. The JSON response is sent as
{speech: "Hello X", type:"0"}
Now, I want to fetch the user location, so I want to ask the user the permission to access the location. I have a separate intent that does not have any training_Phrases. It has an Event actions_intent_PERMISSION.
I am sending the following response
{
"conversationToken": "[\"_actions_on_google_\"]",
"expectUserResponse": true,
"expectedInputs": [
{
"inputPrompt": {
"richInitialPrompt": {
"items": [
{
"simpleResponse": {
"textToSpeech": "PLACEHOLDER_FOR_PERMISSION"
}
}
]
}
},
"possibleIntents": [
{
"intent": "actions.intent.PERMISSION",
"inputValueData": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"optContext": "To locate you",
"permissions": [
"NAME"
]
}
}
],
"speechBiasingHints": [
"$geo_city",
"$event_category",
"$event_date"
]
}
],
"responseMetadata": {
"status": {},
"queryMatchInfo": {
"queryMatched": true,
"intent": "1ec64dc5-a6f4-44f6-8483-633b8638c729"
}
}
}
But I am getting the response as 400 Bad request. Is there anything that I am doing wrong here or am I missing any thing?
There are three issues.
The first is that the actions_intent_PERMISSION event is sent in response to a permission request. So this should not be the intent that triggers the request.
Second, you're asking for the users name, but not their location. You want either the DEVICE_COARSE_LOCATION or DEVICE_PRECISE_LOCATION.
The third, and much bigger, issue is that the JSON you're sending is the format used by the Action SDK. Since you're using Dialogflow, you'll be using a different response format which is the basic Dialogflow response, plus Actions on Google specific content in the data.google JSON property.
Your response should look something more like this:
{
"data": {
"google": {
"expectUserResponse": true,
"systemIntent": {
"intent": "actions.intent.PERMISSION",
"data": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"optContext": "To locate you",
"permissions": [
"NAME",
"DEVICE_PRECISE_LOCATION"
]
}
}
}
}
}
Dialogflow also has some other examples of requests and replies that should help for the other parts of your conversation.

Resources