Being able to handle date and time expressions is crucial for many applications. Think of bots for travel booking or insurance claims for example. Teneo provides a DateTime Handler which can be used to catch date and time expressions from the user input. The DateTime Handler consists of three components:
Many date and time expressions have to be interpreted with respect to an anchor date and time. For example "tomorrow" denotes different dates, depending on when it has been said. The following table contains some examples returned by the DateTime Handler. DateTime expression is what the user said, DateTime representation1 reflects what the DateTime library caught and DateTime interpretation is a map containing Java LocalDates and Java LocalTimes returned by the interpretation script. Note that the assumed anchor date for the interpretations below was November 9th 2018:
DateTime expression | DateTime representation1 | DateTime interpretation |
---|---|---|
Tomorrow | [ date: [ named_relative: tomorrow ]] | [ date: [ start: [ 2018-11-10 ], type: point ] time: [ start: [ 00:00 ]]] |
August 14th, 2019 | [ date: [ month: 8, day_of_month: 14, year: 2019 ]] | [ date: [ start: [ 2019-08-14 ], type: point ] time: [ start: [ 00:00 ]]] |
Monday at 3 o'clock | [ date: [ weekday: mon ], time: [ hour:3, meridiem: ampm ]] |
[ date: [ start: [ 2018-11-12 ], type: point ], time: [ start: [ 03:00, 15:00 ], type: point ]] |
Today, between 15:30 and 16:15 |
[ date: [ named_relative: today ], time: [ relation: between, time1: [ hour: 3, meridiem: pm, minute: 30 ], time2: [ hour: 4, meridiem: pm, minute: 15 ]]] |
[ date: [ start: [ 2018-11-09 ], type: point ], time: [ start: [ 15:30 ], end: [ 16:15 ], type: range ]] |
As you can see from the examples, there are cases where it is not clear which exact time the user meant. In such cases, the interpretation simply contains both alternatives, as "03:00" and "15:00" for "3 o'clock". The ambiguity can then be resolved in the solution, if needed.
In the following, we will show you how to add the DateTime Handler to your solution. Basically, there are three things you need to do:
You can assign the DateTime library in the same way as you assign Lexical Resource. Visual instructions of how to do that can be found here. The first part of the DateTime Handler is now assigned. However, before you can use it, you still have to setup the global listener and add the .JAR file for the interpretation part.
The DateTime library assigned above recognizes the vast majority of all DateTime expressions. However, for collated DateTime expressions like '11h30' that consist of one word but bear several units (here: hours and minutes), we use a global listener instead. This is how you set it up:
DateTime Handler: identify merged date/time expressions
.%TRUE.SCRIPT
in the 'Condition' field. This way, the pre-listener is always active.// The DateTime library recognizes the vast majority of all DateTime expressions.
// However, for collated DateTime expressions like '11h30' that consist of one word
// but bear several units (here: hours and minutes), we use this global listener instead.
datetime.Handler.preProcess(_)
This step concludes the recognition part of the DateTime Handler. Now the only thing that remains to be done is to add the interpretation script, which we will address in the next section.
Now it's time to download the .JAR file which is required for the interpretation of the DateTime representation. Note that you have to unzip it before you can import it to Teneo:
Visual instructions of how to import a .JAR file to your solution can be found here.
That's it! You can now use the DateTime Handler in your solution!
In the following, we will build a simple example flow that makes use of the DateTime Handler to book tables.
We will first set-up the basic flow structure:
Book a table
.I want to book a table
I would like to book a table
I'd like to book a table
Can I book a table
Can I make a reservation for a table
Could I book a table
I want to book a table
.When do you want to book it?
into the 'Answer text field'. Name the node When?
.Interpret date and time
.Booking confirmation
.This is how your flow should now look like:
In the following, we will add content to the empty nodes and add conditions to the transitions.
Teneo's DateTime library features numerous different language objects that can be used to catch date and time expressions in the user input. Some of which are illustrated in the table below. Depending on which kind of DateTime expressions you are expecting from the user, i.e only date or only time or only weekdays, you may use different language objects. All language objects in the English DateTime library start with the prefix 'DT'. You can thus simply search for DT*
in Teneo's search interface (prefixes for languages other than English can be found in the grey box below), to see all language objects that belong to the DateTime library. We recommend to start from the main object, DT_DATE_TIME.PHR and then cllick your way through the language objects used there and continue doing so until you found the level of granularity that you were looking for.
Language Object Name | Coverage | Examples |
---|---|---|
%DT_DATE_TIME.PHR | Combinations of date and time expressions | 18:30 on August 14th, Tomorrow at 5 o'clock |
%DT_DATE.PHR | Date expressions | 14.08.2019, Monday next week, five days from now |
%DT_TIME.PHR | Time expressions | 13:40, at quarter past eight, at 5pm |
For other languages the DateTime Handler's language objects bear a different prefix:
Dutch (NLDT*
), French (FRDT*
), German (DEDT*
), Italian (ITDT*
), Norwegian (NODT*
) and Swedish (SVDT*
).
In our example, we will use the most general one, DT_DATE_TIME.PHR:
dateTimeRepresentation
to your flow and assign it the default value [:]
. Get date and time
%DT_DATE_TIME.PHR^{dateTimeRepresentation = lob.datetime}
into the transition's condition field.While not fully functional yet, you can now use the output node 'Booking confirmation' to print the intermediate DateTime representation:
Great! I booked a table for ${dateTimeRepresentation}
in the 'Answer text' field.You should now get the following response:
User: I want to book a table
Bot: When do you want to book it?
User: Tomorrow, 6:30.
Bot: Great! I booked a table for [ date: [ named_relative: tomorrow ], time: [ hour: 6, meridiem: ampm, minute: 30 ]]
Note that this is the intermediate DateTime representation which simply reflects what the user said. This representation is not really meant to be printed to the user. We just wanted to show you what happens internally here. For example, you can see that the time expression '6:30' is ambiguous with respect to am/pm. We will show you below how you can resolve such ambiguities. In order to get an actual date and time, this representation needs to be handed over to the interpreter. In the next section, we will show you how.
Go back to the 'Book a table' flow in edit mode. Then:
dateTime
and assign it the default value [:]
.dateTime = datetime.Handler.interpret(dateTimeRepresentation)
into the 'Script Action' field.Booking confirmation
node, delet the existing answer and replace it with: Great! I booked a table for ${dateTime.time.start[0]} on ${dateTime.date.start[0]}
. This selects the first time point ('time.start[0]') and the first date point ('date.start[0]') from the date time map which the interpreter returned and prints it to the user in a more readable format.Now go ahead and give it a try in try out! For the dialog above, you should now get the following answer (assuming you spoke to the bot on November 9th):
User: I want to book a table.
Bot: When do you want to book it?
User: Tomorrow, 6:30.
Bot: Great! I booked a table for 6:30 on 2018-11-10.
Note that the expression 'DateTime.time.start[0]' picks the first available start time that the interpreter script returned. However, as you have seen from the internal representation above, this time expression was ambiguous with respect to am/pm ( 'meridiem : ampm' ). In the following, we illustrate some disambiguation strategies.
Many time expressions like "6:30" or "3 o'clock" are ambiguous as to whether they denote 'am' or 'pm'. The DateTimeInterpreter returns both possible times for such expressions: "06:30" and "18:30". However, for many applications it is crucial to correctly disambiguate such time expressions. We will in the following illustrate two disambiguation strategies that you may use in your solution. One is to disambiguate the representation before sending it to the interpretation script, and the other one is to disambiguate what the interpretation script returned.
The safest way to disambiguate a time expression is to let the user disambiguate it. The fact that time expressions are ambiguous with respect to 'am'/'pm' is visible from the intermediate DateTime representation. Thus, it can be resolved there before it is handed over to the DateTime interpretation script:
Resolve ambiguity
.Ambiguous Time
.Resolve am/pm
.The basic structure is now in place. Time to fill it with content!
{dateTimeRepresentation.containsKey('time') && dateTimeRepresentation.time.meridiem=='ampm'}
to the condition field. This condition is fulfilled if the DateTime expression holds a time and if this times does not hold a determined 'am' or 'pm'.Do you mean ${dateTimeRepresentation.time.hour} am or pm?
. For our example this will return 'Do you mean 6 am or pm?'.(am)^{dateTimeRepresentation.time.meridiem='am'}
/
(pm)^{dateTimeRepresentation.time.meridiem='pm'}
That's it. You should now get the following dialog:
User: I want to book a table.
Bot: When do you want to book it?
User: Tomorrow, 6:30.
Bot Do you mean 6 am or pm?
User: pm
Bot: Great! I booked a table for 18:30 on 2018-11-10.
In the previous section we have shown how the decision about 'am' vs 'pm' can be returned to the user to request clarification. Sometimes however, the context only allows one interpretation and in such cases we should avoid asking the user. Let's say that we still want to book a table. As the restaurant is open from 5pm to 11pm, all table bookings will denote 'pm'. In cases where the DateTime interpreter returns more than one possible time, we will thus always select 'pm'.
This is how we will go about: before returning the DateTime interpreter's answer to the user, we will select the 'pm' time, if applicable. Whenever two times are returned, the second one (at index 1) is always 'pm'. If this is the case, we copy the 'pm' value from index 1 to index 0. This way, we do not have to modify the output node:
if (dateTime.time.start[1]) {
dateTime.time.start[0] = dateTime.time.start[1]
}
That's it. When talking to your bot, you should now always get the 'pm' interpretation for ambiguous time expressions like 6:30:
User: I want to book a table.
Bot: When do you want to book it?
User: Tomorrow, 6:30.
Bot: Great! I booked a table for 18:30 on 2018-11-10.
For some date and time expressions the interpretation depends on the conversation context. For example, the expression 'on Wednesday' may be interpreted as a date in the past or in the future. The following example dialoge happened on Friday, November 9th 2018:
User: I arrived in Barcelona on Wednesday.
Bot: You mean 2018-11-07, right?
User: I will arrive in Barcelona on Wednesday.
Bot: You mean 2018-11-14, right?
By default, the interpretation direction is 'forward', so 'on Wednesday' would be interpreted as the following Wednesday. It is possible to change this interpretation direction to 'back' to point to the previous Wednesday instead. We show how to edit the default interpretation direction in the next section. Here, we will show you how you can take advantage of the verb tense to make an appropriate decision. One component of the Teneo Input Processing Chain assignes part-of-speech tags to all words of the user input. We will make use of one of these tags, %$PAST.POS, which indicates that a verb occurred in past tense in order to set the interpretation direction to 'back'. In the following, we build a small example flow in order to illustrate the functionality:
Disambiguate Interpretation Direction
.dateTimeRepresentation
and assign it the default value [:]
. It will store the representation of the DateTime expression uttered by the user.pastTense
and assign it the default value null
. This one will store whether or not a past tense tag was found in the user input.dateTime
and assign it the default value null
. It will store the DateTime interpretation.Visual instructions on how to create a flow with a syntax trigger can be found here. For instructions on how to add flow variables see here.
DateTime + Tense
.
%DT_DATE_TIME.PHR^{dateTimeRepresentation=lob.datetime}
&^
(%$PAST.POS^{pastTense = true}):o
dateTime = pastTense?datetime.Handler.interpret(dateTimeRepresentation, "back"): datetime.Handler.interpret(dateTimeRepresentation)
This will call the interpreter with the interpretation direction 'back' if the pastTense variable has been set in the Trigger condition. Otherwise, the interpreter will be called with the default interpretation direction "forward" (which does not need to be explicitly specified).
Call Interpreter
.You mean ${DateTime.date.start[0]}, right?
into the Output node and name it You mean ... right?
.Anchor date
By default, the DateTime interpretation script assumes the current day to be the anchor date for relative date expressions like 'tomorrow' or 'Monday next week'. Should it be necessary for you to change this anchor date, you can do so by adding the desired anchor date to the DateTime interpreter calll. Say you want "14th of August 2019" to be your anchor date. Then, the DateTime interpreter call in the script node of your flow will look like this: dateTime = datetime.Handler.interpret(dateTimeRepresentation, "2019-08-14")
. Please note that the new anchor date must be passed in ISO-8601 format and put into quotes (""). If you want to change the anchor date globally for the whole solution, go to the global pre-processing script and paste datetime.Handler.setAnchor("2019-08-14")
. Note that you have to restart the conversation before changes in the global script will apply.
Anchor time
You may not only modifiy the anchor date, but also the anchor time, if neccessary. In order to do so, simply add the time to the anchor date by keeping the ISO-8601 format, like so: dateTime = datetime.Handler.interpret(dateTimeRepresentation, "2018-11-21T1630")
. The first two digits after the 'T' denote the hour and the last two digits the minutes of the anchor time.
Interpretation direction
For some expressions like 'on Monday' or 'in September' the interpretation depends on the context. They may denote a date in the past or in the future. Depending on the domain for which you created your bot, different interpretation directions might be appropriate. For example, in our table booking domain, one can assume that all dates occuring in the conversation denote future events. However, in an insurance claim domain a backwards interpretation direction is more suitable. By default the interpretation direction is set to 'forward', but you can change it to 'back', by adding it to the DateTime interpreter call: dateTime = datetime.Handler.interpret(dateTimeRepresentation, "back")
.
Both
You may also change both, the anchor date and the interpretation direction, at once: dateTime = datetime.Handler.interpret(dateTimeRepresentation, "2018-11-21T1630", "back")
.
The DateTime Handler covers a wide range of different date and time expression and it always returns the most plausible interpretation. However, if neccessary, you may adapt the DateTime Handler for example to recognize named days or to adjust the interpretation of existing dates and times. For more information, read this page on Advanced Usage.
Was this page helpful?