Malformed response error : empty speech response while making my agent - node.js

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',
}));
});

Related

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.

Dialogflow Detect Intent Fulfillment

Hi i have created a dialogflow nodejs backend which detects intents using the client library for nodejs.
const sessionPath = this.sessionClient.sessionPath(this.configService.get('dialogFlowProjectId'), sessionId);
const request = {
session: sessionPath,
queryInput: {
text: {
text: query,
languageCode: "en-US"
}
}
};
// Send request and log result
Logger.log(request);
const responses = await this.sessionClient.detectIntent(request);
this works fine but I also want to trigger a fulfillment for certain intents.
I have setup a webhook url - this works fine when you use the chat in the dialogflow console. But when I use the method that I have created to send the request to dialogflow the webhook doesn't get called and goes to fallback intent. I'm calling the same intent through the dialogflow console chat and through my own API.
How can I trigger the webhook call when I use the client library API?
First, remember that you don't "call an Intent", either through the test console or through the API. What you can do is send query text that should be matched by an Intent.
If you have set the Intent so that it should call the Fulfillment webhook, then this should happen no matter the source, as long as the Intent itself is triggered.
That the Fallback Intent is getting triggered instead suggests that something about the query text isn't matching the Intent you think it should be matching. I would check to make sure the text you're sending in query should match the training phrases for the Intent in question, that you have no Input Contexts, and that your agent is set for the "en-US" language code.
For routing multiple intents through a webhook you're going to want to have a handler.js file with an express router in it...
const def = require('./intents/default')
const compression = require('compression')
const serverless = require('serverless-http')
const bodyParser = require('body-parser')
const { WebhookClient } = require('dialogflow-fulfillment')
const express = require('express')
const app = express()
// register middleware
app.use(bodyParser.json({ strict: false }))
app.use(function (err, req, res, next) {
res.status(500)
res.send(err)
})
app.use(compression())
app.post('/', async function (req, res) {
// Instantiate agent
const agent = new WebhookClient({ request: req, response: res })
const intentMap = new Map()
intentMap.set('Default Welcome Intent', def.defaultWelcome)
await agent.handleRequest(intentMap)
})
module.exports.server = serverless(app)
As you can see, this handler.js is using serverless-http and express.
Your intent.js function could look something like this ...
module.exports.defaultWelcome = async function DefaultWelcome (agent) {
const responses = [
'Hi! How are you doing?',
'Hello! How can I help you?',
'Good day! What can I do for you today?',
'Hello, welcoming to the Dining Bot. Would you like to know what\'s being served? Example: \'What\'s for lunch at cronkhite?\'',
'Greetings from Dining Bot, what can I do for you?(Hint, you can ask things like: \'What\'s for breakfast at Annenberg etc..\' or \'What time is breakfast at Anennberg?\')',
'greetings',
'hey',
'long time no see',
'hello',
"lovely day isn't it"
]
const index = Math.floor((Math.random() * responses.length) + 1)
console.log(responses[index].text)
agent.add(responses[index].text)
}
This gives you the bare bones for routing multiple request through your webhook. Hope this helps.

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)

Google dialogflow small talk issue

i am developing chat bot application with google dialog flow. i am using node js client https://github.com/dialogflow/dialogflow-nodejs-client-v2 to access the data of my chat bot. i have enabled small talk from the dialog flow console and it works fine when i use it from the dialog flow web demo or the console it self
for the same chat application i have implemented a api by using dialogflow node js client.
if (req.body.text) {
query = req.body.text;
}
// Get the city and date from the request
var request = {
session: sessionPath,
queryInput: {
text: {
text: query,
languageCode: languageCode,
},
},
};
// Send request and log result
sessionClient
.detectIntent(request)
.then(responses => {
console.log('Detected intent');
const result = responses[0].queryResult;
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
res.json({ "text": result.fulfillmentText });
} else {
res.json({ 'fulfillmentText': "No intent matched" });
console.log(` No intent matched.`);
}
})
.catch(err => {
console.error('ERROR:', err);
});
there i dont get the result i want. instead it goes to a different intent
what i have done incorrectly here..
Queries defined in Small Talk section of your Dialogflow agent will not have an associated intent. If there was a matching intent, then you shouldn't have really added that query into Small Talk. Therefore, since there is not matching intent, the Dialogflow Node library will return an unmatched intent.

Displaying BasicCard in Dialogflow response

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
});

Resources