ReferenceError: request is not defined in DialogFlow using node.js - node.js

const DialogflowApp = require('actions-on-google').DialogflowApp;
const app = new DialogflowApp({request: request, response: response});
const WELCOME_INTENT = 'input.welcome'; // the action name from the Dialogflow intent
const NUMBER_INTENT = 'input.number'; // the action name from the Dialogflow intent
const NUMBER_ARGUMENT = 'input.mynum'; // the action name from the Dialogflow intent
I got Reference Error: request is not defined.

It looks like, from just what you've provided, that you're not defining app inside an HTTPS handler. The DialogflowApp constructor expects to be passed a request and response object that are sent by an Express-like node.js handler. If you are using Google Cloud Functions or Firebase Cloud Functions, these will be what are available in your function handler.
So if you're using Firebase Cloud Functions, it might look something like this:
const DialogflowApp = require('actions-on-google').DialogflowApp;
const WELCOME_INTENT = 'input.welcome'; // the action name from the Dialogflow intent
const NUMBER_INTENT = 'input.number'; // the action name from the Dialogflow intent
const NUMBER_ARGUMENT = 'input.mynum'; // the action name from the Dialogflow intent
// You will use the action name constants above as keys for an "actionMap"
// with the value being a function that implements each action.
let actionMap = new Map();
// TODO - you need to do this part.
const functions = require('firebase-functions');
exports.webhook = functions.https.onRequest( (request,response) => {
const app = new DialogflowApp({request: request, response: response});
app.handleRequest( actionMap );
});

if you are using a Node.js app with express ou need to create the instance (assistant in this case) of the Dialogflow class inside the method that handles the route used.
let express = require('express');
let app = express();
const DialogflowApp = require('actions-on-google').DialogflowApp;
app.post('/', function (request, response) {
const assistant = new DialogflowApp({request: request, response: response});
//... code
})

Adding these statements in your command may solve the issue
const DialogflowApp = require('actions-on-google').DialogflowApp;
const app = new DialogflowApp({request: request, response: response});
I hope this may solve your issue.

Related

agent.add() sometimes not able to give results in dialogflow

I am using Dialogflow to build a chatbot and I am using Axios to make some posts and get requests, but sometimes agent.add() inside that HTTP call doesn't work.
I am attaching the sample code.
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
// Using some external libraries
//axios for using third party api hosted as http.
const axios = require('axios');
// xml2js for parsing xml output in response
const xml2js = require('xml2js');
const json = require('json');
// Accessing firebase admin
const admin = require('firebase-admin');
function name(agent){
return axios.post('http://some-api,
{"name": "Kyle"}).then((result) => {
console.log('Store datato api');
agent.add('What is your email id'); // Sometimes its working and sometimes its not
//return Promise.resolve(agent); // I tried this as well but the same issue.
});
}
What could be appropiate changes, as I was going through all other questions on Stackoverflow, I tried returning pomise as well, but didn't work.
It looks like you've structured your Promise incorrectly. This is the format I use to return responses that require Promises:
function name(agent) {
const promise = new Promise(resolve => {
// logic goes here
resolve(agent.add(output));
});
return promise;
}
If this doesn't work, check other points it may be failing at - are you sure your webhook isn't failing in the POST request?

Dialogflow Node.js Client - save data on data side, but don't return response

I'm using DialogFlow with the official Google Node.js library. I want to use a webhook to save input data to a database, but not return a response.
However, currently I'm just waiting for the function to timeout which is slow, and writes an error to the logs Error: No responses defined for platform: FACEBOOK
I've checked the documentation hoping for a way to send a 200 status or similar, but haven't found anything. https://dialogflow.com/docs/reference/fulfillment-library/webhook-client
Is it possible to do what I'd like to do? It seems like a fairly standard requirement.
UPDATE: My code is simple, but below
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
const firebase = require('firebase-admin');
firebase.initializeApp();
const session_split = agent.session.split('/');
const session = session_split[blf_session_split.length - 1];
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((req, res) => {
const agent = new WebhookClient({
request: req,
response: res
});
agent.handleRequest(savedata);
function input(agent) {
return firebase.database().ref('/tests/' + session).update({
"input": agent.action
});
}
});

Error: Platform can NOT be empty at new Payload in Dialogflow

I have a serverless app where I want to run my logic from the chatbot request coming from Facebook Messenger. When I run the intent function for test_handler I get the correct response back. But after I added another handler for skillRatio I seem to be getting the error in the title i.e
Error: Platform can NOT be empty at new Payload
. My code is as below.
const serverless = require('serverless-http');
const bodyParser = require('body-parser');
const express = require('express');
const app = express();
app.use(bodyParser.json({ strict: false }));
const {WebhookClient, Payload, Image, Card, Suggestion} = require('dialogflow-fulfillment');
const request = require('request');
app.get('/', function (req, res) {
res.send('Hello World !!!\n');
console.log("Testing express lambda\n");
})
app.post('/', function (req, res) {
const agent = new WebhookClient({request: req, response: res});
function test_handler(agent) {
agent.add(`Welcome to my agent on AWS Lambda!`);
agent.add(new Image("https://image-charts.com/chart?chs=700x190&chd=t:60,40&cht=p3&chl=Hello%7CWorld&chf=ps0-0,lg,45,ffeb3b,0.2,f44336,1|ps0-1,lg,45,8bc34a,0.2,009688,1"))
}
function skillRatio(agent) {
agent.add(`Let me just have a look and I'll gather the data. *Processing Chart Data....Mmmm Pie*.
Here we go! Here is the data on your $Skills.original request.`);
//agent.add(`Feel free to save or share :)`);
//agent.add(new Image("https://image-charts.com/chart?chs=700x190&chd=t:60,40&cht=p3&chl=Hello%7CWorld&chf=ps0-0,lg,45,ffeb3b,0.2,f44336,1|ps0-1,lg,45,8bc34a,0.2,009688,1"))
}
// Run the proper function handler based on the matched Dialogflow intent name
let intentMap = new Map();
intentMap.set('super-test', test_handler);
//intentMap.set('skill-ratio', skillRatio);
if (agent.requestSource === agent.FACEBOOK) {
intentMap.set('super-test', test_handler);
intentMap.set('skill-ratio', skillRatio);
} else {
}
agent.handleRequest(intentMap);
})
module.exports.handler = serverless(app);
Dialogflow Images:
I am trying to run the code on Messenger. Any help would be hugely appreciated as I am so stuck trying to get my head around this.
As it turns out, in the below image, a Custom Payload was causing the issue I was having. If you get the same error
Error: Platform can NOT be empty at new Payload.
Triple check your default responses across all the response types and remove anything that has an empty payload.
Your resolution is a little intuitive and not completely correct. It is not specifically a problem with an empty payload, the problem persists with having a payload in general.
You can try to either set the platform manually like so =>
How to set a custom platform in Dialogflow NodeJS Client
or choose one of the methods described in here =>
https://github.com/dialogflow/dialogflow-fulfillment-nodejs/issues/153
Setting the platform befor initializing the WebHookClient
if (!request.body.queryResult.fulfillmentMessages)
return;
request.body.queryResult.fulfillmentMessages = request.body.queryResult.fulfillmentMessages.map(m => {
if (!m.platform)
m.platform = 'PLATFORM_UNSPECIFIED';
return m;
});

Matching Express Routes to Google Assistant intents

I have an Express app that I am trying to integrate with Google Assistant.
I've installed https://www.npmjs.com/package/actions-on-google and have followed https://codelabs.developers.google.com/codelabs/actions-1/#0 which deploys functions to Firebase - however I would like to run them from a self-hosted Express server.
In my app.js I have set up as follows:
const {
dialogflow,
Image,
} = require('actions-on-google')
// Create an app instance
const gapp = dialogflow();
});
However I am unsure how to create the route that I add in Dialogflow console as the webhook - do I use the format below?
app.post('/webhook', function(req, res){
gapp.intent('favorite color', (conv, {color}) => {
const luckyNumber = color.length;
// Respond with the user's lucky number and end the conversation.
conv.close('Your lucky number is ' + luckyNumber);
});
});
If so do all of my intents then go within this route?
EDIT
Updated in response to answer:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const {
dialogflow,
Image,
} = require('actions-on-google')
// Create a google app instance
const gapp = dialogflow()
// Register handlers for Dialogflow intents
gapp.intent('Default Welcome Intent', conv => {
conv.ask('Hi, how is it going?')
conv.ask(`Here's a picture of a cat`)
conv.ask(new Image({
url: 'https://developers.google.com/web/fundamentals/accessibility/semantics-builtin/imgs/160204193356-01-cat-500.jpg',
alt: 'A cat',
}))
})
// Intent in Dialogflow called `Goodbye`
gapp.intent('Goodbye', conv => {
conv.close('See you later!')
})
gapp.intent('Default Fallback Intent', conv => {
conv.ask(`I didn't understand. Can you tell me something else?`)
})
app.post('/ga/webhook', gapp)
You can define all of your gapp intents at the start of your Express server, then you can pass in your gapp object into the webhook that you define:
const express = require('express')
const bodyParser = require('body-parser')
// ... gapp code here
const expressApp = express().use(bodyParser.json())
expressApp.post('/webhook', gapp)
expressApp.listen(3000)

actions-on-google api.ai doesn't send body in POST request with nodejs and express

I'm trying to run the sillyNameMaker example from actions-on-google with api.ai, on my computer.
I set up a nodejs server with express, and a ngrok tunneling. When I try to send a request with my agent on api.ai, my server receives the POST request, but the body appears to be empty. Is there anything i didn't set up properly?
Here is my index.js file:
'use strict';
var express = require('express')
var app = express()
const ApiAiAssistant = require('actions-on-google').ApiAiAssistant;
function sillyNameMaker(req, res) {
const assistant = new ApiAiAssistant({request: req, response: res});
// Create functions to handle requests here
const WELCOME_INTENT = 'input.welcome'; // the action name from the API.AI intent
const NUMBER_INTENT = 'input.number'; // the action name from the API.AI intent
const NUMBER_ARGUMENT = 'input.mynum'; // the action name from the API.AI intent
function welcomeIntent (assistant) {
assistant.ask('Welcome to action snippets! Say a number.');
}
function numberIntent (assistant) {
let number = assistant.getArgument(NUMBER_ARGUMENT);
assistant.tell('You said ' + number);
}
let actionMap = new Map();
actionMap.set(WELCOME_INTENT, welcomeIntent);
actionMap.set(NUMBER_INTENT, numberIntent);
assistant.handleRequest(actionMap);
function responseHandler (assistant) {
console.log("okok")
// intent contains the name of the intent you defined in the Actions area of API.AI
let intent = assistant.getIntent();
switch (intent) {
case WELCOME_INTENT:
assistant.ask('Welcome! Say a number.');
break;
case NUMBER_INTENT:
let number = assistant.getArgument(NUMBER_ARGUMENT);
assistant.tell('You said ' + number);
break;
}
}
// you can add the function name instead of an action map
assistant.handleRequest(responseHandler);
}
app.post('/google', function (req, res) {
console.log(req.body);
sillyNameMaker(req, res);
})
app.get('/', function (req, res) {
res.send("Server is up and running.")
})
app.listen(3000, function () {
console.log('Example app listening on port 3000!')
})
And the error I got:
TypeError: Cannot read property 'originalRequest' of undefined
at new ApiAiAssistant (/Users/clementjoudet/Desktop/Dev/google-home/node_modules/actions-on-google/api-ai-assistant.js:67:19)
at sillyNameMaker (/Users/clementjoudet/Desktop/Dev/google-home/main.js:8:21)
I'm trying to print req.body but it is undefined... Thanks in advance for your help.
Both you and the actions-on-google package are making an assumption about how you're using Express. By default, Express does not populate the req.body attribute (see the reference for req.body). Instead it relies on additional middleware such as body-parser to do so.
You should be able to add body parser to your project with
npm install body-parser
and then use it to parse the request body into JSON (which API.AI sends and actions-on-google uses) with some additional lines right after you define app to attach it to Express:
var bodyParser = require('body-parser');
app.use(bodyParser.json());

Resources