Why does this fulfillment code for Dialogflow does not work? - dialogflow-es

I am playing around a bit with the Dialogflow. As I was trying to figure out the options in the responses, I also wanted to test if Dialogflow has dynamic response. For example, fetch a data from Database (Firebase Database or MongoDB) and show it as a response instead of hard coding every response.
I have learnt that Fulfillment can do that job. When I enabled the Inline editor in Fulfillment in Dialogflow, it already has some code to be deployed. I figured, just for testing, I would write some very basic function in Fulfillment and see if it works.
// 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');
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 test(agent){
agent.add('test confirmed!');
}
// // 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/dialogflow-fulfillment-nodejs/tree/master/samples/actions-on-google
// // 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('test-intent',test);
// intentMap.set('your intent name here', yourFunctionHandler);
// intentMap.set('your intent name here', googleAssistantHandler);
agent.handleRequest(intentMap);
});
The function test is the only thing I have added to the already pre existing code along with the intentMap.set('test-intent', test);.
I have the intent as follows:
{
"id": "3fea3cec-d3f0-4d4e-a838-b4134894ea05",
"name": "test-intent",
"auto": true,
"contexts": [],
"responses": [
{
"resetContexts": false,
"affectedContexts": [],
"parameters": [
{
"id": "de3d79b3-b062-445a-8c55-d499a2d7b12d",
"required": false,
"dataType": "",
"name": "sample",
"value": "1",
"promptMessages": [],
"noMatchPromptMessages": [],
"noInputPromptMessages": [],
"outputDialogContexts": [],
"isList": false
}
],
"messages": [
{
"type": "simple_response",
"platform": "google",
"textToSpeech": "t",
"ssml": "",
"displayText": ""
}
],
"defaultResponsePlatforms": {},
"speech": []
}
],
"priority": 500000,
"webhookUsed": false,
"webhookForSlotFilling": false,
"fallbackIntent": false,
"events": [],
"userSays": [
{
"id": "d8aee895-8326-4454-b0f4-c2237984d968",
"data": [
{
"text": "testing...",
"userDefined": false
}
],
"isTemplate": false,
"count": 0,
"updated": 0,
"isAuto": false
}
],
"followUpIntents": [],
"liveAgentHandoff": false,
"endInteraction": false,
"templates": []
}
It is bare bones with nothingness. I just wanted to test the response in Actions on Google.
I only get the response I have manually entered in the 'testing-intent' in Actions on Google..
What am I doing wrong?

I already figured out the problem I have when I looked at the testing-intent's json before posting this question. I had to Enable webhook call for this intent.
Go to bottom portion of the selected intent page you want to enable Fulfillment.
Click Fulfillment to expand it.
Click Enable webhook call for this intent

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.

Rich response fulfillment Dialogflow Messenger

I'm using Dialogflow Messenger integration. Custom Payloads are working from the Dialogflow platform, but I don't know how to use them from Webhook.
Here is my JavaScript code that doesn't works:
const functions = require('firebase-functions');
const { dialogflow } = require('actions-on-google');
const { Card, Suggestion } = require('dialogflow-fulfillment');
const { WebhookClient } = require('dialogflow-fulfillment');
const app = dialogflow();
const response = {
"fulfillment_messages": [{
"payload": {
"richContent": [
[{
"type": "chips",
"options": [{
"text": "Empezar!"
}]
}]
]
}
}]
}
const numero = (conv) => {
conv.ask(response);
};
app.intent("numero", numero);
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
The intent is detected correctly but the code for the rich response is not working, the chatbot response is: 'Cannot display response in Dialogflow simulator. Please test on the Google Assistant simulator instead.'.
I want to know how to use all possible custom payloads (Info response, Description response, Button response...).
Your JSON response in the webhook should be-
const response = {
"fulfillment_messages": [{
"payload": {
"richContent": [
[{
"type": "chips",
"options": [{
"text": "Empezar!"
}]
}]
]
}
}]
}
Your response on dialogflow messenger would look like
Here is another stackoverflow post that might help-
How to show Rich Response Buttons (''Chips) Using Dialogflow Fulfillment?

actions-on-google Account Linking Signin status is "ERROR" always

I got this sample code from the docs of actions on google account linking with google account. The signin.status is always "ERROR". I have tried on actions console simulator, google assistant app on my phone and on a google home mini with personal results on. But the result is the same in all cases.
const express = require('express');
const bodyParser = require('body-parser');
const {actionssdk, SignIn} = require('actions-on-google');
const app = actionssdk({
// REPLACE THE PLACEHOLDER WITH THE CLIENT_ID OF YOUR ACTIONS PROJECT
clientId: <client_id>,
});
// Intent that starts the account linking flow.
app.intent('actions.intent.MAIN', (conv) => {
conv.ask(new SignIn('To get your account details'));
});
// Create an Actions SDK intent with the `actions_intent_SIGN_IN` event.
app.intent('actions.intent.SIGN_IN', (conv, params, signin) => {
console.log(signin)
if (signin.status === 'OK') {
const payload = conv.user.profile.payload;
conv.ask(`I got your account details, ${payload.name}. What do you want to do next?`);
} else {
conv.ask(`I won't be able to save your data, but what do you want to do next?`);
}
});
app.intent('actions.intent.TEXT', (conv) => {
conv.close("bye");
})
//Run server
const expressApp = express().use(bodyParser.json());
expressApp.post('/', function(req,res){
app(req,res);
});
expressApp.listen(8080,() => {console.log("listening")});
This is the signin object I'm being returned
{ '#type': 'type.googleapis.com/google.actions.v2.SignInValue',
status: 'ERROR' }
EDIT
My actions.json is as follows
{
"actions": [
{
"description": "Default Welcome Intent",
"name": "MAIN",
"fulfillment": {
"conversationName": "fulfilment function"
},
"intent": {
"name": "actions.intent.MAIN",
"trigger": {
"queryPatterns": [
"talk to Care Cat"
]
}
}
},
{
"description": "Everything Else Intent",
"name": "allElse",
"fulfillment": {
"conversationName": "fulfilment function"
},
"intent": {
"name": "actions.intent.TEXT"
}
}
],
"conversations": {
"fulfilment function": {
"name": "fulfilment function",
"url": <url>
}
},
"locale": "en"
}
Could it be because it is still a test app which is not published yet?
Can someone help me with this?
In your Google Cloud Platform Account, check your IAM settings and enable the Dialogflow API Admin
Documentation for more details: https://cloud.google.com/dialogflow/docs/access-control

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

Resources