Good day All,
I have a situation where am building the fulfilment service for the Flights Pre-built agent in Dialogflow. Below is a sample interaction in the application.
I want a return flight from London to New York - DialogFlow/Fulfilment back-end picks up the users Ticket-Type[return], To[New York] and From[London] entities.
The fulfilment service responds with - What date do you plan to travel? E.g next week Monday or 1st of April
User enters Tomorrow - Dialogflow captures the users Departure Date Entity, we will call this Intent the Departure Intent.
Fulfilment service now goes on to ask -
What date do you plan to return? E.g next week Monday or 1st of April, i will call this the Return Intent
User enters next week monday - Dialogflow will still match the Departure Intent from step 3 and this will cause a response back to the user for the same Return date. But if the user enters i will return next week monday then then the return date intent is matched.
So my question is how do i make the Return Intent match over the Departure Intent since i have captured the data for Departure and i cannot expect the user to also use the phrase that works with the dates?
Updated with the Screenshots of affected Intents
URL to Logs - https://jsbin.com/wofefivuqo/edit?js
sample code
Return Screenshot -
The general solution for this is to set a Context once you have the departure date. (For example, you can call it departure-set.) You then condition your Intent that gets the return date to say it expects departure-set in the Incoming Context. In these cases, it will favor the Intent that has the Context that matches over the one that doesn't (or that has a different Context.)
In your example, you have two Input Contexts, which is fine, but it means that both Contexts must be present for the Intent to be triggered. I don't know what the lifespan is for these two Contexts, but I noticed that your departure-set Context only has a lifespan of 1, which means it will only be valid on the next response from the user. If you did the same thing for the flight Context, then it is likely no longer valid at this point in the conversation.
Related
The DialogFlow documentation writes that the base WelcomeDefaultIntent is triggered either by matching training phrases or every time the user starts a dialogue. But this is not true. If the user's phrases match one of the training phrases of another intent, this intent is triggered, instead of a WelcomeIntent. As a result, the user does not understand that he is communicating with the bot and the quality of service fall down. Please, give a hint, how to make the DefaultWelcomeIntent always works first when the user starts a dialogue, no matter what he wrote. I hope on you
That is an expected behavior. As the documentation mentions:
The default welcome intent is matched in one of two ways:
One of its training phrases are matched, which are pre-populated with
common greetings, like "hello".
This intent has a welcome event
attached to it, which is triggered when the end-user begins a
conversation with your agent via a supported integration.
However, it doesn't specify that no other intents can be matched at the beginning of a conversation. At the end of the day, the default welcome intent is just another intent that is automatically created alongside the agent, and pre-populated with training phrases. Intents will always "compete" with each other's matching phrases, so the best intent gets selected according to the user input, regardless of whether the intent is the welcome default intent or not.
From a natural conversational point of view, it doesn't makes much sense to "force" the welcome intent to always be triggered at the beginning of a conversation, regardless of the user input. An example could be:
User: What time is it?
Bot: It's 1:55 pm PT.
And you would be forcing this into something like:
User: What time is it?
Bot: Hey, my name is Bot, how can I help you?
User: What time is it?
Bot: It's 1:55 pm PT.
Adding an extra interaction for the user.
However, if you do want to force your welcome intent at the start of a conversation, or your use case requires to, you could try with:
Dialogflow Contexts, or.
Using the Detect Intent API method, which can receive a EventInput object that allow for matching intents by event name instead of the natural language input. Hence, you could use this to match the intent attached to the Welcome event, regardless of the user input.
I have an entity (items) and its values are ('name', 'colour', 'awards')
I have three intents
Intent1 = Welcome Intent (user will get the options in the form of chips)
Intent2 = Select Option (bot will ask question to enter detail for selected option)
Intent3 = Update Option (bot will save the record and ask next option to update.)
Example -
bot: welcome! what you want to update? name, colour, awards.
user: name
bot: Enter your name.
user: John
bot: record updated, what to update next? name, colour, awards.
now the issue is awards have multiple fields to update, to update awards a user has to provide three things (award name, award date, award description)
What I want is when a user selects awards options from the chips then it should be taken to new intent where I will get all the data through slot filling.
The first thing to remember is that an Intent represents what the user has said and not what you are doing with what they have said. So it doesn't make sense to say that you are "going to an Intent".
Second, while slot filling seems like a good idea, it usually leads to further problems, since it doesn't handle conditional information well, or handle users if they skip around in what they want to update.
All of these are better solved by setting up a state machine where they are in the conversation, what information you need, and what they have provided so far. Based on these settings, you can prompt them yourself for what you expect next. (You may also find using one or several Dialogflow contexts useful for shaping how to accept results as well.)
So, for example, when the user has indicated they are updating the awards, it might work like this:
User: Awards
[Your fulfillment sets the 'awards' context with a parameter that we are prompting for the name.]
Bot: Ok, I'm going to need the award name, description, and when it was awarded. What is the name?
User: Merit
[This matches the Fallback Intent with an Input Context for 'awards', since it is free-form input. Your fulfillment stores this and sets the 'awards' context with a parameter that we are now prompting for the date.]
Bot: Got it, the award is named Merit. When was it awarded?
User: Today
[This matches an Intent with a training phrase of "<#sys.date>" and the Input Context of 'awards'. There are also training phrases for things like "It was awarded <#sys.date>" and so forth. Your fulfillment sets the date and sets the 'awards' context with a parameter that we're now prompting for description.]
Bot: Got it. Awarded on March 1st. What is the description?
User: They were awesome.
[This matches the Fallback Intent with the Input Context of 'awards' again, because it is still free-form input. Our fulfillment, however, knows that this is about the description this time, so it stores it and removes the 'awards' context since we've captured everything.]
Bot: I've recorded that as a description of "they were awesome" - sure thing. That was everything we needed for now. Do you want to update the name, colour, or awards next?
That all seems pretty straightforward. But consider if the conversation had gone this way:
User: Awards
[Your fulfillment sets the 'awards' context with a parameter that we are prompting for the name.]
Bot: Ok, I'm going to need the award name, description, and when it was awarded. What is the name?
User: [Having done this many times] They were given the award for Honor yesterday
[This might match an Intent with an Input Context of 'awards' and the training phrase of "Given the award for <#sys.any> <#sys.date>" and possibly "<#sys.date> they got an award for <#sys.any>". Your fulfillment sets the name and date from this, sees what information it still needs, and prompts with...]
Bot: Got it. Award named Honor. Awarded March 1. What is the description?
User: Actually, it is named Honorable Service
[This matches an Intent with a training phrase of "named <#sys.any>" and an Input Context for 'awards'. Your fulfillment changes the name stored, checks what we still need, and again prompts...]
Bot: Ok, I've changed the award name to Honorable Service. What is the description?
The first scenario could be handled by slot filling and simple prompting, but the second can't. Being able to handle more natural responses from people and more flexible prompting will be better for your users.
I want to be able to handle an intent where the user provides either a date period or a date in their phrase.
E.g., "What's my scheduled today" or "What's my schedule this week".
Using #sys.date-period serves an empty parameter to my webhook when "today" is used, and using #sys.date serves an empty parameter when "this week" is used.
Is there a way to accomplish this other than using #sys.any and deciphering the type of parameter myself in my fulfillment?
Use #sys.date-time entity to get the date, I'm using it in my bot and it's working fine with any of the cases that you've mentioned.
It easily identifies today, tomorrow or general date format (i.e. 21st Jan).
For more information see this documentation
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.
I've got a order flow that I've setup. I have one intent to get quantity and then I have another to get address. I have the address entity to start by asking for a zipcode/postcode and then a follow up to ask for house number/name.
When I ask for the house number or name my parameters entity is set to sys.any. Because we may get just a house number but could also get something like 'Hill Farm' or 'Flat 4b'. The issue is that when the user inputs a number it actually goes back and triggers the quantity intent which is a #sys.nymber-integer entity. I thought the follow up intent would keep it focused on looking for a house no/name.
I've carried the context along from the quantity question thinking that it won't ask for it again but it still does so.
I've changed the entitys from sys.any to sys.number-integer for $houseno and sys.any for $housename. However entering a number still triggers my quantity intent. Anyone have any ideas?
The solution is to use Context to instruct DialogFlow.
Step 1:
For the Address Intent train the intent with all the User says data that you have and set an Out-Context - e.g adress-data. Add another intent that will capture house number and then add all the User says entries as usual. However also set the In-Context to address-data
Step 2:
Create your Quantity Intent as you have now and save.