Reputation: 11
So, i'm building a Chatbot for a school project, and i'm stuck. Basically my chatbot is asking some questions and getting some answers, and then what i wanted was to use those answers to match some data in the Cloud Firestore to return the correspondent information.
For example:
User: I want some coffee.
Bot: What kind? American, Italian, etc...
User: American.
Bot: Ok, and what itensity? Strong, weak, decaf?
User: Decaf.
Bot: So you want an American Decaf, then we have "put Blend here".
My FireStore DB Structure:
{
"coffee":
{
"blend":
{
"Arabica":[
{ "name": "Acaía", "intensityId": "decaf"},
{ "name": "Catuaí", "intensityId": "forte"},
{ "name": "Icatu", "intensityId": "fraco"}
],
"Italiano":[
{ "name": "Buon Giorno!", "intensityId": "forte"},
{ "name": "In Vetro", "intensityId": "fraco"},
{ "name": "Tazzina", "intensityId": "decaf"}
],
"Asiatico":[
{ "name": "Blend", "intensityId": "forte"},
{ "name": "Plantation", "intensityId": "fraco"},
{ "name": "Kaffa", "intensityId": "decaf"}
],
"Americano":[
{ "name": "Grande Intenso", "intensityId": "forte"},
{ "name": "Unwind", "intensityId": "fraco"},
{ "name": "Live for the Moment", "intensityId": "decaf"}
]
},
"intensity":{
"decaf": "Descafeínado",
"forte": "Forte",
"fraco": "Fraco"
},
"packs":
{
"decaf_pack1":
{
"intensityId": "decaf", "name": "Pack 1", "price": "6.99", "units": "3"
},
"decaf_pack2":
{
"intensityId": "decaf", "name": "Pack 2", "price": "9.99", "units": "6"
},
"decaf_pack3":
{
"intensityId": "decaf", "name": "Pack 3", "price": "13.99", "units": "12"
},
"forte_pack1":
{
"intensityId": "forte", "name": "Pack 1", "price": "5.99", "units": "3"
},
"forte_pack2":
{
"intensityId": "forte", "name": "Pack 2", "price": "7.99", "units": "6"
},
"forte_pack3":
{
"intensityId": "forte", "name": "Pack 3", "price": "12.99", "units": "12"
},
"fraco_pack1":
{
"intensityId": "fraco", "name": "Pack 1", "price": "4.99", "units": "3"
},
"fraco_pack2":
{
"intensityId": "fraco", "name": "Pack 2", "price": "6.99", "units": "6"
},
"fraco_pack3":
{
"intensityId": "fraco", "name": "Pack 3", "price": "10.99", "units": "12"
}
}
}
}
EDIT 2: My Function:
function handleBlend( agent ){
const responseBlend = agent.parameters.responseBlend;
const blendAmericano = db.collectionGroup('blend');
const queryBlend = blendAmericano.where(responseBlend,'==',('Americano').where('itensityId', '==', 'forte'));
queryBlend.get().then(function(querySnapshot){
agent.add('Então, o café que procura é ' + doc.data(queryBlend));
My agent parameters:
-Intensidade (Intensity of the Coffe, can be Forte, Fraco ou Descafeínado)
-Type (Americano, Italiano, Arábica or Asiático, which is the type of coffee)
The end result on the answer from the agent, should be the Blend:
-Blend for Americano Fraco is Unwind.
I'm a bit of a newbie at programming so, sorry if i'm not being clear with my explanation.
Thanks for any kind of help provided!
EDIT 1: FireStore DB updated with JSON format
EDIT 3: I've made some progress, i was able to query from VS Code to Firestore. Now im trying to return a single value.. thats the tricky part.
let query = db.collection('coffee').where('blend', 'array-contains', [type,{'intensityId': intensity}])
The code above, is my attempt to return a value that is inside a "map", which is inside an "array".
No luck so far... any help possible?
Thanks
EDIT 4:
function handleBlend( agent )
{
const getBlend = agent.context.get('procura-blend'),
type = getBlend.parameters.type,
intensity = getBlend.parameters.intensity;
//agent.add(`Obrigado, então é um ${type} ${intensity} que procura.`);
let query = db.collection('coffee').doc(type);
return query
.get()
.then(doc =>
{
var value = doc.data().Americano[0].name;
agent.conv(`Então, para um ${type} ${intensity} temos:, ${value}`);
// Intent-Handler para mapear funções aos intents
let intentMap = new Map();
intentMap.set('pergunta.confirma.blend', handleBlend);
agent.handleRequest(intentMap);
});
}
So.. this will be my last update.. i managed to do call for a single value with VS Code and NodeJS, acessing FireStore. Now as i try to replicate for DialogFlow, i though that there wasn't much changes, but i was wrong, so the code above is what i have right now, to try and prompt a responde for the user, but i get a Code: 4, "message": "Webhook call failed. Error: DEADLINE_EXCEEDED.". Any help would be great.
Thanks.
Upvotes: 0
Views: 168
Reputation: 11
Thanks for the tip Prisoner, but after many many many hours of research, i think i found a way.
I had to rearrange my DB and move to Sub-collections, and created some indexes. After that, the end result code is here:
function handleBlend( agent )
{
const getBlend = agent.context.get('confirma-blend'),
type = getBlend.parameters.type,
intensity = getBlend.parameters.intensity;
let query = db.collectionGroup(type);
return query
.where("intensityId", '==', intensity)
.get()
.then(snapshot => {
if (snapshot.empty) {
console.log('Não Descobri nada :( .');
}
snapshot.forEach(doc => {
const value = doc.data().name;
agent.add(`Este é o teu blend meu filho: ${value}`);
});
})
.catch(err => {
console.log('Error.. fogeeee!', err);
});
//Não tocar daqui para baixo..
}
// Intent-Handler para mapear funções aos intents
let intentMap = new Map();
intentMap.set('blend.confirma.sim', handleBlend);
agent.handleRequest(intentMap);
If anyone sees this in the future, i hope it helps, because for me, it was 4 days of constant research and many many hours!
So, from my side is solved and closed!
Upvotes: 1
Reputation: 50701
It looks like the problem is in how you're setting up the Intent Handler. Assuming I'm reading your code correctly, you seem to have the Handler Map inside the Handler function itself, which won't work.
This needs to be outside the function, so it references the function when your webhook is called.
You're getting a timeout because your webhook is being called, but since no Intent Handlers are registered - it doesn't return anything. So it ends up sitting there.
Upvotes: 0