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?
Related
So I'm trying to learn nodeJS.. But something wierd is happening. When I try to make a GET or a POST request it keep requesting infinitly on the localhost. I tested with a simple piece of code just requesting a simple Hello Word but it still doesnt works. It was working perfectly yesterday.
I tested insomnia, postman and the browser. If someone can help me would be very nice, cause I'm really stucked here...printscream of the insomnia infinity request
const {json} = require('express');
const express = require('express');
const {uuid} = require('uuidv4');
const app = express();
app.use(express,json);
const projects = [];
app.get('/projects', (request, response) => {
return response.json(projects);
});
app.post('/projects', (request, response) => {
const {title, owner} = request.body;
const project = {id: uuid(), title, owner };
projects.push(project);
return response.json(project);
});
app.listen(3333, () => {
console.log('Working 👏👏')
});
It's just two little mistakes. Take in mind that express.json() is a method, so you need to put it like this:
app.use(express.json())
You are using a comma instead of a point. However, you have done a destructuring of the .json () method; therefore, you do not have to prepend express; it would look like this:
app.use(json())
On the other hand, you probably have an unwanted result in the post request since you send the project variable instead of projects. Be sure that is what you want.
I can successfully get a query param and post it into my realtime database at a path defined by the query param itself, using this code:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.emptyHat = functions.https.onRequest(async (req, res) => {
// Grab the group parameter.
const group = req.query.group;
// Push the new message into the Realtime Database using the Firebase Admin SDK.
const snapshot = await admin.database().ref('/group').push({list: group});
// Redirect with 303 SEE OTHER to the URL of the pushed object in the Firebase console.
res.redirect(303, snapshot.ref.toString());
});
If the query param was 'test', the result would be a new entry at /test/{firebaseID}/{'list':'test'}
When I tried to modify it to remove the node named in the query parameter I get errors.
(I'm trying to remove that top level /test node
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.emptyHat = functions.https.onRequest(async (req, res) => {
// Grab the group parameter.
const group = req.query.group;
// Remove the node at the location 'group'.
functions.database().ref('/group').remove();
// Redirect with 303 SEE OTHER to the URL of the pushed object in the Firebase console.
//res.redirect(303, snapshot.ref.toString());
});
Error message in the logs:
at exports.emptyHat.functions.https.onRequest (/srv/index.js:95:13)
at cloudFunction (/srv/node_modules/firebase-functions/lib/providers/https.js:49:9)
at /worker/worker.js:783:7
at /worker/worker.js:766:11
at _combinedTickCallback (internal/process/next_tick.js:132:7)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
Your second function is ignoring the promise returned by the Firebase API. This makes it unlikely to work in Cloud Functions. Cloud Functions HTTP triggers require that you only send a response only after all the asynchronous work is complete. After your function generates a response, it will terminate and clean up any async work still in progress. That work might not complete.
Your second function should be more like your first one, and use the promise returned by remove() and wait for it to complete before sending the response:
exports.emptyHat = functions.https.onRequest(async (req, res) => {
const group = req.query.group;
await admin.database().ref('/group').remove();
// send the response here.
});
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
});
}
});
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;
});
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.