actions on google user.storage clears out with every post call from the user-at the same coversation. how do i save the data of the conversation? - dialogflow-es

I am trying to save the data through the conversation with user.storage, I am accessing the user.storage like this:
app.post('/', express.json(), (req, res) => {
const agent = new WebhookClient({ request: req, response: res })
let personalD=new personalDetails(agent)
function personal_details(){
personalD.foo()
}
let intentMap = new Map()
intentMap.set('inform.PersonalDetails',personal_details)
agent.handleRequest(intentMap)
}
//that's the personalDetails class:
class PersonalDetails{
constructor(agent){
this.agent=agent;
this.conv=this.agent.conv();
}
foo() {
this.conv.user.storage.name=this.agent.parameters.name;
this.conv.user.storage.age=this.agent.parameters.age;
this.conv.user.storage.gender=this.agent.parameters.gender;
const gotname = this.conv.user.storage.name==''?0:1
const gotage = this.conv.user.storage.age==''?0:1
const gotgender =this.conv.user.storage.gender==''?0:1
const name=this.conv.user.storage.name;
const gender=this.conv.user.storage.gender;
if (gotname && !gotage&&!gotgender)
this.agent.add(`Ok, ${name}, How old are you? and what is you'r gender?`)
else if (gotname && gotage&&!gotgender)
this.agent.add(`Ok, ${name}, What gender you belong to`)
else if(gotname && !gotage&&gotgender)
this.agent.add(`Ok, ${name}, How old are you?`)
else if (!gotname && gotage&&gotgender)
this.agent.add(`What's your name please?`)
else if (!gotname && !gotage&&gotgender)
this.agent.add(`Well dear ${gender}, What is your name and how old are you`)
else if(!gotname && gotage&&!gotgender)
this.agent.add('Let me know what is your name and what is your gender')
else if (!gotname && !gotage&&!gotgender)
this.agent.add(`I want to get to know you before we begin. what is you'r name?`)
}
}
module.exports=PersonalDetails;
Dialogflow wants from the user three entites: name, age and gender. When the user does not provide all of them the code does some logic to see what is missing.
The problem is that at first I enter lets say name and age, and then it asks the user about the gender, when the user enteres the gender it's already forgetting the name and the age...
please help

In your dialogflow fulfillment code, you are initializing parameters in user.storage on every request from the intent, instead of only when you have a value from the user. This code is your problem:
this.conv.user.storage.name=this.agent.parameters.name;
this.conv.user.storage.age=this.agent.parameters.age;
this.conv.user.storage.gender=this.agent.parameters.gender;
You have to set the user.storage only once and then, you can use it anywhere directly.
app.intent('GetUserName', (conv, {name}) => {
conv.user.storage.name= name;
conv.ask(`Hi, ${conv.user.storage.name}!.
Please tell me how can I help you? `);
});
app.intent('AboutSC', (conv) => {
conv.ask(`well ${conv.user.storage.name}. What more would you like to know? `);
});
You can use the user.storage parameters directly. But using variable/constants that are initialized on every request will change the value everytime & will not help.

Related

Discord.js get user by nickname

I'm having a hard time figuring out
Is is possible to find a user by his or her nickname via the discord.js npm package.
How can I query a user by his or her nickname?
i've tried several things but nothing returns the nickname and I can't quite figure out how their documentation works.
So far I haven't been able to tell how to do it.
I've done as so in my code.
const { Client } = require('discord.js')
const discordClient = new Client()
discordClient.on('message', message => {
if (message.author.bot) return
if (message.content.startsWith('!gpwarn')) {
// The command is something like '!gpwarn thomas'.
// If his nick name is thomas but his username is john it doesn't work.
})
Yes, and it's pretty simple. Do this:
const user = client.users.cache.find(user => user.username == "The user's name");
Reference:
UserManager
To meet your exact requirements you would search the guild members cache for the provided nickname. However, I personally would suggest using either a direct tag or a UserID for this, as multiple people can have the same nickname in the server.
const U = message.guild.members.cache.find(E => E.nickname === 'NICKNAME')
Getting by Tag:
const U = message.mentions.members.first()
Getting by ID:
const U = message.guild.members.cache.find(U => U.id === 'IDHERE')
First you need to identify the nickname argument, you can do this by splitting, slicing, and joining message.content.
Next I recommend you fetch all of the GuildMembers from the guild using GuildMemberManager#fetch(), This way you don't run into the error of a member being uncached.
Handle the promise using async/await and use Collection#find() to return the member.
const { Client } = require('discord.js')
const discordClient = new Client()
discordClient.on('message', async message => {
if (message.author.bot) return
if (message.content.startsWith('!gpwarn')) {
// Returns all of the text after !gpwarn
const query = message.content.split(' ').slice(1).join(' ').toLowerCase()
const members = await message.guild.members.fetch()
const memberToWarn = members.find(m => m.nickname.toLowerCase() === query)
if (!memberToWarn) // No member found error
console.log(memberToWarn) // [GuildMember]
}
})

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];
})

How to get device coarse location for each webhook request in actions on google

Hi i'm trying to get device coarse location by getting permission from user.But i required to get device location details for each webhook request without asking permission again and again.So I'm bit confused how to do this one.
Here is the below code which i tried.
const {Permission} = require('actions-on-google');
const {WebhookClient} = require('dialogflow-fulfillment');
const agent = new WebhookClient({ request: req, response: res });
function x(agent){
conv.ask(new Permission({context:'To Locate You',permissions:'DEVICE_COARSE_LOCATION'}));
}
function userinfo(agent){
var conv=agent.conv();
var resp=conv.arguments.get('PERMISSION');
console.log(conv.device.location);
if(resp){
var country=conv.device.location.country;
var speech="you are located in "+country;
conv.ask(speech);
agent.add(conv);
}else{
conv.ask('Sorry, I could not figure out where you are');
agent.add(conv);
}
}
Please check the helper functions here. You need to do the following:
Create an intent to ask for permission.
In that intent, ask the permission you want
Create second intent to capture user's response to intent by putting the Dialogflow event actions_intent_PERMISSION to that intent.
In the webhook handle of the second intent check for confirmation.
Ask Permission in First Intent
app.intent('FIRST_INTENT_NAME', (conv) => {
// Choose one or more supported permissions to request:
// NAME, DEVICE_PRECISE_LOCATION, DEVICE_COARSE_LOCATION
const options = {
context: 'To address you by name and know your location',
// Ask for more than one permission. User can authorize all or none.
permissions: ['NAME', 'DEVICE_PRECISE_LOCATION'],
};
conv.ask(new Permission(options));
});
Capture result in Second Intent
app.intent('SECOND_INTENT_NAME', (conv, params, confirmationGranted) => {
const {name} = conv.user;
if (confirmationGranted) {
if (name) {
conv.ask(`I'll send the driver you're way now ${name.display}.`);
}
}
});
For exact understanding with code example, check out this GitHubb example link.

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;

Dialogflow assistant app exiting after successful fulfillment

I have a dialogflow assistant app with 3 intents. The first intent asks the user for location and name details from google. I am using a webhook for the fulfillment of this intent. I am able to extract the user information name and location, but after it is showing output from webhook, it is exiting from flow. But it is supposed to pass the location parameters to next intent and stay on the flow. Can anybody help me how to stop assistant from exiting?
Here is the webhook code
'use strict';
const functions = require('firebase-functions');
const DialogflowApp = require('actions-on-google').DialogflowApp;
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const requestPermission = (app) => {
app.askForPermissions('To report ', [app.SupportedPermissions.NAME, app.SupportedPermissions.DEVICE_PRECISE_LOCATION]);
};
const userInfo = (app) => {
if (app.isPermissionGranted()) {
const address = app.getDeviceLocation().coordinates;
const name = app.getUserName().givenName;
if (name) {
app.tell(`You are name ${name}`);
}
else {
// Note: Currently, precise locaton only returns lat/lng coordinates on phones and lat/lng coordinates
// and a geocoded address on voice-activated speakers.
// Coarse location only works on voice-activated speakers.
app.tell('Sorry, I could not figure out where you are.Plaese try again');
}
} else {
app.tell('Sorry, I could not figure out where you are.Please try again');
}
};
const app = new DialogflowApp({request, response});
const actions = new Map();
actions.set('request_permission', requestPermission);
actions.set('user_info', userInfo);
app.handleRequest(actions);
});
The problem is that you are calling app.tell() in your code which is a signal to the Assistant to send the message and then end the conversation.
If you want to send the message and then leave the microphone open for the user to reply, you should use app.ask() instead. It takes the same parameters - the only difference is that it expects the user to reply.
So that portion of your code might look something like
if (name) {
app.ask(`You are name ${name}. What would you like to do now?`);
}
(You should make sure that the prompt for the user is one that they will expect to reply. The review process will reject your Action if you reply and it isn't obvious that the user is supposed to reply to you.)

Resources