No response from my webhook on Dialogflow - node.js

This is the code I have in my server:
const express = require('express');
const bodyParser = require('body-parser');
const appExpress = express().use(bodyParser.json());
const {
dialogflow,
Image,
} = require('actions-on-google')
const app = dialogflow()
appExpress.post('/hook', express.json() ,(req, res) => {
app.intent('MyIntent', conv => {
conv.ask('Hi, how is it going?')
});
});
appExpress.listen(3333, ()=>console.log("Server is live at port 3333"));
When I run this, it returns no errors (I see the message "server is live..") and also when I send a message to my bot with the intent "MyIntent" I get no error, but also no response..
If I look at the Diagnostic Info, under the Fulfillment Status there is this error:
Webhook call failed. Error: DEADLINE_EXCEEDED.
What am I doing wrong?

I don't know how that google library is supposed to work, but generally when using express, you most close the HTTP request by sending a response, there are several examples here
https://expressjs.com/en/guide/routing.html
You could try adding this after convo.ask
res.sendStatus(200);

Related

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client - Node.Js, Express, Postgres

I'm having trouble with the error message in the title when trying to retrieve all users in my express .get('/users') method. I am using Node.js, Express, and node-postgres. I have my
getUsers(); function defined in my queries.js file, and I call the function in my app.get() function in my index.js file.
queries.js
const client = require('./object models/db_client_pool')
const Pool = require('pg').Pool
const pool = new Pool(client.client)
async function getUsers(request, response) {
await pool.connect()
pool.query('select * from discord_users', (error, results) => {
if (error) {
throw error
}
response.sendStatus(200).json(results.rows)
pool.release();
})
}
module.exports = {
getUsers
}
index.js
const express = require('express');
require('dotenv').config();
//const bodyParser = require('body-parser'); deprecated
const app = express();
const port = 3000;
const db = require('./queries');
app.use(express.json())
app.use(express.urlencoded({
extended: true
}))
app.get('/', (request, response) => {
response.json({ info: 'Node.js, Express, and Postgres API' })
})
app.get('/users', (req, res) => {
db.getUsers(req, res)
})
app.listen(port, () => {
console.log(`App is listening on port ${port}`);
});
As I said, I keep getting the "cannot set headers after they are sent to the client" error and I'm at a loss of what to do. Thanks in advance for your help!
Change from this:
response.sendStatus(200).json(results.rows)
to this:
response.status(200).json(results.rows);
or even just to this:
response.json(result.rows); // 200 is the default status already
The last one is fine because 200 is already the default status so you don't need to set that yourself.
The problem is that response.sendStatus(200) sends a complete response with an empty body and then you try to call response.json(result.rows) which tries to send ANOTHER response to the same request. Trying to send that second response to the same request is what triggers the error message you are getting.
response.status(200) just sets the status to 200 as a property on the waiting response object and waits for some other method to actually send the response itself which you can then do with .json(...).
So my guess is, you're running express 4.x and that doesn't support response.sendStatus(200) anymore. You have to use response.status(200) instead.
Now, another issue I see in your code is, I don't recognize pool.release() method from pg library. You can release a client back to a pool but you can't release a pool of clients. Maybe you meant pool.end()?

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

Twilio statusCallback implementation running into trouble

I am a beginner to Twilio. I understand that I can get the status of the SMS send by having a statusCallback, so that the POST will happen to the callbackurl with the status of the message. But I am having troubles in creating that particular POST endpoint.
Here is what I have :
// Twilio API CALL
client.sendMessage({
to:userId,
from: metadata.myTwilioNumber,
body: message,
StatusCallback:'POST URL'
}, function(err, responseData) {
if (!err) {
} else {
logger.info(err);
}
My POST endpoint is a simple node js (request, response) endpoint.
var server = http.createServer ( function(request,response){
response.writeHead(200,{"Content-Type":"text\plain"});
if(request.method == "GET")
{
response.end("received GET request.")
}
else if(request.method == "POST")
{
console.log(request.CallStatus);
console.log(response);
console.log('receivedRequest');
response.end("received POST request.");
}
else
{
response.end("Undefined request .");
}
});
server.listen(4445);
Can someone help me in getting the status and messageID of the response? Currently, the POST is getting invoked but i am unable to get the message details and status.
Twilio developer evangelist here.
You are using the basic Node.js standard library http module which is going to make it a lot of work to extract the information from the POST request. Can I recommend you try something like express with body-parser instead.
You can do so by installing the two modules with npm:
npm install express body-parser
Then you can rewrite your incoming message application like this:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/', (req, res) => {
console.log(req.body.CallStatus);
res.sendStatus(200);
});
app.listen(4445, () => {
console.log('Application running on localhost:4445');
});
All the parameters that Twilio sends will be available on the req.body object.
Check out this tutorial on receiving SMS messages with Twilio in Node for a bit more detail.

how to reply message from web demo on dialogflow via webhook

I'm currently trying to add chatbot to my website.
I'm integrating web demo on the agent used for our lIne bot.
which some responses are handled by lambda webhook.
what I'm asking is can we send responses to web demo using lambda?
if can, then how do I send them?
there suppose to be some id right? and do we use HTTP post request to send them?
I couldn't find an example.
and for some intent which has more than one response handled by dialogflow it can only send one of them.
why is that? and what should I do so that I can send all of them via dialogflow?
Yes, it can be achieved and you can refer to give NodeJs code for that,
const express = require("express");
const bodyParser = require("body-parser");
const apiai = require("apiai");
const request = require("request");
const app = express();
app.use(bodyParser.json());
app.set("port", process.env.PORT || 5000);
app.post("/", (req, res) => {
//console.log(req.body)
const action = req.body.result.action;
if (!req.body || !req.body.result || !req.body.result.parameters) {
return res.status(400).send("Bad Request");
}
console.log("--------------------------------");
console.log("Action =>", action);
console.log("--------------------------------");
switch (action) {
case "price.search":
const webhookReply = `Sorry NO book found in store.`;
res.status(200).json({
source: "webhook",
speech: webhookReply,
displayText: webhookReply
});
break;
default:
break;
}
});
app.listen(app.get("port"), function() {
console.log("* Webhook service is listening on port:" + app.get("port"));
});
For every intent, there will be an action of that we have to define in dialogFlow.
So when the user enters any query your webhook will get triggered it will
go in the switch case to find the particular action and form that case you can send back the replay to your bot.

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