Context is not working properly in dialogflow - node.js

const contextlist = 'customer';
app.intent('Welcome', (conv) => {
const customer = { 'companyId': '11131' };
conv.contexts.set(contextlist, 5, customer);
});
app.intent('Delivery',(conv)=>{
let companycontext = conv.contexts.get(contextlist);
})
These are the logs regarding the context
I'm going to set the context when my welcome intent is called and getting the value from intent when the Delivery intent will call, But I'm getting undefined at the time of getting context value.

First try adding a conv.ask() call with some text, in the code example you showed you are not returning a response, this might affect the setting of the context.
If that doesn't work, try changing the way you are setting your variables in your context to the following:
conv.contexts.set(contextlist, 5, { customer });
The properties that you want to set need to be part of an object. If you want to retrieve the customer, you need to use the following code:
// Set context
conv.contexts.set(contextlist, 5, { customer });
// Retrieve context
const companycontext = conv.contexts.get(contextlist);
const customer = companycontext.parameters.customer;

Related

How can I create an entity specific to a user?

I'm creating an action for Google Assistant with Dialogflow and actions-on-google-nodejs that accesses the GitKraken Glo API to add cards to people's boards. I'm authenticating my users with Account Linking. I want my users to be able to say things like Add a card to [board name] or Add a card. If a board name isn't given I want the action to prompt the user for it. How can I create a session entity that get's all the board names for the logged in user?
Sorry if this doesn't make much sense, I'm pretty new to Actions on
Google and Dialogflow. Feel free to ask questions for clarity.
There are a few things you'll need to do first to use a Session Entity:
The Entity Type needs to already exist. Session Entities update existing ones. The easiest way to do this is to create the Entity you want in the Dialogflow UI. It doesn't need to have any Entities in it, but having one as a default can be useful.
You need a Service Account for your project in Google Cloud that will do the update, and a secret key for this account.
Your life will be a lot easier if you use a library, such as the dialogflow-nodejs library.
In general, your code needs to do the following, typically when the user first starts the session (ie - in your Welcome Intent Handler):
Get the list of boards
Update the Session Entity Type, creating an Entity for each board. Doing this update involves:
Issuing a patch against the projects.agent.sessions.entityTypes method with a SessionEntityType for the Entity Type you're overriding.
The SessionEntityType will contain an array of Entities with the canonical name (likely the board name, or some unique identifier) and any aliases for it (at least the board name, possibly anything else, possibly including aliases like "the first one" or "the most recent one").
The README for the library includes links to sample code about how to do this using the nodejs library. Code that I have that does this work has a function like this:
function setSessionEntity( env, entityType ){
const config = envToConfig( env );
const client = new dialogflow.SessionEntityTypesClient( config );
let parent = env.dialogflow.parent;
if( entityType.displayName && !entityType.name ){
entityType.name = `${parent}/entityTypes/${entityType.displayName}`;
}
if( !entityType.entityOverrideMode ){
entityType.entityOverrideMode = 'ENTITY_OVERRIDE_MODE_OVERRIDE';
}
const request = {
parent: parent,
sessionEntityType: entityType
};
return client.createSessionEntityType( request );
}
conv.user.email
You can use conv.user object :
const Users = {};
app.intent('Get Signin', (conv, params, signin) => {
if (signin.status === 'OK') {
const email = conv.user.email
Users[email] = { };
conv.ask(`I got your email as ${email}. What do you want to do next?`)
} else {
conv.ask(`I won't be able to save your data, but what do you want to next?`)
}
})
app.intent('actions.intent.TEXT', (conv, input) => {
if (signin.status === 'OK') {
Users[conv.user.email] = {
lastinput: input
};
}
});
conv.id
Also with conv id is unique id for the current conversation.
// Create an app instance
const app = dialogflow()
// Register handlers for Dialogflow intents
const Users = {};
app.intent('Default Welcome Intent', conv => {
Users[conv.id] = {
conversationId: conv.id,
name: '1234'
};
})
app.intent('actions.intent.TEXT', (conv, input) => {
Users[conv.id] = {
lastinput: input
};
});
app.intent('Goodbye', conv => {
delete Users[conv.id];
})

Set context on Google Actions through Dialogflow fulfillment

I'm using the Dialogflow editor fulfillment to build a conversation on Google Assistant, but I'm not sure how to use the agent.setContext function.
When I ask "Turn off my device" the first step returns successfully. The problem happens when the user responds with "TV", for example. The system returns with another context, ignoring the one I set.
When the user directly asks "Turn off my TV in the kitchen" the system also works perfectly. Because of it I think that the entities are correctly defined.
Conversation 1 (success):
Turn off my TV in the kitchen
Right. Turning off.
Conversation 2 (fail):
Turn off my device //Gives the same intent that Conversation 1
OK, which device?
TV
"My bot" isn't responding right now. Try again soon. //It throws "'final_response' must be set". I think it's because of generic intent actions.intent.TEXT.
My code:
The code below is nested in exports.dialogflowFirebaseFulfillment = functions.https.onRequest and the intent is called by intentMap.set('smarthome.device.switch.off', setDeviceOff);
const agent = new WebhookClient({ request: request, response: response });
function setDeviceOff(agent) {
const device = agent.parameters.device;
const room = agent.parameters.room;
const context= 'device-switch'; //I tried 'smarthome.device.switch.off' too
let resp = commandDevice(device, room, 'Off', agent, context);
return resp;
}
function commandDevice(device, room, cmd, agent, context) {
var conv = agent.conv();
if(device===''){
conv.ask("OK, which device?");
}else if (room===''){
conv.ask("Got it. of what room?");
}else{
conv.ask("Right. Turning off.");
}
agent.setContext({
name:context,
lifespan: 5, //Tried 0, 4 and 3 too
parameters:{
'device':device,
'room':room
}
});
agent.add(conv);
return true;
}
So I tried another version and the same problem persists:
const app = dialogflow();
app.intent('welcome', conv =>{
conv.ask("Welcome to auto obari. What can I do for you?");
});
app.intent('Default Fallback Intent',conv =>{
conv.ask("I didn't understand, can you try again?");
});
app.intent('smarthome.device.switch.off', (conv,{device, room})=> {
const context= 'device-switch';
if(device===''){
conv.ask("OK, which device?");
}else if (room===''){
conv.ask("Got it. of what room?");
}else{
conv.ask("Right. Turning off.");
}
const parameters = {'device':device, 'room': room};
conv.contexts.set(context, 5, parameters);
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app); //I tried exports.factsAboutGoogle, but it threw a error too.
The contexts are the same, but the intent is different.
If using conv, you may also try like this:
app.intent('<INTENT>', conv => {
conv.ask('<RESPONSE>');
const parameters = {'param1':param1, 'param2': param2}};
conv.contexts.set('welcome-context', 5, parameters);
});
and access it like here :
const conv.contexts.get(<context>).parameters[<param>];
you can try this method too it worked for me
const AppContexts = {CONTEXT_ONE: 'context-one'};
const app = dialogflow();
In current intent (for output context)
conv.contexts.set(AppContexts.CONTEXT_ONE, 1);
In next intent (for input context )
const context = conv.contexts.get(AppContexts.CONTEXT_ONE);

dialogflow Webhookclient "request_" property

I am trying to build up a facebook messenger chatbot using Dialogflow. In the dialogflow fulfillment inline editor, I found that I can use agent.request_.body to get the body of the request. I assume "request_" is a property of WebhoodClient object? But I couldn't find any documentation elaborate that, could you please advise if my understanding is correct and where I can find the reference or documentation?
const agent = new WebhookClient({ request, response });
console.log(JSON.stringify(agent.request_.body));
Thanks
Google provides documentation for Dialogflow webhooks here, which include this sample webhook to inspect parameters and dynamically create slot filling prompts:
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
function flight(agent) {
const city = agent.parameters['geo-city'];
const time = agent.parameters['time'];
const gotCity = city.length > 0;
const gotTime = time.length > 0;
if(gotCity && gotTime) {
agent.add(`Nice, you want to fly to ${city} at ${time}.`);
} else if (gotCity && !gotTime) {
agent.add('Let me know which time you want to fly');
} else if (gotTime && !gotCity) {
agent.add('Let me know which city you want to fly to');
} else {
agent.add('Let me know which city and time you want to fly');
}
}
let intentMap = new Map();
intentMap.set('flight', flight);
agent.handleRequest(intentMap);
});
My guess would be to add
console.log(agent);
right before defining the flight function, then checking the logs to see which objects agent contains, then adding iterations of console.log(agent.fakeObjectName) until you find the information you're looking for.
If you're following the deployment process recommended in Actions on Google's Codelabs level 2, your logs will show up in the Firebase console, like this:
Hope that helps!
Just a note.
I had a code similar to this:
const city = agent.parameters['geo-city'];
There is an icon that suggest it's better written in dot notation.
that is gone after I changed it to:
const city = agent.parameters.geo-city;

How do I trigger a firebase cloud function only when a field is updated?

I would like to trigger a cloud function only when a particular field of a firestore document is updated. I don't want to trigger it every time the document is updated regardless which field. Is it possible?
For example:
exports.onAvatarUpdated = functions.firestore.document('users/{userId}/avatarUrl')
.onUpdate(change => {
// do something here
});
Currently there are no triggers for a specific field. You can only trigger on any change to a document, and if you want to know if a particular field changed, you have to examine the change object to figure it out.
You can always file a feature request if you would like to be able to express a function that only pays attention to particular field.
I will change Firebase native manual code from here:
exports.updateUser = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
// Get an object representing the document
// e.g. {'name': 'Marie', 'age': 66}
const newValue = change.after.data();
const newFieldValue = newValue.field;
// ...or the previous value before this update
const previousValue = change.before.data();
const previousFieldValue = previousValue.field;
if (previousFieldValue!== newFieldValue)
{ // perform desired operations ... }
});

agent.set.context() not working Dialogflow fulfillment

We are facing issues while managing multiple user interaction at the same time in Dialogflow.
How we can manage user unique session as we are using custom event which will process our 3rd party API and then return a response to the specific user.
To manage User unique session We try Dailogflow Set/Get Context method, to set Context with Unique Id (using this id will store API response to the Redis server) from the first intent when a user makes a first request then will traverse that Unique Id through the custom event.
Will get that Unique Id from Context and grab data from Redis server which we stored in first intent.
We used agent.set.context() to set unique id but this method is not working with "dialogflow-fulfillment"  version ^0.5.0, To get this work we have updated the version with "^0.6.1". But this will provide other error like "UnhandledPromiseRejectionWarning: Error: No responses defined for platform: null".
Required Output: Context set with a unique id and will get a proper response.
Current Output: UnhandledPromiseRejectionWarning: Error: No responses defined for platform: null
async function searchFromAPI(agent){
axios.post('https://testApi.com', searchString.data, {headers: headers})
.then((resp) => {
response.data = resp;
redisClient.set(sessionId, JSON.stringify(response));
}
}).catch(error => {
response.error = true;
response.message = error.response.statusText;
redisClient.set(sessionId, JSON.stringify(response));
});
await customsleep(2000);
const sessionId = uuid.v4();
const contextData = {'name':'userSession','lifespan': 5,'parameters':{'sessionId':sessionId}};
agent.context.set(contextData);
console.log(contextData);
agent.add('We are processing your request, Could you please wait?');
agent.add(new Suggestion("Yes"));
agent.add(new Suggestion("No"));
}
// wait for 4.5sec and call custom event
async function followOne(agent){
await customsleep(4500);
agent.setFollowupEvent('followUpTwo');
}
// wait for 4.7sec then red API response from redis server and return
async function followUpTwo(agent){
await customsleep(4000);
sess = session;
//get context
const response = agent.context.get('userSession');
// get the sessionId, Get the data from redis server
agent.add(response);
}
async function PleaseWait(agent){
await customsleep(3500);
agent.setFollowupEvent('followUpOne');
}
I found the only workaround to reassign a new context object via context.set(ctx). Then it worked.
//update context to show full menu
let context = agent.context.get('user_data');
if (!context) throw "User_data context ius nod defined in PreferrenceAdd"
let context2 = new Object();
context2 = {'name': 'user_data', 'lifespan': 40,
'parameters': context.parameters};
console.log("ctx: = " + JSON.stringify(context2));
context2.parameters.new = false;
context2.parameters.refresh = true;
agent.context.set(context2);
Check this resource on how to set a new Dialogflow outgoing context
dialogflow webhook-client.
I hope this helps you?

Resources