I am using Google Assistant with Node.js where I ask the user for check-in date and check-out date.
If the check-out date is later than the check-in date then I want to add a re-prompt so that the user can tell a valid date. Is there a way to force a re-prompt from the code?
The code snippet is below:
app.intent('myIntent', conv => {
// validation
const checkInDateString = conv.parameters[CHECK_IN_ARGUMENT];
const checkOutDateString = conv.parameters[CHECK_OUT_ARGUMENT];
var checkInDate = new Date(checkInDateString);
var checkOutDate = new Date(checkOutDateString);
console.log("Check-in date is: " + checkInDate.getTime());
console.log("Check-out date is: " + checkOutDate.getTime());
if (checkInDate.getTime() > checkOutDate.getTime())
{
conv.close('Pick a check-out date that is later than the check-in date!');
console.error('The check-in date must be before the check-out date!');
}
else
{
// save to db.
}
});
I don't want to close the conversation, but rather to do a re-prompt for the last question.
This is the first attempt after the check-out date failed.
and this is the second attempt:
For adding a re-prompt after checking the date, you need to handle the parameters/slots in the NodeJS code by enabling "Enable webhook call for slot filling" at the bottom of the "add intent".
With this, for every parameter required, the webhook NodeJS code will be called and you can check the validity of the parameters.
The important point will be the re-prompt. When you want to re-prompt for correct parameter, you need to set the context programmatically. The issue will be that while collecting slots, dynamic context is generated by the Dialogflow for individual parameters.
You need to identify the context associated with your date parameter and if re-prompt, set that context with lifespan 2 so as to collect the parameter again.
A better way would be to have a separate individual intent for all the parameters that you want to validate. This way you will not have to identify the dynamic context and you can play with your own context while re-prompting.
Update - using second approach
Identify the slots that require validation.
Remove them from the current intent.
Create separate intents for each slot that require validation.
Enable webhook for these intents (not for the slot as you are collecting only one).
In the webhook, if the validation fails, set the output context same as the input so as to trigger the same intent.
Respond back with re-prompt response.
You want to use conv.ask() instead of conv.close(). Using ask() will send the message in the same way but will expect the user to respond. As the name might suggest, close() does close the microphone and end the conversation.
Additionally here for simplicity, consider using contexts, as those accomplish some persistence of state.
In your example, the action can fail correctly (as it should), but also save the check-in date so the next call can run correctly with both dates. The "7th March 2018" request can also trigger the same action, but read the check-in date already saved and function correctly.
Related
I am using contexts within Dialogflow to call the next intent for the user. What I would like to do is have the ability for someone to change their mind on an answer they just entered. For example, as seen in the image below, if I enter a name then it would ask for an email. However, the user should be able to say "can I change my name" and go back to the context where Dialogflow is asking for a name.
I already have that intent implemented but I am trying to figure out how to go back to the question they were going to answer before deciding to change their name. I can use fulfillment to capture the raw API response and possibly get the last context however how can I force the user after changing their name to go back their previous context/intent?
You can do this easily by using the fulfillment. You have to save the previous intent contexts and prompt as well as the next intent contexts and prompt in the parameters of the intent.
I am writing you to ask a question about Dialogflow fulfillments.
I am trying to create an agent for Google Home and my backend is basically a web hook implemented in TypeScript.
In the conversation that I designed, the user requests to the agent to perform an action, providing a category as paramter. Now, the set of possible categories can vary through time, so I am using the entity type #sys.any to detect the parameter.
My problem is that, when on the fulfillment I try to identify the specific category on which the agent needs to take action, it may be the case that the requested paramter matches multiple cateogries, so I'd need a followup intent to ask the user to clarify which is the actual category it wants to select.
E.g. the conversation could be the following:
Agent: 'Welcome.'
User: 'Do action on **category**'
Agent: 'I have found **categoryA**, **categoryB** and **categoryC**. Please specify which one you want to select.'
User: 'Select the second || Select **categoryB**'
Agent: 'Great, action performed on **categoryB**'
Now, I was able to build this conversation using followup events and contexts: for example I created two followup events, one that detects the numbers and another that detects the text, so the user is driven on one or another depending on what it says (if the user says 'The first', a number is detected and in the backend I cycle the categories selecting the one that is associated to that index. I do a similar operation if the user says "categoryX", but inside a different intent).
What I want to understand is: what is the proper way to achieve that kind of conversation through the Node.js fulfillment API?
Thank you for any help.
From your description - you've done precisely the right thing (although you don't need followup intents).
When you reply with the options the user has, you include a Context that may contain the array of possible results. You then create Intents that have this as an Input Context, match either the index of the array (lets call this the match.index Intent) or by name (the match.name Intent).
In your webhook, the match.index Intent would determine which category was actually chosen, and then call a function that takes care of that category. Similarly, the webhook for match.name would take the parameter with the name and call the same function to take care of that category.
In my dialogflow chatbot i am creating i have a scenario where a user can ask what are the available vacancies you have or they can directly ask i want to join as a project manager or something. Both are in the same intent called "jobs" and the position they want is a required parameter. If user don't mention the position (eg - "what are the available vacancies you have" ) it will list all available vacancies and minimum qualifications need for that vacancy and ask user to pick one (done with slotfilling for webhook.). Now since the intent is waiting for the parameter when user enter the position they like it will provide the details regarding that position. But even when user is trying to ask for something else (trying to call to a another intent or they don't have enough qualifications for that vacancy or the needed job is not listed with the available job list) since that parameter (the Job position) is not provided it ask again and again what is the position you want.
how do i call to another intent when the chatbot is waiting for a required parameter
There is a separate intent for "The job i want is not here". If i typed the exact same one i used to train that intent then i works. but if it is slightly different then it won't work
Try this:
make your parameter as "NOT" required by unchecking the required checkbox.
keep webhook for slot filling.
in the webhook, keep a track if the parameter is provided or not.
if the intent is triggered, check programmatically for parameter and ask the user to provide it by playing with the contexts.
if the user said something else, then there will be no "required" parameter as per Dialogflow and it will not ask repeatedly to provide the parameter.
Let me know if this helped.
Lets say I have two Intents QuotationIntent and SalesRepresentativeIntent.
The QuotationIntent, gets some input from the user and returns appropriate result through web-hook. After successful fulfillment, I want to trigger the SalesRepresentativeIntent to check with the user if they want our sales representative to call them. I am able to trigger the Intent through events. But the problem is QuotationIntent fulfillment message is skipped.
I don't want to add a follow up intent directly to QuotationIntent, as there are many intents from which I will have to trigger SalesRepresentativeIntent.
Can you please tell me how to achieve this? Thanks in advance.
You may use context here. Add output context say "QuotationDone" in your QuotationIntent. Use the same context as the input context for SalesRepresentativeIntent. This way SalesRepresentativeIntent will be triggered only when QuotationIntent is completed.
To trigger SalesRepresentativeIntent you need to add either "user says" phrases and train your agent or add EVENTS to your intent.
This way your SalesRepresentativeIntent will only be triggered when the following condition met:
if((inputContext is present) AND (event is triggered OR user says phrase is present)){
trigger `SalesRepresentativeIntent`
} else {
fallback intent called
}
The other way you can do your task is to use SLOTS. Here in single intent, you can have multiple parameters collected. Add parameters that you want to collect. In your case whatever you are collecting in QuotationIntent you can collect it in first few parameters and make them as required and then the things you need to collect in SalesRepresentativeIntent you can collect in other parameters in the same intent. Arrange the order of the parameters in the order you want your bot asks from your users. This way your responses will be asked automatically depending on the parameters are collected from the user or not.
I'm building Alexa skills using Node.js in a lambda function and can't find any tutorials on the best way to confirm the data I have in the slots. I got to the point that all slots now have data but would like to have Alexa read back the request and get a confirmation from the user before proceeding. What's the best & proper way to do this?
At first I thought to use an emit with :elicitSlot but then I would need a new slot to do this and it looks very hackish.
for example:
if(all slots have a valid value){
this.emit(':elicitSlot','confirm',"You're request is .... with data .... is this correct?");
}
if(user confirmed data is valid){
// do something
}else{
// the data was not correct get the right data
}
For the whole intent confirmation, check here. For only slot confirmation, check here.
Also, for your followup question,
can the confirmation for the skill and slots be fine tuned for example if one of the slots is something like a name and alexa knows 100% what name I said can it skip the confirmation?
Short answer - of course you can if you do not maintain the dialog. However, it's strongly discouraged to rely on that.
In order to maintain a dialog, you have to monitor dialogState attribute of the intent request, and as long as it's not in state COMPLETED send response with attribute directives as [{'type': 'Dialog.Delegate'}] to keep it flowing. You can maintain finer control of the dialog - consult this doc. Moreover, you are strongly suggested to omit outputSpeech and reprompt in those responses, otherwise Alexa gets upset. Once dialog status is COMPLETED, you get confirmationStatus (for both Intent and slots) - SUCCESS(?)/DENIED/NONE. If the confirmation is not successful. I have seen multiple matches being sent as reply. However, when successful, only the matched slot value is returned.
P.S. I have had this weird issue. When Alexa is asking for confirmation for one slot value, if I deliberately decline twice in a row, it gives up and does nothing! Although, pretty much 99% of the time Alexa was spot on.
P.P.S. Turns out 2 attempts was a hard limitation from Alexa. This is supposed to be improved in next iterations.