Displaying BasicCard in Dialogflow response - node.js

I'm trying to display a BasicCard in dialogflow's fulfillment, but I always get this error message MalformedResponse 'final_response' must be set.. The responseMetaData says code 10 and Failed to parse Dialogflow response into AppResponse because of empty speech response.
This is my code:
agent.add(`Check this out`);
agent.add(new BasicCard({
title: 'Card Title',
text: 'Description',
image: {
url: 'https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png',
accessibilityText: 'Google Logo',
},
buttons: new Button({
title: 'Button Title',
url: 'https://www.google.com',
}),
}));
I'm using Cloud Functions for Firebase and
"actions-on-google": "2.0.0-alpha.4",
"dialogflow-fulfillment": "0.3.0-beta.3"
and
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card} = require('dialogflow-fulfillment');
const {BasicCard, Button} = require('actions-on-google');
const agent = new WebhookClient({ request, response });
It works perfectly fine when I use new Card() instead of new BasicCard().
Any ideas what I'm doing wrong?

Just a thought, have you tried
let conv=agent.conv();
conv.ask(new BasicCard({//Your code here
});

Related

For some reason when using the dialogflow detectIntent googleapi, I keep getting default fallback intent even though other api's like listIntents work

Has anyone experienced this issue?
I am sure the dialogflow connection works because listing the intents works which is (intentsClient.listIntents(request)) and it gives me back all the intents from my dialogflow es agent. So it looks like the credentials should be fine.
Any help would be highly appreciated,
Thanks
const dialogflow = require('#google-cloud/dialogflow').v2;
const uuid = require('uuid');
const sessionId = uuid.v4();
const sessionClient = new dialogflow.SessionsClient({ keyFilename: '..........' });
const sessionPath = sessionClient.projectAgentSessionPath(
projectId,
sessionId
);
const query = 'What are the pets rules';
async function detectIntentForQuestion() {
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
text: query,
languageCode: 'en-US',
},
},
queryParams: {
sentimentAnalysisRequestConfig: {
analyzeQueryTextSentiment: true,
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
console.log(` Intent: ${result.intent.displayName}`);
} else {
console.log(' No intent matched.');
}
if (result.sentimentAnalysisResult) {
console.log('Detected sentiment');
console.log(
` Score: ${result.sentimentAnalysisResult.queryTextSentiment.score}`
);
console.log(
` Magnitude: ${result.sentimentAnalysisResult.queryTextSentiment.magnitude}`
);
} else {
console.log('No sentiment Analysis Found');
}
};
you are setting languageCode: 'en-US' for language. Does your agent support this language? If it is set using a different language (ie. Spanish), then it is expected to give you back only the fallback intent response.
other thing that you can do is checking at https://dialogflow.cloud.google.com/#/agent/<your agent name>/history and in your last interactions, you click on the 3 dots in the agent response and go to Raw interaction log. There you can see the information the agent got from your code, how it was interpreted by the agent and how it answered you back.

How to trigger an sending email to human using Dialogflow ES Fulfillment

I am using the fulfillment and nodemailer in my editor and would like to send an email to my personal email address. When I try to integrate to Dialogflow Messenger Beta version, my chatbot will not understand the response.
My output:
User: "I would like to send an email to the support service."
Bot: "Sorry. I do not understand your question."
Correct output:
User: "I would like to send an email to the support service."
Bot: "What is your name?"
User: "Henry"
Bot: "What is your email?"
User: "henry65#gmail.com"
Bot: "Thanks Henry. We will get back to you as soon as possible."
index.js
// See https://github.com/dialogflow/dialogflow-fulfillment-nodejs
// for Dialogflow fulfillment library docs, samples, and to report issues
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const nodemailer = require("nodemailer");
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'james641#gmail.com',
pass: 'test#1567'
}
});
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
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 sendEmailHandler(agent){
const { email, name } = agent.parameters;
const question = agent.parameters.question;
const mailOptions = {
from: "James", // sender address
to: email, // list of receivers
subject: "Email from Chatbot", // Subject line
html: "<p>Name:</p> " + name + "<p>Email:</p>" + email + "<p>Questions:</p>" + question
};
transporter.sendMail(mailOptions, function (err, info) {
if(err)
{
console.log(err);
}
});
}
// // Uncomment and edit to make your own intent handler
// // uncomment `intentMap.set('your intent name here', yourFunctionHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function yourFunctionHandler(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/images/badges/XPM_BADGING_GoogleAssistant_VER.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.setContext({ name: 'weather', lifespan: 2, parameters: { city: 'Rome' }});
// }
// // Uncomment and edit to make your own Google Assistant intent handler
// // uncomment `intentMap.set('your intent name here', googleAssistantHandler);`
// // below to get this function to be run when a Dialogflow intent is matched
// function googleAssistantHandler(agent) {
// let conv = agent.conv(); // Get Actions on Google library conv instance
// conv.ask('Hello from the Actions on Google client library!') // Use Actions on Google library
// agent.add(conv); // Add Actions on Google library responses to your agent's response
// }
// // See https://github.com/dialogflow/fulfillment-actions-library-nodejs
// // for a complete Dialogflow fulfillment library Actions on Google client library v2 integration sample
// 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('sendEmail_intent', sendEmailHandler);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
agent.handleRequest(intentMap);
});
I'm still new to Dialogflow so I'm not that savvy with the webhooks and fulfillments. Please help me.
One approach to achieving your use case is to activate the Default fallback intent and enable the Fulfilment of that intent. However, you must ensure that you collect the email address at the fallback intent.
On Dialogflow webhook is triggered by the default fallback, which provides the question
and sessionID, which is then saved in a database.
Then fallback method requests an email address.
Lastly, the user provides an email and intent fires another webhook, which updates the
original record with the email address and sends the request to the inbox.
To avoid this hassle, you can integrate Dialoglfow with any third-party platform, such as Kommunicate, and send email notifications directly from the dashboard. When the default fallback intent gets triggered or when a human agent is assigned to a conversation, an email will be automatically sent.
PS: I work for Kommunicate.

Error : Dialogflow server in 'us' received request for resources located in 'europe-west2-dialogflow.googleapis.com.'

I want to detect an intent with dialogflow, but my dialogflow agent's region is europe-west2 for some reasons. So to specify a location, I use the version v2beta1 of Dialogflow API like described in the documentation. But it doesn't worked and I have the following error Dialogflow server in 'us' received request for resources located in 'europe-west2-dialogflow.googleapis.com.
Code :
const sessionId = crypto.randomBytes(16).toString("hex");
// Create a new dialogflow session
const sessionClient = new Dialogflow.SessionsClient(this.dialogFlowConfig)
const sessionPath = sessionClient.projectLocationAgentSessionPath(this.projectId, "europe-west2-dialogflow.googleapis.com", sessionId);
// The text query request.
const dfRequest = {
session: sessionPath,
queryInput: {
event: {
name: "Welcome",
languageCode: DialogFlowService.LANGUAGE_CODE
}
}
}
try {
const responses = await sessionClient.detectIntent(dfRequest);
const result = responses[0].queryResult!;
Logger.debug(` Query: ${result.queryText}`);
Logger.debug(` Response: ${result.fulfillmentText}`);
if (result.intent) {
Logger.debug(` Intent: ${result.intent.displayName}`);
} else {
Logger.debug(` No intent matched.`);
}
return result
I had the similar issue, but the below config worked to access dialogflow agent's in region europe-west2
Set the Location as "europe-west2"
Also need to set the
SessionsClient's 'apiEndpoint' as
"europe-west2-dialogflow.googleapis.com"
const sessionClient = new dialogflow.SessionsClient({ apiEndpoint: "europe-west2-dialogflow.googleapis.com" });
const sessionPath = sessionClient.projectLocationAgentSessionPath(
projectId,
"europe-west2",
sessionId
);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
text: query,
languageCode: languageCode,
},
},
};
Try to use 'europe-west2' as location. More docs here.

Malformed response error : empty speech response while making my agent

I was making dialogflow app that links the user to each links regarding to the number that user says.
I got google codelab's fulfillment code and edited it to make it.
But when I try to use Card and other things to create clickable url links, "MalformedResponse: Failed to parse Dialogflow response into AppResponse because of empty speech response" happens.
I'm using Dialogflow InlineEditor for this.
Tried to app.buildRichResponse but that also fails
This is my node.js code.
'use strict';
// Import the Dialogflow module from the Actions on Google client library.
const {dialogflow} = require('actions-on-google');
// Import the firebase-functions package for deployment.
const functions = require('firebase-functions');
// Instantiate the Dialogflow client.
const app = dialogflow({debug: true});
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
// Handle the Dialogflow intent named 'favorite color'.
// The intent collects a parameter named 'color'.
app.intent('getJobs', (conv, {number}) => {
const jobNum = number;
// Respond with the user's lucky number and end the conversation.
if (number == 1) {
conv.ask(new Card({
title: `Title: this is a card title`,
imageUrl: 'https://dialogflow.com/images/api_home_laptop.svg',
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://docs.dialogflow.com/'
}));
} else if (number == 2) {
conv.close('camera on');
} else {
conv.close('unknown number');
}
});
//Set the DialogflowApp object to handle the HTTPS POST request.
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
I think problem is, you use only rich response when number is 1 and this may cause "MalformedResponse: Failed to parse Dialogflow response into AppResponse because of empty speech response" error since there is nothing assistant can response with voice. You can't use rich response without simple response.
Also you are trying to use both actions-on-google and dialogflow-fulfillmentlibraries. This can cause the problem as well. You can try:
function getJobs(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/images/badges/XPM_BADGING_GoogleAssistant_VER.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/'
})
);
intentMap.set('getJobs', getJobs);
or
const { dialogflow, BasicCard, Image, Button } = require('actions-on-google');
app.intent('getJobs', (conv, {number}) => {
conv.ask('This is simple response...',new BasicCard({
text: `This is a basic card.`
subtitle: 'This is a subtitle',
title: 'Title: this is a title',
buttons: new Button({
title: 'This is a button',
url: 'https://assistant.google.com/',
}),
image: new Image({
url: 'https://example.com/image.png',
alt: 'Image alternate text',
}),
display: 'CROPPED',
}));
});

How to implement Media Response with Dialogflow

I am using Dialogflow and would like to implement a media response in my project. I have tried to do so using the following link: https://developers.google.com/actions/assistant/responses but have been unsuccessful. How to do the implementation?
const functions = require('firebase-functions')
const {dialogflow} = require('actions-on-google')
const TEST = 'test'
const app = dialogflow({
debug: true,
})
app.intent('test', (conv) =>{
conv.ask('we will now play a song for you');
conv.ask(new MediaObject({
name: 'Jazz in Paris',
url: 'https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3',
}));
conv.ask(new MediaResponse({
mediaObject: 'Jazz in Paris',
mediaType: AUDIO,
}));
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app)
You just need to add the MediaObject. You don't need to add the MediaResponse object since the library will add it for you.
You will, however, need to make sure you load the MediaObject object as part of your call to require(). You'll also need to load the Suggestions object since you need to provide suggestions to advance the conversation if the user chooses to interrupt your audio.
So your code can look something like this:
const functions = require('firebase-functions')
const {
dialogflow,
MediaObject,
Suggestions
} = require('actions-on-google')
const app = dialogflow({
debug: true,
})
app.intent('test', (conv) =>{
conv.ask('we will now play a song for you');
conv.ask(new MediaObject({
name: 'Jazz in Paris',
url: 'https://storage.googleapis.com/automotive-media/Jazz_In_Paris.mp3',
}));
conv.ask(new Suggestions(['suggestion 1', 'suggestion 2']));
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app)

Resources