Dialogflow fulfilment : agent.add() not returning response to webhook (twilio), works good with dialogflow console and google assistant - javascript

I'm creating a chatbot using dialogflow, firebase and twilio on Whatsapp. The interaction works well using the responses from the Intents and using the inline editor function, writes data to the firebase database too. But when I try to return the response from the fulfilment inline editor using the agent.add() method the responses are shown only in the dialogflow console interaction (and the google assistant as well), but not in the Twilio-whatsapp webhook integration. The logs in the GCP show that the data is being read when a request is made from using a text from twilio-whatsapp number.
I just want that the agent.add() text to be returned to twilio message body.
Or if there is some other possible way to do it, so that I can generate dynamic responses based on the data being read from the database.
Response in Dialogflow console
The code in my inline editor.
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 admin = require("firebase-admin");
const { WebhookClient } = require("dialogflow-fulfillment");
process.env.DEBUG = "dialogflow:debug"; // enables lib debugging statements
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(
(request, response) => {
const agent = new WebhookClient({
request,
response,
});
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function saveUserDataHandler(agent) {
const firstname = agent.parameters.firstname;
const lastname = agent.parameters.lastname;
const phoneno = agent.parameters.phonenumber;
const dialogflowAgentRef = db.collection("users").doc();
return db
.runTransaction((t) => {
t.set(dialogflowAgentRef, {
firstname: firstname,
lastname: lastname,
phoneno: phoneno,
});
return Promise.resolve("Write complete");
})
.then((doc) => {
agent.add(
` Wrote "${firstname} ${lastname}, ${phoneno}" to the Firestore database.`
);
console.log("wrote to db", firstname, lastname, phoneno);
})
.catch((err) => {
console.log(`Error writing to firestore : ${err}`);
agent.add(
` Failed to write "${firstname} ${lastname}, ${phoneno}" to the Firestore database.`
);
});
}
function readUserDataHandler(agent) {
const dialogflowAgentDoc = db.collection("users");
return dialogflowAgentDoc
.get()
.then((snapshot) => {
snapshot.forEach((doc) => {
if (!doc.exists) {
agent.add("No Data found in the database");
} else {
agent.add(doc.data().firstname);
agent.add(doc.data().lastname);
agent.add(doc.data().phoneno);
console.log(doc.data());
}
return Promise.resolve("Read complete");
});
})
.catch((err) => {
agent.add("Error reading entry from the Firestore database.");
console.log(err);
});
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
// 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("Get User Data", saveUserDataHandler);
intentMap.set("Read User Data", readUserDataHandler);
agent.handleRequest(intentMap);
}
);
package.json
{
"name": "dialogflowFirebaseFulfillment",
"description": "This is the default fulfillment for a Dialogflow agents using Cloud Functions for Firebase",
"version": "0.0.1",
"private": true,
"license": "Apache Version 2.0",
"author": "Google Inc.",
"engines": {
"node": "8"
},
"scripts": {
"start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
"deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
},
"dependencies": {
"actions-on-google": "^2.5.0",
"dialogflow": "^4.0.3",
"dialogflow-fulfillment": "^0.6.1",
"firebase-admin": "^6.4.0",
"firebase-functions": "^2.1.0"
}
}
Links referred : fulfillment-firestore-nodejs, updating dependencies
In the twilio debugger I get a response that the message body is invalid.
MESSAGE
Message body must be specified
Invalid Body
Warning - 14103
Message Invalid Body
The Message body does not contain valid text or a media URL
Something mentioned here too, but the comments there didn't help.
Am I missing something, or is it a bug as others are facing it too??
Thanks in advance.

Related

Transaction failure while testing firebase firestore

I am trying to write some tests for the cloud functions I have written, but I am facing a problem where a transaction never succeeds and ends up in an error:
9 FAILED_PRECONDITION: the stored version (1648901730789554) does not match the required base version (0)
Problematic code is the following:
await firebase.db().runTransaction((t) => {
return t.get(docRef).then((doc) => {
if (!doc.exists) {
console.log("no exist");
}
});
});
It is run several times (checked with debugger), and then the error messages is thrown...
And the firebase test env init:
export async function initialize() {
fb.initializeTestApp({
projectId: "my-test-project",
auth: { uid: "alice", email: "alice#example.com" }
});
const testEnv = await initializeTestEnvironment({
projectId: "demo-project-1234",
firestore: {
rules: fs.readFileSync("../firestore.rules", "utf8"), // Load rules from file
// host and port can be omitted if they can be discovered from the hub.
},
});
const alice = testEnv.authenticatedContext(uid);
const db = (alice.firestore() as unknown) as firestore.Firestore;
firebase.db = () => db;
return testEnv;
}
Am I doing something wrong?
Note: I currently have only one test that runs, nothing else. And firebase emulators are running, without any other app accessing it.
After some more research, I have figured out that I was mixing #firebase/testing and firebase-admin, and the matter should not be used for unit testing backend functions according to this post.
On a side note, it seems there already is a function to create a doc iff it does not exist:
docRef.create(...).then(() => log("ok")).catch(() => log("Not ok"))

Pub Sub Cloud Function - Async Await

Trying to accomplish the following via a scheduled Firebase Function:
Fetch Firestore Collection
Delete Collection
Make Get Request to External API
Write Get Request results to Firestore Collection.
The function is failing to deploy. Error logs only say {"code":3,"message":"Function failed on loading user code. This is likely due to a bug in the user code.
When I run the emulator suite locally, I get no errors, but the DB does not update.
I'm getting a linting error on the "=>" that's attached to the "onRun" method. Not sure if this is a code problem or an ESLint problem for ES6 in Firebase Functions.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const axios = require('axios');
admin.initializeApp();
const db = admin.firestore();
exports.scheduledFunction = functions.pubsub
.schedule("every 2 minutes")
.timeZone("America/New_York")
.onRun(async (context) => {
try {
const querySnapshot = await db.collection("my_collection").get();
console.log(querySnapshot.docs)
const promises = querySnapshot.docs.map(doc => db.collection("my_collection").doc(doc.id).delete());
await Promise.all(promises);
const options = {
"method": "get",
"url": "www.myUrl.com",
"headers": {
"Cookie": "...",
},
};
const axiosResponse = await axios(options);
const apiResponse = JSON.parse(axiosResponse.data);
const parsedResponse = apiResponse["news_results"];
const docCreationPromises = parsedResponse.map(response => db.collection("my_collection").add(parsedResponse))
await Promise.all(docCreationPromises);
return null;
} catch (error) {
console.log(error);
return null;
}
});
For the ESLint issue with =>, try setting the ecmaVersion to 8 in your ESLint config.
module.exports = {
root: true,
env: {
es6: true,
node: true,
},
extends: [
"eslint:recommended",
"google",
],
parserOptions: {
ecmaVersion: 8
}
};
When I run the emulator suite locally, I get no errors, but the DB does not update.
Are you using Firestore emulator? If yes, then data will be added there and not in production so you can see the data in emulator only.

Getting firestore data from a Google Cloud Function with array-contains-any

A web page calls a Firebase function that should get several records from a Firestore collection, Everything runs without error but no data is returned. When I run the query in the page directly (not via the function), the right data is returned.
In the web page:
var getUserConfigFiles = firebase.functions().httpsCallable('getUserConfigFiles');
getUserConfigFiles()
.then((result) => {
console.log("Yay - Firebase result ===>",result);
})
.catch((error) => {
console.warn("error",error.code,error.message,error.details)
});
In index.js:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const cors = require('cors')({origin: true});
const db = admin.firestore();
Then the function itself:
exports.getUserConfigFiles = functions.https.onCall((data, context) => {
if (!context.auth) {
return {"status": "error", "code": 499, "message": "The function must be called while authenticated"};
}
const uid = context.auth.uid;
const email = context.auth.token.email;
var outcome = {"status": "OK", "code": 200, "requestor": uid, "email": email, "configfiles":[]};
// search on either the user's userid or their email
outcome.searcharray = [uid];
if (email) {
outcome.searcharray.push(email);
}
return db.collection("configfiles").where("memberAttached", "array-contains-any", outcome.searcharray)
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
outcome.configfiles.push({"tokenid": doc.id, "data-all": doc.data()});
})
// next row is returning the object just to see if it's there
outcome.querySnapshot = querySnapshot;
//
return (outcome);
})
.catch((error) => {
return ({"status": "error", "code": 402, "message": error,"requestor": uid});
});
});
Everything works, the result returns a querySnapshot. Except, there is no data, .configfiles should have a hundred or so rows. If I run the db.collection("configfiles").where("memberAttached... portion just in the web page, data is returned.
I have searched and tried many approaches but I'm obviously missing something fundamental. Can anyone help?
I'd suspect the outcome.querySnapshot = querySnapshot line is causing problems, as querySnapshot is not a JSON object and thus can't be returned. I recommend removing that line, and trying again.
If that doesn't solve the problem, can you add some logging, and see if the code ever reaches inside the then?

Discord.JS | Music Bot "Error: Video Unavailable"

I'll list the command logic itself and all installed dependencies below. Basically, whenever I run the command in Discord with any youtube link I've given it so far, the bot joins and everything runs correctly but then shortly after, the bot errors out in VSC with the error "Video Unavailable". I've looked through all kinds of forums and watched a lot of videos and I can't find any solution at all.
Play Command Logic:
if (musicArgs.startsWith('play')) {
let musicPlayPrefix = 'play';
let musicPlayArgs = musicArgs.slice(musicPlayPrefix.length).trim();
if (message.member.voice.channel) {
const connection = await message.member.voice.channel.join();
const dispatcher = connection.play(await ytdl(musicPlayArgs), { type: 'opus'})
dispatcher.on('error', console.error);
dispatcher.on('start', () => {
message.channel.send(`**Now Playing:** *${musicPlayArgs}`);
});
dispatcher.on('finish', () => {
message.channel.send(`**Music Finished!**`);
});
}
else {
message.channel.send(`You're not in a voice channel! Retry the command inside of one.`);
}
}
Dependencies in Package.json:
"dependencies": {
"#discordjs/opus": "github:discordjs/opus",
"discord.js": "^12.3.1",
"ffmpeg-static": "^4.2.7",
"hypixel-api-reborn": "^2.2.4",
"libsodium-wrappers": "^0.7.8",
"ytdl-core-discord": "git+https://github.com/amishshah/ytdl-core-discord.git"
}

Firebase functions.auth.user().onCreate no triggering

i am trying create user with custom claim. I am using Firebase Cloud Functions. The problem is, when i create (Sign Up) an user, the onCreate not trigger. I am following this tutorial of provided by google. https://firebase.google.com/docs/auth/admin/custom-claims
I Deployed my functions and the region is us-central1
Cloud functions version :
firebase-admin": "^8.9.0
firebase-functions": "^3.3.0
I am using Vue JS as Front-end
My functions/Index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.ProccessSignUp = functions.auth.user().onCreate(async (user) =>{
console.log("Email"+user.email);
if (user.email){
const customClaims = {
admin:true
};
return admin.auth().setCustomUserClaims(user.uid,customClaims)
.then(() =>{
const metadataRef = admin.database().ref('metadata/' +user.uid);
return metadataRef.set({refeshTime:new Date().getTime()})
}).catch(err =>{
console.log(err.message)
})
}
});
My SignUpWithEmailAndPassword
userSignUp({dispatch},payload){
firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
.then(user =>{
user.user.sendEmailVerification()
.then(() =>
alert('Your account has been created! Please, verify your account'),
dispatch('userSignOut'),
).catch(err =>{
console.log(err.message)
})
}).catch(err =>{
console.log(err.message)
})
},
oAuthStateChanged
router.beforeEach(async (to, from, next) => {
const user = await new Promise((resolve) => {
firebase.auth().onAuthStateChanged(async user => {
await store.dispatch("autoSignIn", user);
resolve(user)
});
});
const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
if (requiresAuth) {
if (!user){
next(false)
}else {
if (user.emailVerified){
next();
}else {
alert('Please verify your account')
await store.dispatch("userSignOut", user);
}
}
} else {
next()
}
});
As explained in the doc, with Cloud Functions you can "emit a log line from your function, use standard JavaScript logging calls such as console.log and console.error".
Then the Cloud Functions logs are viewable either in the Firebase console, Stackdriver Logging UI, or via the firebase command-line tool.
So you should be able to confirm that your Cloud Function runs correctly (or not) by looking at, for exemple, the Firebase console.
I had the same situation while running cloud funtions locally. My user().onCreate() trigger function was also not triggering.
export const addNewUser = auth
.user()
.onCreate((user) => {
// Do something
})
I tried many things but everything was looking fine. Finally I updated my firebase-tools to latest version by running this command and it started working as a charm.
npm install -g firebase-tools#latest
Hope this helps someone.

Categories

Resources