How to create tables in firebase with api.ai - dialogflow-es

I have a question for dialogflow. I want to know if it's possible to have the agent create new fields or tables in the firebase database (firestore or realtime) All the code I find is about changing the values ​​of a table and not creating them.
I do not know where to start, I've done integrations with the server and everything is working.
function writeToDb (agent) {
const databaseEntry = agent.parameters.databaseEntry;
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
I need a explication to create new tables or fields by the agent

Google's Dialogflow Firestore sample on Github demonstrates how to connect Dialogflow to the Firestore database.
Check out the writeToDb() function below, and remember to require the same dependencies:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // 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 writeToDb (agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Wrote "${databaseEntry}" to the Firestore database.`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${databaseEntry}" to the Firestore database.`);
});
}
function readFromDb (agent) {
// Get the database collection 'dialogflow' and document 'agent'
const dialogflowAgentDoc = db.collection('dialogflow').doc('agent');
// Get the value of 'entry' in the document and send it to the user
return dialogflowAgentDoc.get()
.then(doc => {
if (!doc.exists) {
agent.add('No data found in the database!');
} else {
agent.add(doc.data().entry);
}
return Promise.resolve('Read complete');
}).catch(() => {
agent.add('Error reading entry from the Firestore database.');
agent.add('Please add a entry to the database first by saying, "Write <your phrase> to the database"');
});
}
// Map from Dialogflow intent names to functions to be run when the intent is matched
let intentMap = new Map();
intentMap.set('ReadFromFirestore', readFromDb);
intentMap.set('WriteToFirestore', writeToDb);
agent.handleRequest(intentMap);
});

Related

My onCreate funciton in Functions of firebase is not creating my desired collection in the cloud database

I just typed a code in my index.js file of functions (firebase CLI).According to my code there must be a timeline collection created in cloud database of firebase.Function is healthy and there are no errors it gets deployed and even in the logs everything works fine. But still timeline collection is not created in the cloud databaese when I follow a user in my app.
this is my code:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.onCreateFollower = functions.firestore
.document("/followers/{userId}/userFollowers/{followerId}")
.onCreate(async (snapshot, context) => {
console.log("Follower Created", snapshot.id);
const userId = context.params.userId;
const followerId = context.params.followerId;
// 1) Create followed users posts ref
const followedUserPostsRef = admin
.firestore()
.collection("posts")
.doc(userId)
.collection("userPosts");
// 2) Create following user's timeline ref
const timelinePostsRef = admin
.firestore()
.collection("timeline")
.doc(followerId)
.collection("timelinePosts");
// 3) Get followed users posts
const querySnapshot = await followedUserPostsRef.get();
// 4) Add each user post to following user's timeline
querySnapshot.forEach(doc => {
if (doc.exists) {
const postId = doc.id;
const postData = doc.data();
return timelinePostsRef.doc(postId).set(postData);
}
});
});
Since you want to execute a variable number of asynchronous calls in parallel, you should use Promise.all(), in order to wait that all these different asynchronous calls are completed before indicating to the CF platform that it can cleanup the CF. See https://firebase.google.com/docs/functions/terminate-functions for more details.
exports.onCreateFollower = functions.firestore
.document("/followers/{userId}/userFollowers/{followerId}")
.onCreate(async (snapshot, context) => {
const userId = context.params.userId;
const followerId = context.params.followerId;
// ...
// 3) Get followed users posts
const querySnapshot = await followedUserPostsRef.get();
// 4) Add each user post to following user's timeline
const promises = [];
querySnapshot.forEach(doc => {
//query results contain only existing documents, the exists property will always be true and data() will never return 'undefined'.
const postId = doc.id;
const postData = doc.data();
promises.push(timelinePostsRef.doc(postId).set(postData));
});
return Promise.all(promises);
});

Firestore: scheduled export

I have used the code from the Firebase documentation to schedule a backup of the data in my Firestore project in a bucket every 6 hours. See the link and the code here:
https://firebase.google.com/docs/firestore/solutions/schedule-export
const functions = require('firebase-functions');
const firestore = require('#google-cloud/firestore');
const client = new firestore.v1.FirestoreAdminClient();
// Replace BUCKET_NAME
const bucket = 'gs://BUCKET_NAME';
exports.scheduledFirestoreExport = functions.pubsub
.schedule('every 24 hours')
.onRun((context) => {
const projectId = process.env.GCP_PROJECT || process.env.GCLOUD_PROJECT;
const databaseName =
client.databasePath(projectId, '(default)');
return client.exportDocuments({
name: databaseName,
outputUriPrefix: bucket,
// Leave collectionIds empty to export all collections
// or set to a list of collection IDs to export,
// collectionIds: ['users', 'posts']
collectionIds: []
})
.then(responses => {
const response = responses[0];
console.log(`Operation Name: ${response['name']}`);
})
.catch(err => {
console.error(err);
throw new Error('Export operation failed');
});
});
Everything works well, my data is saved like I want to but nevertheless I am getting an error:
Error serializing return value: TypeError: Converting circular structure to JSON
Can someone tell me what I should change? Would be glad to get a hint.

saving data in conversations with Actions on Google

I am developing an app on Actions on Google and I've noticed that when using the Dialogflow Fulfillment library I can't save data between conversations.
Here is the code using the WebhookClient:
const { WebhookClient, Card, Suggestion } = require('dialogflow-fulfillment');
exports.aog_app = functions.https.onRequest((request, response)=>{
let agent = new WebhookClient({request, response});
let intentMap = new Map();
intentMap.set('Default Welcome Intent', (agent)=>{
agent.add("hello there!") ;
});
intentMap.set('presentation', (agent)=>{
let conv = agent.conv();
let counter = conv.data.counter;
console.log("counter", counter)
if(counter){
conv.data.counter = counter+1;
}else{
conv.data.counter = 1;
}
agent.add("counter is "+counter) ;
});
agent.handleRequest(intentMap)
});
counter remains undefined on each turn.
But when using the Action on Google Nodejs Library I can save data without issues:
const {
dialogflow,
SimpleResponse,
BasicCard,
Permission,
Suggestions,
BrowseCarousel,
BrowseCarouselItem,
Button,
Carousel,
DateTime,
Image,
DialogflowConversation
} = require('actions-on-google');
const app = dialogflow({debug: true});
app.intent('Default Welcome Intent', (conv)=>{
conv.ask("hello there!");
});
app.intent('presentation', (conv)=>{
let counter = conv.data.counter;
console.log("counter", counter)
if(counter){
conv.data.counter = counter+1;
}else{
conv.data.counter = 1;
}
conv.ask("counter is "+counter)
})
exports.aog_app = functions.https.onRequest(app);
counter is incremented on each turn.
Is there a way to save data between conversations using the Dialogflow fulfillment library?
you need to add the conv back to agent after you update the conv.data
agent.add(conv);
Google's Dialogflow team published a code sample showing how to implement data persistence by integrating Google Cloud's Firebase Cloud Firestore.
You can find the sample here: https://github.com/dialogflow/fulfillment-firestore-nodejs
This is (probably) the code you're looking for:
function writeToDb (agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Wrote "${databaseEntry}" to the Firestore database.`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${databaseEntry}" to the Firestore database.`);
});
}

Node.js cloud function "firestore set() inside get() if not exists" is not working correctly?

Here is I'm trying to achieve
if user is exist in firestore
show the data
else
add it to firestore
And following is my code
// 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 {WebhookClient} = require('dialogflow-fulfillment');
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
var db = admin.firestore();
const settings = {timestampsInSnapshots: true};
db.settings(settings);
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function save(agent) {
const usersRef = db.collection('users').doc('someid');
usersRef.get().then(function(doc) {
if(doc.exists) {
let existingUser = doc.data();
console.log("Document is already exists " + existingUser.userName);
agent.add('Hello ');
} else {
console.log("Document creation is started");
usersRef.set({
userName : 'somename'
});
agent.add('Welcome ');
}
}).catch(function(error) {
console.error("Error writing document: ", error);
agent.add('Failed to login!');
});
}
let intentMap = new Map();
intentMap.set('dialogflow-intent-name',save);
agent.handleRequest(intentMap);
});
But the execution of above code it starts the cloud function and terminated first and my chatbot doesn't get any response but after execution log is like
Function execution started
Function execution took 404 ms, finished
with status code: 200
"Document is already exists someusername"
DocumentReference.set returns a promise, and you are not waiting for it to finish. So it should work if you change your code from:
usersRef.set({
userName : 'somename'
});
... rest of the code
to
usersRef.set({
userName : 'somename'
}).then(result => {
... rest of the code
})

How to connect Dialogflow to Cloud Firestore via the Inline Editor in Dialogflow?

I have a Cloud Firestore database that stores the number of inhabitants of all cities in England in 2017.
Then I have a Dialogflow. Whenever I tell the name of a city to Dialogflow, I want it to get the number of inhabitants in that city from Firestore and return it to Dialogflow.
Specifically, I want to implement this via the Inline Editor.
Question: What lines of code do I need to add to the code below in order to make this happen?
So here is the code that I write in the Inline Editor in Dialogflow > Fulfillment > index.js:
'use strict';
const functions = require('firebase-functions');
const firebaseAdmin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
const App = require('actions-on-google').DialogflowApp;
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(`Hello and welcome!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
agent.handleRequest(intentMap);
});
Here is some sample code showing how to connect Firebase's Firestore database to Dialogflow fulfillment hosting on Firebase functions:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const {WebhookClient} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:*'; // 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 writeToDb (agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Wrote "${databaseEntry}" to the Firestore database.`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${databaseEntry}" to the Firestore database.`);
});
}
function readFromDb (agent) {
// Get the database collection 'dialogflow' and document 'agent'
const dialogflowAgentDoc = db.collection('dialogflow').doc('agent');
// Get the value of 'entry' in the document and send it to the user
return dialogflowAgentDoc.get()
.then(doc => {
if (!doc.exists) {
agent.add('No data found in the database!');
} else {
agent.add(doc.data().entry);
}
return Promise.resolve('Read complete');
}).catch(() => {
agent.add('Error reading entry from the Firestore database.');
agent.add('Please add a entry to the database first by saying, "Write <your phrase> to the database"');
});
}
// Map from Dialogflow intent names to functions to be run when the intent is matched
let intentMap = new Map();
intentMap.set('ReadFromFirestore', readFromDb);
intentMap.set('WriteToFirestore', writeToDb);
agent.handleRequest(intentMap);
});
This came from Dialogflow's Firestore sample located here: https://github.com/dialogflow/fulfillment-firestore-nodejs

Resources