I try to build an Alexa Skill that has an utterance with various slots. I implemented, that if a slot value is not given Alexa asks for that specific value.
Everything works fine.
Now the problem is, that one of the Slots should be a Name. A User might also say 'I' instead of his name. In that case the value should again be undefined and alexa should ask for the Name.
But I have no Idea how to set the value undefined in the Lambda funktion. I mean i can say: name = undefined or name = NONE but Alexa doesn't ask for it.
I guess that ASK saves the value somewhere and I can't touch that Value.
I've searched for Solutions but everything I found was about why slots are still undefined or things like that.
Thanks in advance
Always validate slots in your backend, and whenever your name-slot is not giving you expected values, use Dialog.ElicitSlot directive to make Alexa ask for that particular slot.
Ex:
If you are using ask-nodejs-sdk, then
return handlerInput.responseBuilder
.addElicitSlotDirective(slotToElicit)
.speak("Please provide a valid name")
.reprompt("Please provide a valid name")
.getResponse();
More on Dialog directives here
If you are using dialogs then you can easily validate a slot value like i have checked that the date is in past, if it is in future alexa asks the user to tell the date again
(i'm using node sdk v2)
if (dialogState !== 'COMPLETED') {
var dateTakenSlot=handlerInput.requestEnvelope.request.intent.slots.dateTaken.value;
if (dateTakenSlot !== null || dateTakenSlot !== undefined) {
var dateTaken = new Date(dateTakenSlot);
if (dateTaken > new Date()) {
resolve(handlerInput.responseBuilder
.speak('You can not log any future slots, On what date did you took the medicine')
.addElicitSlotDirective(handlerInput.requestEnvelope.request.intent.slots.dateTaken.name)
.getResponse());
}
then check your slots after dialogState is COMPLETED like
else if (dialogStatus === 'COMPLETED') {
console.log('slots after confirmation: ', handlerInput.requestEnvelope.request.intent.slots);
}
Related
I have tried literally using what everyone says and it just keeps giving me empty arrays or undefined. I am using discord.js v12 I believe.
I am REALLY certain that I actually have members with this role and that the roleID is correct. Why is this wrong? compare new_channel to channel. I suppose the ${} in the find function is not necessary but that is not the issue. Up to the roles.cache.get(importantRole.id) part it goes right, but I can't seem to get the members from it.
let importantRole = await new_channel.guild.roles.cache.find(r => r.name === `${new_channel.name}`)
console.log(importantRole.id) // --> gives the right role ID
let membersWithRole = await new_channel.guild.roles.cache.get(importantRole.id).members.map(m=>m.user.id);
console.log(membersWithRole) // --> gives []
Most likely the members with that role are not cached. You need to:
Enable the GUILD_MEMBERS privileged intent on the Discord developer panel if you have not already (if your bot is less than 100 guilds this is a simple toggle; if your bot has >100 guilds and is verified you need to apply for these, it's to protect user privacy), and
Enable the GUILD_MEMBERS privileged intent in your Discord.js Client's options (the object that is passed to new Client({...}) by passing { ws: { intents: [ 'GUILD_MEMBERS' ] } }
Fetch all of the guild's members when this command/module/etc runs (only do this when strictly necessary, and not on an interval, as it causes an extra API call)
Also, there's no need to do `${variable}` as variable does the same thing. The ` and ${...} syntax are only needed when merging variables with strings `like${this}` (= 'like' + this)
To fetch all guild members, you can do:
<Guild>.members.fetch() // => Promise<GuildMemberManager>
Note that for some reason, in my testing, the value of the resolved promise doesn't work as a valid GuildMemberManager, so you should do:
// _ = temporary var
<Guild>.members.fetch().then((_) => {
// do something with <Guild>.members.cache
});
Hello everyone,
i am working on an Alexa Skill at the moment and I have the problem, that I need to call a handler from another one.
I read several posts but there was no clear answer to my problem. I have a handler "AskForEmployeeInformation_Handler" which deals with several intents which answer several questions about a person. But if the user only says the surname or name instead of the full name then Alexa prompts out if there are persons which match to the given name. The user should now say one of the proposed names. While saying this name another handler "SetName_Handler" is called, which sets the chosen name as a session attribute. Now I want to call in the return statement the "AskForEmployeeInformation_Handler" again because it includes the whole logic to prompt out the wanted informations.
I saw some solutions to call the handler like you can see in the following code and the logic was executed but Alexa did not say anything and do not prompt the answer to the user.
Do you have an idea what I can do to solve the problem?
Thanks for your help.
const SetName_Handler = {
canHandle(handlerInput){
const request = handlerInput.requestEnvelope.request;
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
return sessionAttributes.event === 'AskForEmployee_Name' || sessionAttributes.event === 'AskForPhoneNumber_Name' || sessionAttributes.event === 'AskForRole_Name';
},
handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const responseBuilder = handlerInput.responseBuilder;
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
let say = '';
let slotValues = getSlotValues(request.intent.slots);
console.log('***** slotValues: ' + JSON.stringify(slotValues, null, 2));
//save person for the session - maybe for further questions
sessionAttributes['employeeSurname'] = slotValues.employeeSurname.resolved;
sessionAttributes['employeeName'] = slotValues.employeeName.resolved;
handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
return AskForEmployeeInformation_Handler.handle(handlerInput;
}
};
I think your best bet is to separate the logic out of your handlers. I have never seen the need to call another Intent's handle method from another, and I find that this would add complications and odd errors.
The flat IntentHandler way of doing things is a recipe for disaster once your skill needs to know about session states and context (for example, what the user was doing previous to this IntentHandler being invoked).
Instead, you might find the Dialog Interface way of confirming slots to be exactly what you are looking for: https://developer.amazon.com/en-US/docs/alexa/custom-skills/dialog-interface-reference.html
Check out this article for a good overview of why/how to manage state and context in Alexa apps: https://medium.com/hackernoon/lessons-learned-moving-from-web-to-voice-development-35daa1d301db
[We have a Dialogflow bot consisting of two intents. Each intent contains some set of questions.
The user answers the questions(prompts) and this process continues. We are getting the fulfillment text only after the intent is completed but we need to get the fulfillment text(Each and every prompt) after completing every question in that particular intent.
Help us in finding the solution.
You can use webhook for slot filling. (under the "Enable webhook call for this intent", enable Enable webhook call for slot filling button). By doing this, you can still stay in intent handler function and prompt what you need until you can finish your steps.
For example:
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');
}
}
Also you can use this functionality on actions-on-google library.
Check for more information:
Webhook for slot filling
Enable Webhook for Slot Filling. Dialogflow will call your server to see if you can provide the pending information that your user didn’t.
I am working on a Zapier app and there is a tenant id (integer) that is retrieved during authentication that I need to use in a trigger. What is the correct way to do this?
I have tried using global, bundle.authData and storing the data in a module, but nothing seems to work consistently. The best has been when I stored the data in global, but it is inconsistent, out of six calls to the trigger the tenant id may only be valid twice, the other four times it will be returned as undefined.
In the case of global I am writing the data during authentication:
const test = (z, bundle) => {
return z.request({
url: URL_PATH + ':' + URL_PORT + '/v1/auth',
params: {
username: bundle.authData.username,
password: bundle.authData.password
}
}).then((response) => {
if (response.status === 401) {
throw new Error('The username and/or password you supplied is incorrect.');
} else {
global.GLOBAL_tenant = response.json.tenant;
// ...
}
}
And then attempting to read the data back in the trigger:
const processTransactions = (z, bundle) => {
let jsonAll = [];
let tenant = global.GLOBAL_tenant;
return new Promise( (resolve, reject) => {
(function loop() {
// ...
I also tried adding the dat to 'bundle.authData', this was the recommendation that Zapier made when I contacted them, but the tenant id that I added during the authentication:
bundle.authData.tenant = response.json.tenant
Is not available when I try to retrieve it in the trigger. Only the 'username' and 'password' are present.
I am new to Zapier and node.js so any help will be greatly appreciated.
Instead of returning fully qualified name like bundle.authData.tenant = response.json.tenant, please use something like tenant = response.json.tenant and this statement should be enclosed in a return statement preferably. The bundle.authData qualifier is automatically applied by Zapier.
global variables should be avoided. Hope this helps.
David here, from the Zapier Platform team.
global isn't going to work because your code runs in multiple lambda executions and state isn't stored between them. Plus, global implies it would be the same for all users, which probably isn't what you want.
Instead, I'd check out session auth, which will let you store extra fields during your test by creating a computed field and returning values for it from sessionConfig.perform. Then it'll be stored in the auth object, next to the username and password.
Separately, you may want to consider whatever code is in processTransactions. Either you can return them all and they'll deduped on our end, or you're doing a bunch of extra computation that is better dehydrated. That's just a guess on my part though, so feel free to ignore this part.
OK, new to Node.js and botframework. I built first bot using Azure site and downloaded the code. Chose the Luis integrated bot template.
I understand (finally) the event driven model of node.js and the concept of callbacks.
I have the code snippet below. When Luis finds an intent of "Help" it triggers this function. In turn, I have database calls to lookup the entity. Within the database I have an entity, response (if entity is bottle, answer "Recycle").
I have that code working too.
Below the first block is a function handleHelpRequester which is the callback function, I have that working as well. Where I am a little stuck (best practice) is that in this callback function I want to send something to the session object (session.send toward the bottom of the function).
Since I don't create the session object (directly) I'm not sure on the options.
Should I pass the session object to the database function, then pass it back?
Should I create a global variable and set it to the session object (I'm concerned that if multiple people are using this bot then this approach won't work).
I'm open for suggestions.
Thanks
.matches('Help', (session, args) => {
var entities = args.entities;
var itype = builder.EntityRecognizer.findEntity(args.entities, 'ItemTypes');
var respondToUser = '';
var msg = 'Initialized';
// if there is an entity provided, perform a lookup of the entity.
if (itype.entity !== null) {
//Use session.sendTyping so the user thinks something is happening rather than being ignored while we do the lookup in SharePoint.
session.sendTyping();
//perform lookup
respondToUser = sp.lookupEntity(itype.entity, handleHelpRequest);
};
})
function handleHelpRequest(err, respondToUser) {
var msg = 'uninitialized';
if (err = 'success') {
console.log('Respond to user from matches:'.concat(respondToUser));
//return from lookup
if (respondToUser === 'No match found') {
msg = 'I think you are asking for help, but I don\'t understand what you need help with.';
}
else {
msg = 'I can help you with that, \'%s\'.', respondToUser;
}
console.log(msg);
session.send(msg);
//The following two lines are for debugging
session.send('How may I assist you? ' + JSON.stringify(args));
session.send('Value of entity you said: \'%s\'.', itype.entity);
}
else {
console.log('an error occurred');
}
}
If you want to have access to the session object, then pass it as a parameter to your helper function.
Example:
function handleHelpRequest(session, err, respondToUser) {
// do session stuff
}