I have written webhook functions in the inline editor.
I get the deadline exceeded error intermittently.
All webhooks which failed with deadline exceeded error has webhook_latency_ms : 4992ms
In Dialogflow documentation (https://cloud.google.com/dialogflow/docs/fulfillment-how) it's mentioned that default timeout is 5sec, as per this my webhook should not throw this error because it's within 5sec.
The webhook has a very simple code that will take no more than 20-30ms.
Most of the time, the same function has webhook_latency_ms: less than 50ms.
What are the factors that could contribute to increased latency?
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function testHandler(agent) {
let pendingHabits = agent.getContext('pendinghabits').parameters.habits;
let message = "Ok, let me know when you complete these habits:";
for (let i = 0; i < pendingHabits.length; i++) {
message = message + "\n" + pendingHabits[i];
}
let payload = {
type: 'message',
isPositive: false,
messages: [{ type: 0, text: message }]
};
agent.add(new Payload(agent.UNSPECIFIED, payload));
}})
You are missing your handler call, as i can see the code you have provided,
const functions = require('firebase-functions');
const {WebhookClient, Card, Suggestion} = require('dialogflow-fulfillment');
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((req, res) => {
const agent = new WebhookClient({ req, res });
function intentHandler(agent) {
agent.add('This message is from Dialogflow\'s Cloud Functions for Firebase editor!');
agent.add(new Card({
title: 'Title: this is a card title',
imageUrl: 'https://developers.google.com/actions/assistant.png',
text: 'This is the body text of a card. You can even use line\n breaks and emoji! 💁',
buttonText: 'This is a button',
buttonUrl: 'https://assistant.google.com/'
})
);
agent.add(new Suggestion('Quick Reply'));
agent.add(new Suggestion('Suggestion'));
}
agent.handleRequest(intentHandler);
});
Related
It says [InteractionAlreadyReplied]: The reply to this interaction has already been sent or deferred. But inreality i am using editReply
I am having issue in logging error, it works fine with try and else but it shows [InteractionAlreadyReplied]: The reply to this interaction has already been sent or deferred in catch (error). I even tried using followUp but still doesnt work, it keeps giving the same error and shuts the whole bot down.
module.exports = {
data: new SlashCommandBuilder()
.setName("chat-gpt")
.setDescription("chat-gpt-3")
.addStringOption(option =>
option.setName('prompt')
.setDescription('Ask Anything')
.setRequired(true)),
async execute(interaction, client) {
const prompt = interaction.options.getString('prompt');
await interaction.deferReply();
const configuration = new Configuration({
apiKey: "nvm",
});
const openai = new OpenAIApi(configuration);
const response = await openai.createCompletion({
model: 'text-davinci-003',
prompt: prompt,
max_tokens: 2048,
temperature: 0.7,
top_p: 1,
frequency_penalty: 0.0,
presence_penalty: 0.0,
});
let responseMessage = response.data.choices[0].text;
/* Exceed 2000 */
try {
let responseMessage = response.data.choices[0].text;
if (responseMessage.length >= 2000) {
const attachment = new AttachmentBuilder(Buffer.from(responseMessage, 'utf-8'), { name: 'chatgpt-response.txt' });
const limitexceed = new EmbedBuilder()
.setTitle(`Reached 2000 characters`)
.setDescription(`Sorry, but you have already reached the limit of 2000 characters`)
.setColor(`#FF6961`);
await interaction.editReply({ embeds: [limitexceed], files: [attachment] });
} else {
const responded = new EmbedBuilder()
.setTitle(`You said: ${prompt}`)
.setDescription(`\`\`\`${response.data.choices[0].text}\`\`\``)
.setColor(`#77DD77`);
await interaction.editReply({ embeds: [responded] });
}
} catch (error) {
console.error(error);
await interaction.followUp({ content: `error` });
}
return;
},
};
i even tried using followUp or etc but the result is still same.
Your Problem
I believe the error occur in the catch() method (Line 55).
Please be reminded that the interaction has been deferred at Line 14:
await interaction.deferReply();
Explanation
Each interaction can only be replied and deferred once only. If you want to make changes on it, consider using the editReply() method.
Solution
Simply replace the code on Line 55 with editReply and this will solve the current error.
await interaction.editReply({ content: `error` });
I am building a chat component. This component uses Redux. My Chat component has a useEffect that dispatch(listConversations()) and retrieves the conversation along with its messages.
When someone sends a text to my chatApp twilio automatically updates the conversation with the new text message. The problem is, in order for me to see the message in my app I have to hit refresh and Execute a useEffect that dispatch(listConversations()).
My solution im thinking is a webhook?
I set up Ngrok successfully on my computer to create a url that points to my localhost backend for development.
http://ngrok.io ----> localhost:5000
I have successfully created a webhook for my conversation like so
await subClient.conversations.services(convoServiceSid)
.conversations(newConvoId)
.webhooks
.create({
'configuration.method': 'GET',
'configuration.filters': ['onMessageAdded', 'onConversationRemoved'],
'configuration.url': ' http://3de1-a30-00-8547.ngrok.io/conversation-messages',
target: 'webhook'
})
.then(webhook => console.log(webhook.sid));
My thought is that this will trigger a 'GET' request to my backend /conversation-messages and this will trigger the function I have below. But what I'm not sure of is if the GET comes from twilio, will the response go to my frontend or back to the Webhook server in this case twilio?
When I refresh my page this function below is called, But when I setup my webhook it doesnt get called. Am I doing this wrong?
const listConversationMessages = async (req, res) => {
console.log("list conversation Messages triggered")
console.log(req.body)
const { subActServiceSid, subActAuthToken, convoServiceSid} = req.user
const subClient = require('twilio')(subActServiceSid, subActAuthToken)
const allConversationSids = []
const allMessages = []
const sortedMessages = []
const options = { weekday: 'long'}
const monthOptions = { month: 'long'}
await subClient.conversations.services(convoServiceSid)
.conversations
.list()
.then(conversations => conversations.forEach(c => allConversationSids.push(c.sid))); // conversation possibly has "read" property?
await Promise.all(allConversationSids.map( async (convo) => {
await subClient.conversations.services(convoServiceSid)
.conversations(convo)
.messages
.list({limit: 20})
.then(messages => messages.forEach(m => allMessages.push({"messagesId": m.conversationSid, "participantSid": m.participantSid, "message": m.body, "time": { "day": new Intl.DateTimeFormat('en-US', options).format(m.dateCreated.getDay()), "hour": m.dateCreated.getHours() + ":" + m.dateCreated.getMinutes(), "date": new Intl.DateTimeFormat('en-US', monthOptions).format(m.dateCreated.getMonth()) + " " + m.dateCreated.getDate() + ", " + m.dateCreated.getFullYear()}})));
}))
let response
if(allMessages.length < 1 ) {
response = [{"messagesId": 1 , "content": [{ "participantSid": 2, "message": "test"} ]}]
} else {
response = allMessages
}
result = await response.reduce(function (accumulator, indexOfObject) {
accumulator[indexOfObject.messagesId] = accumulator[indexOfObject.messagesId] || [];
accumulator[indexOfObject.messagesId].push(indexOfObject); //it generates a new property a.messagesId with an array if it does not exist (the value of not existing properties is undefined). if exist, it assign itself
return accumulator;
}, Object.create({}));
sortedMessages.push(result)
const finalResult = Object.entries(sortedMessages[0]).map(([id, content]) => ({ id, content }))
res.json(finalResult)
}```
DETAILS....
My problem was when I declare the webhook 'configuration.url: '// I have a space before the http://'
Once I remove the space It works.
My goal is to send a push notification when a user sends a message. I am trying to do this by retrieving all of the push tokens from the firestore database, and sending a multicast message using these tokens each time a new message is added to the realtime database.
Works
This first example works. There is no token retrieval, the tokens are hardcoded. I do receive the notifications.
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate((liveSnapshot, context) => {
const name = context.params.messageId;
const message = liveSnapshot.val().toString();
const tokens = [
"e6erA_qM...",
"ePU9p_CI...",
];
const payload = {
notification: {
title: `New message from ${name}`,
body: message,
badge: '1',
sound: 'default'
},
tokens: tokens,
}
const res = admin.messaging().sendMulticast(payload);
console.log(`response: ${res}`);
Doesn't work
This doesn't work, I don't receive any notifications.
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (liveSnapshot, context) => {
const name = context.params.messageId;
const message = liveSnapshot.val().toString();
const snapshot = await admin.firestore().collection('users').get();
const tokens = snapshot.docs.map(doc => doc.data().token);
const payload = {
notification: {
title: `New message from ${name}`,
body: message,
badge: '1',
sound: 'default'
},
tokens: tokens,
}
const res = await admin.messaging().sendMulticast(payload);
console.log(`response: ${res}`);
I have verified that the tokens retrieved from the database are the same as the hardcoded ones with the following code.
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (liveSnapshot, context) => {
const hardcodedTokens = [
"e6erA_qM...",
"ePU9p_CI...",
];
const snapshot = await admin.firestore().collection('users').get();
const tokens = snapshot.docs.map(doc => doc.data().token);
let same = true;
hardcodedTokens.forEach(el => {
if (!tokens.includes(el)) {
same = false;
}
});
console.log(same);
})
This logs true in the firebase cloud functions console.
The function uses Node 12.
I experienced a similar problem recently, and solved it by breaking out Android and iOS specific fields according to the Firebase docs :
const message = {
"notification": {
"title": `New message from ${name}`,
"body": message,
},
'apns': {
'payload': {
'aps': {
'badge': 1,
},
},
},
'android':{
'notification':{
'notificationCount': 1,
},
},
"tokens": tokens,
}
The following code works.
async function getTokens() {
const snapshot = await admin.firestore().collection('users').get();
return snapshot.docs.map(doc => doc.data().token);
}
exports.notifyUsers = functions.database.ref('/messages/{messageId}').onCreate(async (snapshot, context) => {
const name = context.params.messageId;
const message = snapshot.val().toString();
const tokens = await getTokens();
const payload = {
notification: {
title: `New message from ${name}`,
body: message,
},
tokens: tokens,
};
await admin.messaging().sendMulticast(payload);
})
I logged my response like below:
const res = await admin.messaging().sendMulticast(payload);
console.log('response:', JSON.stringify(res));
This logged the following:
response: {"responses":[{"success":false,"error":{"code":"messaging/invalid-argument","message":"Invalid JSON payload received. Unknown name \"sound\" at 'message.notification': Cannot find field."}},{"success":false,"error":{"code":"messaging/invalid-argument","message":"Invalid JSON payload received. Unknown name \"sound\" at 'message.notification': Cannot find field."}}],"successCount":0,"failureCount":2}
Based on this, I believe the problem was the sound argument in the notification part of the payload. It works after removing it.
I have a problem testing my Skill on actions on google and in my mobile. It works fine with dialogflow but when I arrive to the Intent defined by the function questions_ready on the assistent of google or in the actions google web page to test it, I have the error "'final_response' must be set.". But it works on Dialogflow, so I dont know where it is the error. I leave here my code hoping some of you can help me! Thank you!
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
// Variables
var procedure;
var procedure;
var finish = "Ok, thank you. We have finished the questions";
var status_questions = [
{question: 'Ok, here is your first question. Please, could you tell me how do you feel on a scale from 1 to 10 ? Where 1 is very bad and 10 is very good'},
{question: 'Your workload is very high, high, normal, low or very low?'},
{question: 'Tell me what is your level of monotony on a scale from 1 to 10. Where 1 is very bad and 10 is very good'}];
var currentIndex = 0;
var currentQuestion = "";
var flag = 0;
var list_answers = [];
var list_index = [];
var list_timestamps = [];
var list_questions = [];
const dialogflowAgentRef = db.collection('dialogflow').doc();
//
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function manual(agent) {
const problem = agent.parameters.manual_problems;
if (problem == "DDoS problem"){
procedure = `Ok! Let's see how to solve your `+ problem + `. Specify here the procedure to resolve DDoS problem`;
}
else {
procedure = `Sorry, we don't have a manual to resolve that problem`;
}
agent.add((procedure));
}
function user_name(agent){
const user = agent.parameters.names;
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {name: user});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Ok ${user}, are you ready?`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${user}" to the Firestore database.`);
});
}
//WHEN IT IS CALLING THIS FUNCTION I GOT THE ERROR
function questions_ready(agent) {
if(currentIndex === 0){
list_index=[];
list_answers=[];
list_questions=[];
list_timestamps=[];
list_index.push(currentIndex);
currentQuestion = status_questions[currentIndex++].question;
}
else if(currentIndex >=1 && currentIndex <= 10){
list_index.push(currentIndex);
currentQuestion = status_questions[currentIndex++].question;
flag = 1;
const answParam = agent.parameters.answers;
const ans = answParam;
list_answers.push(ans);
}
else {
currentIndex = 0;
currentQuestion = finish;
flag=0;
const answParam = agent.parameters.answers;
const ans = answParam;
list_answers.push(ans);
agent.add(currentQuestion);
return db.runTransaction(t => {
t.update(dialogflowAgentRef, {time: list_timestamps});
t.update(dialogflowAgentRef, {index: list_index});
t.update(dialogflowAgentRef, {question: list_questions});
t.update(dialogflowAgentRef, {answer: list_answers});
return Promise.resolve('Write complete');
});
}
const ques = currentQuestion;
list_questions.push(ques);
var timestamp = Date.now();
list_timestamps.push(timestamp);
let ctx = {'name': 'projects/prueba-firebase-v1/agent/sessions/545ec712-8f69-6999-a50b-4127d38bce82/contexts/questions_ready', 'lifespan': 14,
'parameters': {'timestamp': list_timestamps, 'list_index': list_index, 'list_questions': list_questions, 'list_answers': list_answers}}; //, 'list_index': list_index
agent.setContext(ctx);
agent.add(currentQuestion);
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set(enter code here'Manual', manual);
intentMap.set('User_Name', user_name);
intentMap.set('Questions_Ready', questions_ready);
agent.handleRequest(intentMap);
});
The messages I obtain on Actions on Google are:
-On Simulator Display:
Prueba application isn't responding right now. Try again soon.
-Errors:
MalformedResponse
'final_response' must be set.
-Debug:
{
"response": "Prueba application isn't responding right now. Try again soon.",
"expectUserResponse": false,
"conversationToken": "GidzaW11bG...",
"audioResponse": "//NExAASWK...",
"debugInfo": {
"assistantToAgentDebug": {
"curlCommand": "curl -v 'https://api.api.ai/api/integrations/google?token=6094e3dbd9e242679d0dcc603568b120&versionId=3' -H 'Content-Type: application/json;charset=UTF-8' -H 'Google-Actions-API-Version: 2' -H 'Authorization: eyJhbGciOiJSUzI1NiIsImtpZCI6ImQxZTg2OWU3YmY0MGRkYzNkM2RlMDgwNDI1OThiYTgzNTA5NzBmMGEiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiJjeWJlcm9wcy1maXJlYmFzZS12MSIsIm5iZiI6MTU0MjcxMTY5MCwiaWF0IjoxNTQyNzExOTkwLCJleHAiOjE1NDI3MTIxMTAsImp0aSI6Ijc5NWYyZTViZGRjNzk5ZDAxMTY2MDZhZmEyZjJiMDRlYjU3MDk4ZGQifQ.XNBl3DcL2Zhw9bXHvPG52U21ATIb52snsQ5YF9T57cf9HrEeau6XTPfbtALdkiTEqhRfcihQTwLu7wAMdvmqTeeDaRW3F8C2xDCitT2bjPryeDJ3eyoJvI2cTy5Vhf1oN3WwsHdlM0D59JYyNtTH1NE-B60bnLCPQNe7Mv23aUnipdo-LsAytF_d9Bpz93SR_WZITqP6-FpqHSSuUHL3qi8idqGNQrtFF6RQ5-AGKkLkqE-V_Sa2iLmpqDsi4fP3RYW0bajuSFrn74JvrziQKQR4ZaFc4ITjPtJlhboCTgJusOqpFvOYV_-LF5FqgswaiMqUtaX8YBW_EKLLMLoS2A' -A 'Mozilla/5.0 (compatible; Google-Cloud-Functions/2.1; +http://www.google.com/bot.html)' -X POST -d '{\"user\":{\"userId\":\"ABwppHFD2VxLtzrmnMXp4XsxyE13Xc7mxOhaf7cbxMUQg7OEe_I1qRVlcDck8Rl-bESCZBPi3cHvESEbHYfvecHr59o\",\"locale\":\"en-US\",\"lastSeen\":\"2018-11-20T10:51:47Z\"},\"conversation\":{\"conversationId\":\"ABwppHH7q6m-4okbTf3aKCU-dgpEAoOmeCLle2AZjocfLI6i8BS1Lhqcx4InD3QBKboVr4yyTPcaOhAOMgQsaHIgHRU\",\"type\":\"ACTIVE\",\"conversationToken\":\"[]\"},\"inputs\":[{\"intent\":\"actions.intent.TEXT\",\"rawInputs\":[{\"inputType\":\"KEYBOARD\",\"query\":\"yes\"}],\"arguments\":[{\"name\":\"text\",\"rawText\":\"yes\",\"textValue\":\"yes\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"},{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"}]}],\"requestType\":\"SIMULATOR\"}'",
"assistantToAgentJson": "{\"user\":{\"userId\":\"ABwppHFD2VxLtzrmnMXp4XsxyE13Xc7mxOhaf7cbxMUQg7OEe_I1qRVlcDck8Rl-bESCZBPi3cHvESEbHYfvecHr59o\",\"locale\":\"en-US\",\"lastSeen\":\"2018-11-20T10:51:47Z\"},\"conversation\":{\"conversationId\":\"ABwppHH7q6m-4okbTf3aKCU-dgpEAoOmeCLle2AZjocfLI6i8BS1Lhqcx4InD3QBKboVr4yyTPcaOhAOMgQsaHIgHRU\",\"type\":\"ACTIVE\",\"conversationToken\":\"[]\"},\"inputs\":[{\"intent\":\"actions.intent.TEXT\",\"rawInputs\":[{\"inputType\":\"KEYBOARD\",\"query\":\"yes\"}],\"arguments\":[{\"name\":\"text\",\"rawText\":\"yes\",\"textValue\":\"yes\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"},{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"}]}],\"requestType\":\"SIMULATOR\"}"
},
"agentToAssistantDebug": {
"agentToAssistantJson": "{\n \"responseMetadata\": {\n \"status\": {\n \"code\": 10,\n \"message\": \"Failed to parse Dialogflow response into AppResponse because of empty speech response\",\n \"details\": [{\n \"#type\": \"type.googleapis.com/google.protobuf.Value\",\n \"value\": \"{\\\"id\\\":\\\"95a80a4d-4a98-461f-b183-88a358d87ebc\\\",\\\"timestamp\\\":\\\"2018-11-20T11:06:30.765Z\\\",\\\"lang\\\":\\\"en-us\\\",\\\"result\\\":{},\\\"alternateResult\\\":{},\\\"status\\\":{\\\"code\\\":206,\\\"errorType\\\":\\\"partial_content\\\",\\\"errorDetails\\\":\\\"Webhook call failed. Error: Webhook response was empty.\\\"},\\\"sessionId\\\":\\\"ABwppHH7q6m-4okbTf3aKCU-dgpEAoOmeCLle2AZjocfLI6i8BS1Lhqcx4InD3QBKboVr4yyTPcaOhAOMgQsaHIgHRU\\\"}\"\n }]\n }\n }\n}"
},
"sharedDebugInfoList": [
{
"name": "ResponseValidation",
"debugInfo": "",
"subDebugEntryList": [
{
"name": "MalformedResponse",
"debugInfo": "'final_response' must be set.",
"subDebugEntryList": []
}
]
}
]
},
"visualResponse": {
"visualElementsList": [
{
"displayText": {
"content": "Prueba application isn't responding right now. Try again soon."
}
}
],
"suggestionsList": [],
"agentLogoUrl": ""
},
"clientError": 0,
"is3pResponse": 1,
"clientOperationList": []
}
Here there are the images I have on my Questions_Ready Intent and the Dialog established by Dialogflow where all work perfectly. The problem is when I try to test the skill on Actions on Google
Questions_Ready Intent (I)
Questions_Ready Intent (II)
Answers Entities
Dialogflow dialog (I)
Dialogflow dialog (II)
Result obtained on Actions on Google
On the Debug json:
debugInfo.agentToAssistantDebug.agentToAssistantJson: "Failed to parse Dialogflow response into AppResponse because of empty speech response"
We can see that Dialogflow is not returning any response that Actions on Google understands. Example response for AoG
So, my thoughts are that the webhook is not returning the correct format for Actions on Google, which is different from Dialogflow.
Here you have a repository for examples of the responses for Actions on Google: https://github.com/dialogflow/fulfillment-webhook-json/tree/master/responses/v2/ActionsOnGoogle/RichResponses
I'm sorry I can't help further with the node.js code, I implemented the webhooks in another language, but the json response is the same for all of them.
From the code sample you provided, it seems like you've been using Dialogflow's Fulfillment library and not the Actions on Google client library, you can test out various samples and take a look at the dependencies up on Github, take this sample for example. The index.js file will have the following import declared when using the Actions on Google Node.js library:
const {dialogflow} = require('actions-on-google');
I am on ActionOnGoogle V2 SDK, and using Firebase Functions
I tried this code...
import * as functions from 'firebase-functions';
const admin = require('firebase-admin');
const serviceAccount = require("../key/secretkey.json");
import {dialogflow, BasicCard, SimpleResponse, List, Carousel} from 'actions-on-google';
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://dburl.com"
});
const getSomethingPromize = admin.database().ref(`/user_list/`).orderByChild('blood_group');
const app = dialogflow();
app.intent('getLocation', async (conv:any, parameters) => {
console.log("params", parameters);
return getSomethingPromize.equalTo(parameters.blood_group)
.once('value')
.then((snapshot) => {
const childCount = snapshot.numChildren();
let message = "";
let singleRecord;
switch (childCount) {
case 0:
message = `No Record`;
break;
case 1:
singleRecord = snapshot.val();
singleRecord = singleRecord[Object.keys(singleRecord)[0]];
message = `1 Record`;
getBasicCard(conv, singleRecord);
break;
default:
let myItems = {};
snapshot.forEach(childSnapshot => {
const entity = childSnapshot.val();
const state:any = parameters.indian_states;
if (entity.state.toLowerCase() !== state.toLowerCase()){
return;
}
myItems[entity.name] = {
synonyms: [
entity.name,
],
title: ` ${entity.name} `,
description: ` Contact : ${entity.phone} ${entity.phone2}, ${entity.city}, ${entity.state}, ${entity.pincode} `,
};
});
message = `Multiple Records`;
//ISSUE HERE
conv.close(new List({
title: `List Title`,
items: myItems,
}));
}
return getSimpleResponse(conv, parameters, message);
});
});
function getSimpleResponse(conv, parameters, message=null){
let displayMessage = message;
if (!message) {
displayMessage = `Sorry! No Record Found`;
}
return conv.close(new SimpleResponse({
text: displayMessage,
speech: displayMessage
}));
}
function getBasicCard(conv, singleRecord){
return conv.close(new BasicCard({
text: `${singleRecord.blood_group}, ${singleRecord.state}`,
subtitle: `Contact : ${singleRecord.phone} ${singleRecord.phone2}, ${singleRecord.city}, ${singleRecord.state}, ${singleRecord.pincode}, ${singleRecord.comment} `,
title: `${singleRecord.name}`,
display: 'CROPPED',
}));
}
export const fulfillment = functions.https.onRequest(app);
Issue is : When i Tried to Close Convo by Sending Rich List Card, the Convo remains Open.
Hence, on Stackdriver i am Issued with
"MalformedResponse: 'final_response' must be set"
I am Referencing this Docs
https://developers.google.com/actions/assistant/responses#list
You can only close the conversation with a SimpleResponse. According to the docs, "Your final response must be a single simple response with a 60-character limit on its textToSpeech and displayText values".