Custom Dialogflow Fulfillment response - dialogflow-es

I am trying to return an object as a response from Dialogflow fulfillment.
I wanted to return some object to be handled later by my front end but I am getting an error:
Error: Unknown response type: "{"fruit1": "apple", "fruit2":
"orange"}";
It's likely that I may be doing it wrong. Here's the code that I have, problem is on function intent1f.
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 intent1f(agent) {
var someObject = {"fruit1": "apple",
"fruit2": "orange"};
agent.add(someObject);
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('intent1', intent1f);
// intentMap.set('your intent name here', googleAssistantHandler);
agent.handleRequest(intentMap);
});
Is there a way where I can return an object / self defined json via Dialogflow Fulfillment? agent.add() seems to only accept strings but I may be wrong.

function intent1f(agent) {
var someObject = {
"fruit1": "apple",
"fruit2": "orange"
};
agent.add(JSON.stringify(someObject));
}
On your client side you can use JSON.parse() to have same object.

Related

How to get data from firebase Realtime database to Dialogflow chatbot

I was trying to create a chatbot in Dialogflow es. I want, when the user ask chatbot to show Board id it will read data from firebase Realtime database and show that data to the user.
I have tried this way:-
'use strict';
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const firebaseAdmin = require("firebase-admin");
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
firebaseAdmin.initializeApp({
credential:firebaseAdmin.credential.applicationDefault(),
databaseURL:"https://***************.firebaseio.com",
});
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 akvo agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function getFromFirebase(agent){
return firebaseAdmin.database().ref('board_id').once("value").then((snapshot) => {
var boardid = snapshot.val();
agent.add(boardid);
});
}
// 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('board id', getFromFirebase);
agent.handleRequest(intentMap);
});
After deploying this code I got an error.
Error:-"Webhook call failed. Error: DEADLINE_EXCEEDED, State: URL_TIMEOUT, Reason: TIMEOUT_WEB."
Please tell me how can I solve this.

Stripe webook signature verification failed using express

Hey stack overflow so I am using webooks with stripe. For some reason I am getting the error "Stripe webook signature verification failed". Here is my source code below. Any ideas on how I can get it working? I know it has something to do with the bodyparser. But I am not able to figure out a workaround to get the stripe webhooks working.
Error Message:
Webhook signature verification failed. No signatures found matching the expected signature for payload. Are you passing the raw request body you received from Stripe? https://github.com/stripe/stripe-node#webhook-signing
require("dotenv").config();
const express = require("express");
var cors = require('cors')
const axios = require("axios");
const bodyParser = require("body-parser");
const Stripe = require('stripe');
const stripe = Stripe('sk_test_4eC39HqLyjWDarjtT1zdp7dc');
const invoiceDescription = require('./constants');
const endpointSecret = "whsec_w5Qipi3Wz0fm8sSCHcJIHwWfobS0kfYe";
const { TOKEN, SERVER_URL, BOTTOKEN } = process.env;
const TELEGRAM_API = `https://api.telegram.org/bot${TOKEN}`;
const URI = `/webhook/${TOKEN}`;
const WEBHOOK_URL = SERVER_URL + URI;
const app = express();
app.use(cors());
app.use(bodyParser.json());
const init = async () => {
const res = await axios.get(`${TELEGRAM_API}/setWebhook?url=${WEBHOOK_URL}`);
console.log(res.data);
};
app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
let event = request.body;
// Only verify the event if you have an endpoint secret defined.
// Otherwise use the basic event deserialized with JSON.parse
if (endpointSecret) {
// Get the signature sent by Stripe
console.log(request.headers)
const signature = request.headers['stripe-signature'];
try {
event = stripe.webhooks.constructEvent(
request.body,
signature,
endpointSecret
);
} catch (err) {
console.log(`⚠️ Webhook signature verification failed.`, err.message);
return response.sendStatus(400);
}
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`);
// Then define and call a method to handle the successful payment intent.
// handlePaymentIntentSucceeded(paymentIntent);
console.log('payment intent is', paymentIntent)
break;
case 'payment_method.attached':
const paymentMethod = event.data.object;
// Then define and call a method to handle the successful attachment of a PaymentMethod.
// handlePaymentMethodAttached(paymentMethod);
console.log('payment method is', paymentMethod)
break;
default:
// Unexpected event type
console.log(`Unhandled event type ${event.type}.`);
}
// Return a 200 response to acknowledge receipt of the event
response.send();
});
app.post(URI, async (req, res) => {
let text = "", chatId = "", userObjectForTable = {};
if(req.body.message?.chat?.id && req.body.message?.text && req.body.message?.text === "Start"){
chatId = req.body.message.chat.id;
text = invoiceDescription;
const message = await axios.post(`${TELEGRAM_API}/sendMessage`, {
chat_id: chatId,
text: text,
reply_markup: {
inline_keyboard: [[{
text: 'Pay $65.00',
web_app: {url: 'https://buy.stripe.com/test_14kbKj3Gd0AGeRi7ss' }
}]]
}
});
}
return res.send();
});
app.listen(process.env.PORT || 5050, async () => {
console.log("🚀 app running on port", process.env.PORT || 5050);
await init();
});

How to integrate Dialogflow to my discord bot along with contexts and followup intents in Node js

I made a fully well functioning chatbot using dialogflow now I wanted to integrate it to my discord bot. I followed a youtube video which integrated only the intents but I couldn't figure out how to do with contexts and follow up intents.
const Discord = require('discord.js');
const client = new Discord.Client();
require('dotenv').config();
const token = process.env.DISCORD_TOKEN;
process.env.GOOGLE_APPLICATION_CREDENTIALS = `${process.env.PWD}/${process.env.REPL_SLUG}/config.json`
const dialogflow = require('#google-cloud/dialogflow');
const uuid = require('uuid');
client.once('ready', () => console.log('ready!'));
async function replyMsg(textMsg) {
projectId = process.env.PROJECT_ID;
// A unique identifier for the given session
const sessionId = uuid.v4();
// Create a new session
const sessionClient = new dialogflow.SessionsClient();
const sessionPath = await sessionClient.projectAgentSessionPath(
projectId,
sessionId
);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: textMsg,
// The language used by the client (en-US)
languageCode: 'en-US',
},
},
};
// 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.`);
}
return await result.fulfillmentText;
}
client.on('message', (message) => {
console.log(message.author.bot);
if (!message.author.bot) {
if (message.mentions.has('784734506812833792'))
replyMsg(message.content).then((res) => {
console.log(res);
message.channel.send("<#" + message.author.id + ">" + ' ' + res);
});
}
});
client.login(token);
instead of this
const sessionId = uuid.v4();
Use user wise Session for contexts and follow up intents
like...
const sessionId = Userid;

What is the proper way to send a response form dialogflow from nodejs webhook?

I'm new to dialogflow and I've been trying to send a response from a nodejs webhook to my DF bot when a record has been added to a firestore DB. I've been searching a lot and I couldn't find either examples or docs that could help me understand.
This is the cloud function that performs the above:
const functions = require('firebase-functions');
const mysql = require('mysql');
const promise_mysql = require('promise-mysql');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug';
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.dialogflowFirebaseFulFillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Request headers: ' + JSON.stringify(request.headers));
console.log('Request body>>>>>>>> ' + JSON.stringify(request.body));
const parameters = request.body.queryResult.parameters;
db.collection('reservations').add(parameters).then(() => {
agent.add("Room reversed!")
}).catch((e => {
agent.add('Something went wrong!!!!!')
}))
});
// Other stuff
The issue (I think) is this part:
db.collection('reservations').add(parameters).then(() => {
agent.add("Room reversed!")
}).catch((e => {
agent.add('Something went wrong!!!!!')
}))
It adds the record perfectly but I can't get the dialogflow response to be shown as none of the options: agent.add("Room reversed!"), agent.add('Something went wrong!!!!!')
What am I missing? Thanks.
Method1:
exports.dialogflowFirebaseFulFillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Request headers: ' + JSON.stringify(request.headers));
console.log('Request body>>>>>>>> ' + JSON.stringify(request.body));
const parameters = request.body.queryResult.parameters;
db.collection('reservations').add(parameters).then(() => {
agent.add("Room reversed!")
// Other stuff
}).catch((e => {
agent.add('Something went wrong!!!!!')
// Other stuff
}))
});
Method2:
exports.dialogflowFirebaseFulFillment = functions.https.onRequest(async (request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Request headers: ' + JSON.stringify(request.headers));
console.log('Request body>>>>>>>> ' + JSON.stringify(request.body));
const parameters = request.body.queryResult.parameters;
try {
await db.collection('reservations').add(parameters)
agent.add("Room reversed!")
} catch (error) {
agent.add('Something went wrong!!!!!')
}
// Other stuff
});

How to deal with the different type of errors that returns from the cloud function?

I have written the cloud functions which sends the response either with the statuscode 200 or 400 but sometimes I am getting this error
Function execution took 219 ms, finished with status: 'connection error'
Error: function crashed out of request scope Function invocation was interrupted.
So the problem is I need to know send this error message with some statuscode as the response of the cloud function.
const functions = require('firebase-functions');
const dialogflow = require('dialogflow');
const admin = require('firebase-admin');
const Firestore = require('#google-cloud/firestore');
const firestore = new Firestore();
admin.initializeApp();
var db = admin.firestore();
const {WebhookClient} = require('dialogflow-fulfillment');
var UID = new Object();
exports.fulfillmenttext = functions.https.onRequest((req,res) =>{
const answer1 = req.body.Text;
const uid = answer1.substring(0,28);
const answer = answer1.substring(28);
const sessionId = uid;
var count,questvalue;
const promise = db.collection("***").doc('***').collection("**").doc("uid").get();
promise.then(doc => {
snapshot.forEach(function(doc) {
if (doc.exists) {
count = doc.data().count;
if(count == 1){
var updatequest = title[questvalue];
res.status(200).send({"question":updatequest,"question_number":questvalue});
return;
}
else{
runSample();
}
}
else {
console.log("No such document!");
}
});
}).catch(function(error) {
console.log("Error getting document:", error);
});
async function runSample() {
const languageCode = 'en-US';
const projectId = 'xxxxxxx';
const credentials = {
client_email: 'xxxxxxx',
private_key:
'xxxxxxx',
};
//Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient({
projectId,
credentials,
});
// Define session path
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
//session: context1,
session: sessionPath,
queryInput: {
text: {
text: answer,
languageCode,
},
},
};
const responses = await sessionClient.detectIntent(request);
const result = responses[0].queryResult;
let action = result.action;
if (result.intent) {
const question = result.fulfillmentText;
console.log("question is",question);
const actionHandlers = {
'early': () => {
console.log('earlyaction1', action);
let name1 = JSON.stringify(result.parameters.fields.Name.stringValue);
name1 = name1.toString().replace(/"/g,"");
var data1 = {
Name: name1
};
var setDoc1 = admin.firestore().collection('**').doc('uid').collection("***").doc('uid').collection('**').doc('**').update(data1);
},
};
if (action === 'early') {
console.log('1');
actionHandlers[action]();
}
res.status(200).send({"question":result.fulfillmentText,"action":action,"question_number":title.indexOf(question)});
} else {
console.log(` No intent matched.`);
res.status(400).send({"action":"empty"});
}
}
});
That message is telling you that you have some async code that was still running after the function terminated normally by sending a response to the client. That bit of async code crashed. Since the function already terminated by sending a response, there's nothing you can do to send another response. There can only be one response per function invocation.
What you'll have to do is review your code and make sure you're 1) handling promises correctly and 2) not intentionally trying to leave any work going after sending the response, since Cloud Functions does not support that.

Resources