Unable to accept the permission prompt on Actions on Google - dialogflow-es

I am trying to get permissions for location and name for my app.
Here is my index.js - link
It seems to be stuck in a loop :-
Here are my intents on API.AI :-

The event actions_intent_PERMISSION needs to be attached to an Intent that will be called after the user authorizes the information to be sent. The handling for it in the webhook needs to read the information given and save it or do something with it immediately.
Your code is looping because the code that is processing the request_permission action is, itself, requesting permission:
function requestPermission(app){
const permissions = [
app.SupportedPermissions.NAME,
app.SupportedPermissions.DEVICE_PRECISE_LOCATION
];
app.askForPermissions('To pick you up', permissions);
}
So you will need:
A new intent
that has actions_intent_PERMISSION set for the event
that has a new action string associated with it
and maps to a new function that handles the information that the user has consented to.

Related

Prevent new context after responding with new ones on Dialogflow

I have an intent with webhook and slotfilling enabled for validation and it have 4 parameters marked as required, so my server can validade the parameter value.
The strategy that I'm trying to use is: reset the context for invalid parameter value, so the dialogflow can ask it again.
Here is an example entering an invalid value:
On responding "Brasília" the webhook makes a request to my server. My server knows that is an invalid value and respond with the context presented on the previous image.
This is the result:
Notice that the first 4 context match with the previous image, its everything ok here. But dialogflow adds another context. That context is a request for the next parameter, called "motivo" and if I respond back, the response will be stored on this param. After this, dialogflow prompts back for the "local" param.
The conversation runs like this:
User: I want to register a call
Dialogflow: From where you want to register? Aracaju, CAB, Itabuna or Salvador?
User: Brasília
Dialogflow: Please, describe the reason
User: My network wireless is not working
Dialogflow: From where you want to register? Aracaju, CAB, Itabuna or Salvador?
...
What was supose to be:
User: I want to register a call
Dialogflow: From where you want to register? Aracaju, CAB, Itabuna or Salvador?
User: Brasília
Dialogflow: From where you want to register? Aracaju, CAB, Itabuna or Salvador?
...
What I need to know: Am'I responding with the correct contexts? Is there a way to prevent dialogflow creating this new "registrar_dialog_params_motivo" after responding with a new contexts?
Obs.: I'm using a Nodejs server, responding the webhook as the docs suggests.
Edit 1: I know that I can use an entity for this situation. However there is some cases that I need to make multiple validations on backend to procede, something like an user id, etc.
If the intent “Intent_Name” has some input_context defined already, then you need to set that context again as output_context and reply something like you have entered an invalid location, and please enter again.
If the intent does not have any input_context, then you can simply reply you have entered an invalid location. Please enter again, and your intent should be able to catch that too. However, this can cause problems as well.
What I would recommend is having another intent “Intent_Name_followup” with an input_context as location_validation_failed in the logic. If the location is incorrect, you can set this in the output_context to reply to the user.

How to pass to an intent if Permission request is denied

I have an Action that integrates with Dialogflow which as part of the conversation requests access to the user's location.
This is fulfilled via a webhook:
app.intent('actions_intent_PERMISSION', async (conv, params, permissionGranted) => {
if (!permissionGranted) {
app.intent('actions_intent_PERMISSION - no', (conv, params) => {
conv.ask('sad face, you said no to my permission request!');
});
// conv.ask(`Ok, no worries. I'll have to figure out how to get your postcode. follow-up intent I suppose`);
} else {
conv.data.postcode = conv.device.location.zipCode;
conv.ask(`Ok great - please give me a minute, I have to get data from a few different places.`);
//use postcode to make some other API calls
}
});
Everything is fine when the user gives permission but when they don't give permission I would like to pass off to an intent that asks for their location manually ('what is your postcode/zipcode?').
As per the screenshot I tried creating a followup intent to actions_intent_PERMISSION called actions_intent_PERMISSION - no but this causes the app to crash.
What is the best way to pass the conversation to another intent is the value of permissionGranted is false?
Your question doesn't quite make sense the way you've asked it. Intents represent what the user has said and not what you do with it - that is what your webhook does in an Intent Handler. There is nothing (technically) stopping you from replying to the user asking for their zip code by just replying differently.
If you want users to be able to trigger some Intents if they have given permissions, and other Intents if they have not, you can set a different Context for each. Then you would set some Intents to only be triggered if the "permitted" context was set, and others only if the "notpermitted" context was set.
However, you have a non-technical problem to consider. If they aren't giving you permission to get their location, why would they tell you their location? It also is likely that the reviewers would reject it, saying that you should be getting location information through the provided API.

Alexa SDK Redirect to Set Session Attributes

Is there a way to temporarily redirect from one intent to another in order to fill slots or session attributes and then return to the original intent to be responded to or fulfilled?
My use-case is for asking for an account PIN as a secondary authentication after account linking. For instance, if someone asks "What are my account details?", I want that intent to change in the session attributes if it exists and if not, temporarily redirect to an intent that will prompt them for the PIN and set it...then come back and answer their account details request. Similar to the example below:
const IntentHandler = {
canHandle(input) {
return (
input.requestEnvelope.request.type === 'IntentRequest' &&
input.requestEnvelope.request.intent.name === 'MyIntent'
},
handle(input) {
const { accessToken } = input.requestEnvelope.context.System.user
// ... do stuff with accessToken
if (!input.attributesManager.getSessionAttributes().pin) {
// redirect to other intent to set the pin session attribute
}
// ...response to intent request
}
}
I can get this working with a single intent using slot filling prompts but this is a common task for several intents and would like to separate it out so it doesn't have to be configured in the console for all that require it.
FYI: using the ask-sdk for Node.js
Is this possible with the current version of the ask-sdk?
Yes, Alexa makes it easy now to switch between intents and jump right into eliciting a specific slot for the new intent.
I would use the ElicitSlot Dialog Directive and include the updatedIntent object for the new intent.
updatedIntent
Use this to change intents during the dialog or set slot values and confirmation status. See Change the intent or update slot values during the dialog. If you don't need to change the intent, slot values, or confirmation statuses, you can leave this property out of your response.
When you switch intents with this parameter, Alexa attempts to elicit the specified slot value on the new intent. The next IntentRequest to your skill will be the new intent, not the original.
Example:
Intent A is missing access token.
Intent A directs Alexa to elicitSlot "pin" from Intent B. (include info in sessionAttributes such as "previousIntent" or "nextIntent" to use as direction to Intent B)
Alexa responds to user with Intent B's elicit prompt for slot "pin".
User provides pin.
Alexa provides user input to Intent B (not A) with slot "pin" filled and Intent B sets the access token in sessionAttribtues.
Then Intent B checks sessionAttribtues for direction of which intent to return to and which slot to elicit from that intent. So you can either confirmIntent or elicitSlot for Intent A.
Intent A will receive the next user input and now detects access token.
Notice that you will have to address the user with something between switching intents. If you are using confirmIntent then it can be a simple Yes/No confirmation question such as, "Thank you for your pin, would you like me to retrieve your account details now?". The user says "Yes", and that is sent back to Intent A to complete what it started.
If you don't want this extra back and forth with the user, then as far as I know, you'll have to build the pin slot into each intent you may need to elicit it. That way, you just stay within Intent A. Less efficient code, but more efficient conversation, so it's a bit of a trade off.

How can I delegate the LaunchRequest to an IntentRequest using the alexa-sdk from npm

I am building an Alexa skill in node using the alexa-sdk. I am using a dialog model to handle the user interaction. I am having some trouble passing the flow along to new request types, such as from the launch request to an intent request.
Below is an example of my handlers and what I want ideally. My specific usecase is that I would like to ask some questions of the user and then send them to different intents based on what they answer. In the intents I would like to have access to the request objects, as if they entered that intent originally, so the dialog model can do its work.
const handlers = {
'LaunchRequest': function () {
this.emit('Entry'); // this does not do what I want
},
'Entry': function () {
let request = this.event.request; // this is the launch request object.
// I would like to get the request object for Entry, like if the user started here
// ask some questions, potentially passing the torch to a new intent based on the answers
}
};
So, is there any way to "call" an intent like the user originally made a request to that intent? Sorry if I missed something obvious in the documentation, I searched around pretty thoroughly I think, but there is A LOT of documentation. ps: I could manually construct the request object of course, but I really should not have to I feel.
I am pretty sure there is no way yet to call on an intent as you are asking.
If you go through the syntax description of dialog directieves here, it says:
Note that you cannot change intents when returning a Dialog directive, so the intent name and set of slots must match the intent sent to your skill.
With returning a dialog directive you are able to 'elicit' or 'confirm' slots or intents, or even let a delegate handle your dialog for you, with prompts and reprompts set in the Skill Builder.
As far as i know, the only solution to trigger a specific intent is to make the user invoke it. You can guide the user into saying a specific utternace to trigger your intent.
As for saving older requests, you can use session attributes. Just build a response after your Launch with a session attribute containing the whole LaunchRequest.
"sessionAttributes": {
"oldRequest": this.event.request
}

Microsoft bot: How to log each conversation step?

I'm learning how to build a Microsoft Bot and I need to send every message (ie log the user progress through the bot) to an API.
Let's say I have these dialogs with 3 steps each:
/
/welcome
/onboarding
/finish
When a user joins the conversation (Root dialog), I need to make a POST to our API with the following data:
{
"conversationId": "8n21b2mkmdb9abi26",
"dialog": "root",
"step": 1
}
And then, for each following user message, I would update that conversation in our server with the dialog and step.
I tried to use the middleware hook, but it doesn't have the information of which dialog/step the user is currently in.
Any suggestion?
The middleware feature gives you access to the session object. Store the metadata you need in the session object, then access it in your logging middleware.
For a code example, check out: Microsoft/BotBuilder-Samples - Middleware and Logging with BotBuilder Node SDK

Resources