From 2b0b96c8b20373b442e58c1a3e843cde441bf378 Mon Sep 17 00:00:00 2001 From: Martin Battaglino Date: Fri, 9 Apr 2021 15:09:27 -0300 Subject: [PATCH 1/7] Add pom file --- samples/40.timex-resolution/pom.xml | 204 ++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 samples/40.timex-resolution/pom.xml diff --git a/samples/40.timex-resolution/pom.xml b/samples/40.timex-resolution/pom.xml new file mode 100644 index 000000000..9327e53d1 --- /dev/null +++ b/samples/40.timex-resolution/pom.xml @@ -0,0 +1,204 @@ + + + + 4.0.0 + + com.microsoft.bot.sample + bot-timex-resolution + sample + jar + + ${project.groupId}:${project.artifactId} + This package contains a Java Timex Resolution sample. + http://maven.apache.org + + + org.springframework.boot + spring-boot-starter-parent + 2.4.0 + + + + + + MIT License + http://www.opensource.org/licenses/mit-license.php + + + + + + Bot Framework Development + + Microsoft + https://dev.botframework.com/ + + + + + 1.8 + 1.8 + 1.8 + com.microsoft.bot.sample.timex.resolution.Application + + + + + com.microsoft.bot + bot-dialogs + 4.6.0-preview9 + + + + + + build + + true + + + + + src/main/resources + false + + + + + maven-compiler-plugin + 3.8.1 + + + maven-war-plugin + 3.2.3 + + src/main/webapp + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + com.microsoft.bot.sample.timex.resolution.Application + + + + + + com.microsoft.azure + azure-webapp-maven-plugin + 1.12.0 + + V2 + ${groupname} + ${botname} + + + JAVA_OPTS + -Dserver.port=80 + + + + linux + Java 8 + Java SE + + + + + ${project.basedir}/target + + *.jar + + + + + + + + + + + + publish + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + maven-war-plugin + 3.2.3 + + src/main/webapp + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.8 + true + + true + ossrh + https://oss.sonatype.org/ + true + + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + 8 + false + + + + attach-javadocs + + jar + + + + + + + + + From 2470a80f9a4e5324afe86a4b44f69e1092ebc4a0 Mon Sep 17 00:00:00 2001 From: Martin Battaglino Date: Fri, 9 Apr 2021 15:09:44 -0300 Subject: [PATCH 2/7] Add root files --- .../sample/timex/resolution/Ambiguity.java | 123 ++++++++++++++++++ .../sample/timex/resolution/Constraints.java | 43 ++++++ .../timex/resolution/LanguageGeneration.java | 40 ++++++ .../bot/sample/timex/resolution/Parsing.java | 49 +++++++ .../bot/sample/timex/resolution/Ranges.java | 76 +++++++++++ .../sample/timex/resolution/Resolutions.java | 47 +++++++ 6 files changed, 378 insertions(+) create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ambiguity.java create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Constraints.java create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/LanguageGeneration.java create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Parsing.java create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ranges.java create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Resolutions.java diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ambiguity.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ambiguity.java new file mode 100644 index 000000000..1f40a6848 --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ambiguity.java @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.sample.timex.resolution; + +import com.microsoft.recognizers.text.Culture; +import com.microsoft.recognizers.text.ModelResult; +import com.microsoft.recognizers.text.datetime.DateTimeRecognizer; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; + +/** + * TIMEX expressions are designed to represent ambiguous rather than definite dates. + * For example: + * "Monday" could be any Monday ever. + * "May 5th" could be any one of the possible May 5th in the past or the future. + * TIMEX does not represent ambiguous times. So if the natural language mentioned 4 o'clock + * it could be either 4AM or 4PM. For that the recognizer (and by extension LUIS) would return two TIMEX expressions. + * A TIMEX expression can include a date and time parts. So ambiguity of date can be combined with multiple results. + * Code that deals with TIMEX expressions is frequently dealing with sets of TIMEX expressions. + */ +public final class Ambiguity { + + private Ambiguity() { + } + + /** + * This method avoid ambiguity obtaining 2 values, backwards and forwards in the calendar. + */ + public static void dateAmbiguity() { + // Run the recognizer. + List results = DateTimeRecognizer.recognizeDateTime( + "Either Saturday or Sunday would work.", + Culture.English); + + // We should find two results in this example. + for (ModelResult result : results) { + // The resolution includes two example values: going backwards and forwards from NOW in the calendar. + LinkedHashSet distinctTimexExpressions = new LinkedHashSet<>(); + List> values = (List>) result.resolution.get("values"); + for (Map value : values) { + // Each result includes a TIMEX expression that captures the inherent date but not time ambiguity. + // We are interested in the distinct set of TIMEX expressions. + String timex = value.get("timex"); + if (timex != null) { + distinctTimexExpressions.add(timex); + } + + // There is also either a "value" property on each value or "start" and "end". + // If you use ToString() on a TimeProperty object you will get same "value". + } + + // The TIMEX expression captures date ambiguity so there will be a single distinct + // expression for each result. + String output = String.format("%s ( %s )", result.text, String.join(",", distinctTimexExpressions)); + System.out.println(output); + + // The result also includes a reference to the original string + // but note the start and end index are both inclusive. + } + } + + /** + * This method avoid ambiguity obtaining 2 values, one for AM and one for PM. + */ + public static void timeAmbiguity() { + // Run the recognizer. + List results = DateTimeRecognizer.recognizeDateTime( + "We would like to arrive at 4 o'clock or 5 o'clock.", + Culture.English); + + // We should find two results in this example. + for (ModelResult result : results) { + // The resolution includes two example values: one for AM and one for PM. + LinkedHashSet distinctTimexExpressions = new LinkedHashSet<>(); + List> values = (List>) result.resolution.get("values"); + for (Map value : values) { + // Each result includes a TIMEX expression that captures the inherent date but not time ambiguity. + // We are interested in the distinct set of TIMEX expressions. + String timex = value.get("timex"); + if (timex != null) { + distinctTimexExpressions.add(timex); + } + } + + // TIMEX expressions don't capture time ambiguity so there will be two distinct expressions for each result. + String output = String.format("%s ( %s )", result.text, String.join(",", distinctTimexExpressions)); + System.out.println(output); + } + } + + /** + * This method avoid ambiguity obtaining 4 different values, + * backwards and forwards in the calendar and then AM and PM. + */ + public static void dateTimeAmbiguity() { + // Run the recognizer. + List results = DateTimeRecognizer.recognizeDateTime( + "It will be ready Wednesday at 5 o'clock.", + Culture.English); + + // We should find a single result in this example. + for (ModelResult result : results) { + // The resolution includes four example values: backwards and forward in the calendar and then AM and PM. + LinkedHashSet distinctTimexExpressions = new LinkedHashSet<>(); + List> values = (List>) result.resolution.get("values"); + for (Map value : values) { + // Each result includes a TIMEX expression that captures the inherent date but not time ambiguity. + // We are interested in the distinct set of TIMEX expressions. + String timex = value.get("timex"); + if (timex != null) { + distinctTimexExpressions.add(timex); + } + } + + // TIMEX expressions don't capture time ambiguity so there will be two distinct expressions for each result. + String output = String.format("%s ( %s )", result.text, String.join(",", distinctTimexExpressions)); + System.out.println(output); + } + } +} diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Constraints.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Constraints.java new file mode 100644 index 000000000..d21b6a3ab --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Constraints.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.sample.timex.resolution; + +import com.microsoft.recognizers.datatypes.timex.expression.TimexCreator; +import com.microsoft.recognizers.datatypes.timex.expression.TimexProperty; +import com.microsoft.recognizers.datatypes.timex.expression.TimexRangeResolver; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; + +/** + * The TimexRangeResolved can be used in application logic to apply constraints to a set of TIMEX expressions. + * The constraints themselves are TIMEX expressions. This is designed to appear a little like a database join, + * of course its a little less generic than that because dates can be complicated things. + */ +public final class Constraints { + + private Constraints() { + } + + /** + * This method runs the resolver examples. + */ + public static void examples() { + // When you give the recognizer the text "Wednesday 4 o'clock" you get these distinct TIMEX values back. + + // But our bot logic knows that whatever the user says it should be evaluated against the constraints of + // a week from today with respect to the date part and in the evening with respect to the time part. + + List resolutions = TimexRangeResolver.evaluate( + new HashSet(Arrays.asList("XXXX-WXX-3T04", "XXXX-WXX-3T16")), + new ArrayList(Arrays.asList(TimexCreator.weekFromToday(null), TimexCreator.EVENING))); + + LocalDateTime today = LocalDateTime.now(); + for (TimexProperty resolution : resolutions) { + System.out.println(resolution.toNaturalLanguage(today)); + } + } +} diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/LanguageGeneration.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/LanguageGeneration.java new file mode 100644 index 000000000..44e101763 --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/LanguageGeneration.java @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.sample.timex.resolution; + +import com.microsoft.recognizers.datatypes.timex.expression.TimexProperty; + +import java.time.LocalDateTime; + +/** + * This language generation capabilities are the logical opposite of what the recognizer does. + * As an experiment try feeding the result of language generation back into a recognizer. + * You should get back the same TIMEX expression in the result. + */ +public final class LanguageGeneration { + + private LanguageGeneration() { + } + + private static void describe(TimexProperty t) { + // Note natural language is often relative, + // for example the sentence "Yesterday all my troubles seemed so far away." + // Having your bot say something like "next Wednesday" in a response can make it sound more natural. + LocalDateTime referenceDate = LocalDateTime.now(); + String output = String.format("%s %s", t.getTimexValue(), t.toNaturalLanguage(referenceDate)); + System.out.println(output); + } + + /** + * This method runs the resolver examples. + */ + public static void examples() { + describe(new TimexProperty("2019-05-29")); + describe(new TimexProperty("XXXX-WXX-6")); + describe(new TimexProperty("XXXX-WXX-6T16")); + describe(new TimexProperty("T12")); + describe(TimexProperty.fromDate(LocalDateTime.now())); + describe(TimexProperty.fromDate(LocalDateTime.now().plusDays(1))); + } +} diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Parsing.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Parsing.java new file mode 100644 index 000000000..621322ed1 --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Parsing.java @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.sample.timex.resolution; + +import com.microsoft.recognizers.datatypes.timex.expression.Constants.TimexTypes; +import com.microsoft.recognizers.datatypes.timex.expression.TimexProperty; + + /** The TimexProperty class takes a TIMEX expression as a string argument in its constructor. + * This pulls all the component parts of the expression into properties on this object. You can + * then manipulate the TIMEX expression via those properties. + * The "Types" property infers a datetimeV2 type from the underlying set of properties. + * If you take a TIMEX with date components and add time components you add the + * inferred type datetime (its still a date). + * Logic can be written against the inferred type, perhaps to have the bot ask the user for disambiguation. + */ +public final class Parsing { + + private Parsing() { + } + + private static void describe(TimexProperty t) { + System.out.print(t.getTimexValue() + " "); + + if (t.getTypes().contains(TimexTypes.DATE)) { + if (t.getTypes().contains(TimexTypes.DEFINITE)) { + System.out.print("We have a definite calendar date. "); + } else { + System.out.print("We have a date but there is some ambiguity. "); + } + } + + if (t.getTypes().contains(TimexTypes.TIME)) { + System.out.print("We have a time."); + } + + System.out.println(); + } + + /** + * This method runs the parsing examples. + */ + public static void examples() { + describe(new TimexProperty("2017-05-29")); + describe(new TimexProperty("XXXX-WXX-6")); + describe(new TimexProperty("XXXX-WXX-6T16")); + describe(new TimexProperty("T12")); + } +} diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ranges.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ranges.java new file mode 100644 index 000000000..efc14f35f --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Ranges.java @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.sample.timex.resolution; + +import com.microsoft.recognizers.text.Culture; +import com.microsoft.recognizers.text.ModelResult; +import com.microsoft.recognizers.text.datetime.DateTimeRecognizer; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; + +/** + * Class with date and time ranges examples. + */ +public final class Ranges { + + private Ranges() { + } + + /** + * TIMEX expressions can represent date and time ranges. Here are a couple of examples. + */ + public static void dateRange() { + // Run the recognizer. + List results = + DateTimeRecognizer.recognizeDateTime("Some time in the next two weeks.", + Culture.English); + + // We should find a single result in this example. + for (ModelResult result : results) { + // The resolution includes a single value because there is no ambiguity. + LinkedHashSet distinctTimexExpressions = new LinkedHashSet<>(); + List> values = (List>) result.resolution.get("values"); + for (HashMap value : values) { + // We are interested in the distinct set of TIMEX expressions. + String timex = value.get("timex"); + if (timex != null) { + distinctTimexExpressions.add(timex); + } + } + + // The TIMEX expression can also capture the notion of range. + String output = String.format("%s ( %s )", result.text, String.join(",", distinctTimexExpressions)); + System.out.println(output); + } + } + + /** + * This method has examples of time ranges. + */ + public static void timeRange() { + // Run the recognizer. + List results = + DateTimeRecognizer.recognizeDateTime("Some time between 6pm and 6:30pm.", + Culture.English); + + // We should find a single result in this example. + for (ModelResult result : results) { + // The resolution includes a single value because there is no ambiguity. + LinkedHashSet distinctTimexExpressions = new LinkedHashSet<>(); + List> values = (List>) result.resolution.get("values"); + for (HashMap value : values) { + // We are interested in the distinct set of TIMEX expressions. + String timex = value.get("timex"); + if (timex != null) { + distinctTimexExpressions.add(timex); + } + } + + // The TIMEX expression can also capture the notion of range. + String output = String.format("%s ( %s )", result.text, String.join(",", distinctTimexExpressions)); + System.out.println(output); + } + } +} diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Resolutions.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Resolutions.java new file mode 100644 index 000000000..b8edf9700 --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Resolutions.java @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.sample.timex.resolution; + +import com.microsoft.recognizers.datatypes.timex.expression.Resolution; +import com.microsoft.recognizers.datatypes.timex.expression.TimexResolver; +import java.time.LocalDateTime; + +/** + * Given the TIMEX expressions it is easy to create the computed example values that the recognizer gives. + */ +public final class Resolutions { + + private static final Integer THREE = 3; + + private Resolutions() { + } + + /** + * This method runs the resolver examples. + */ + public static void examples() { + // When you give the recognizer the text "Wednesday 4 o'clock" you get these distinct TIMEX values back. + + LocalDateTime today = LocalDateTime.now(); + Resolution resolution = TimexResolver.resolve(new String[] {"XXXX-WXX-3T04", "XXXX-WXX-3T16"}, today); + + System.out.println(resolution.getValues().size()); + + System.out.println(resolution.getValues().get(0).getTimex()); + System.out.println(resolution.getValues().get(0).getType()); + System.out.println(resolution.getValues().get(0).getValue()); + + System.out.println(resolution.getValues().get(1).getTimex()); + System.out.println(resolution.getValues().get(1).getType()); + System.out.println(resolution.getValues().get(1).getValue()); + + System.out.println(resolution.getValues().get(2).getTimex()); + System.out.println(resolution.getValues().get(2).getType()); + System.out.println(resolution.getValues().get(2).getValue()); + + System.out.println(resolution.getValues().get(THREE).getTimex()); + System.out.println(resolution.getValues().get(THREE).getType()); + System.out.println(resolution.getValues().get(THREE).getValue()); + } +} From 12d0531418e6be9ecc6583d5525075aecc717c10 Mon Sep 17 00:00:00 2001 From: Martin Battaglino Date: Fri, 9 Apr 2021 15:09:57 -0300 Subject: [PATCH 3/7] Add Startup class --- .../sample/timex/resolution/Application.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Application.java diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Application.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Application.java new file mode 100644 index 000000000..df4645b51 --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/Application.java @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.microsoft.bot.sample.timex.resolution; + +/** + * This is the main program class. + */ +public final class Application { + + private Application() { + } + + /** + * This is the entry point method. + * @param args String array to capture any command line parameters. + */ + public static void main(String[] args) { + // Creating TIMEX expressions from natural language using the Recognizer package. + Ambiguity.dateAmbiguity(); + Ambiguity.timeAmbiguity(); + Ambiguity.dateTimeAmbiguity(); + Ranges.dateRange(); + Ranges.timeRange(); + + // Manipulating TIMEX expressions in code using the TIMEX Datatype package. + Parsing.examples(); + LanguageGeneration.examples(); + Resolutions.examples(); + Constraints.examples(); + } +} From 2a05a18f8e8861eec7d9b7442aa4c615905b022e Mon Sep 17 00:00:00 2001 From: Martin Battaglino Date: Fri, 9 Apr 2021 15:10:03 -0300 Subject: [PATCH 4/7] Add package-info file --- .../bot/sample/timex/resolution/package-info.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/package-info.java diff --git a/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/package-info.java b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/package-info.java new file mode 100644 index 000000000..41c20f0c7 --- /dev/null +++ b/samples/40.timex-resolution/src/main/java/com/microsoft/bot/sample/timex/resolution/package-info.java @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for +// license information. + +/** + * This package contains the classes for the timex-resolution sample. + */ +package com.microsoft.bot.sample.timex.resolution; From 92e6800226e2b990b8155c8c08cfdd0d51102270 Mon Sep 17 00:00:00 2001 From: Martin Battaglino Date: Fri, 9 Apr 2021 15:10:10 -0300 Subject: [PATCH 5/7] Add documentation files --- samples/40.timex-resolution/LICENSE | 21 ++ samples/40.timex-resolution/README.md | 357 ++++++++++++++++++++++++++ 2 files changed, 378 insertions(+) create mode 100644 samples/40.timex-resolution/LICENSE create mode 100644 samples/40.timex-resolution/README.md diff --git a/samples/40.timex-resolution/LICENSE b/samples/40.timex-resolution/LICENSE new file mode 100644 index 000000000..21071075c --- /dev/null +++ b/samples/40.timex-resolution/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/samples/40.timex-resolution/README.md b/samples/40.timex-resolution/README.md new file mode 100644 index 000000000..ec8099c95 --- /dev/null +++ b/samples/40.timex-resolution/README.md @@ -0,0 +1,357 @@ +# Timex Resolution + +This bot has been created using [Bot Framework](https://dev.botframework.com), it shows how to use TIMEX expressions. + +A number of topics are covered within this readme. + +* [Concepts introduced in this sample](#Concepts-introduced-in-this-sample) +* [To try this sample](#to-try-this-sample) +* [Testing the bot using Bot Framework Emulator](#Testing-the-bot-using-Bot-Framework-Emulator) +* [Experimenting with Recognizers](#experimenting-with-recognizers) +* [Representing ambiguity](#representing-ambiguity) +* [Representing duration](#representing-duration) +* [Representing ranges](#representing-ranges) +* [Special concepts](#special-concepts) +* [Limitations](#limitations) +* [Resolution](#resolution) +* [TIMEX resolution using the TimexExpressions library](#TIMEX-resolution-using-the-TimexExpressions-library) + +## Concepts introduced in this sample + +### What is a TIMEX expression? + +Natural language has many different ways to express ambiguous dates, ranges of dates and times and durations. However, these concepts cannot be represented with the regular [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) date time representation. This is why TIMEX exists. TIMEX takes ISO 8601 as a starting point and provides additional mechanisms for these concepts. The resulting format normalizes and formalizes these concepts such that they can be processed with regular program logic. + +Whenever the ISO 8601 representation is sufficient the TIMEX value is identical. TIMEX is often refered to as an expression because unlike a discrete data time value it can represent a set of values. This will be clear when we look at some examples. + +TIMEX expressions can be additionally described with a type. The notion of type is more descriptive than it is constraining. You can, for instance, look at a TIMEX expression and infer its type. This can be useful in application logic. For example, if a bot is expecting a datetimerange but only has a daterange then it can prompt the user according. Again this will be clear when when we look at some examples. + +## To try this sample + +- From the root of this project folder: + - Build the sample using `mvn package` + - Run it by using `java -jar .\target\bot-timex-resolution-sample.jar` + +## Experimenting with Recognizers + +TIMEX has been introduced into the bot authoring platform by the [Text Recognizers](https://github.com/Microsoft/Recognizers-Text) package. One of the best ways to understand the TIMEX behavior is to experiment directly with the Rcognizers. You can do this by install the appropriate Recognizer package, instantiating the date time recognizer and calling it with your test string. In Node you can use the following 3 lines of code, but the behavior is identical in C#, Python and Java. + +``` + const Recognizer = require('@microsoft/recognizers-text-date-time') + const result = Recognizer.recognizeDateTime("next Wednesday 4pm", Recognizer.Culture.English); + console.log(JSON.stringify(result, null, 2)); +``` + +Alternatively you can use [LUIS](https://www.luis.ai/home). When you add a datetime2 datatype to your LUIS model you are asking LUIS to run this exact same recognizer on the input. + +## Representing ambiguity + +We'll start with an example. The computer scientist Alan Turning was born on June 23rd in 1912. The ISO 8601 representation of this date would be: + +``` +1912-06-23 +``` +and this happens to also be the correct TIMEX respresentation. However, with TIMEX we can also represent Alan's birthday: + +``` +XXXX-06-23 +``` + +Here the XXXX means "any." In other words we can represent the concept of June 23rd without being specific about the year. There are many June 23rds, one every year. This is what we mean here when we say "June 23rd" is ambiguous; we know its June 23rd we just don't know which June 23rd. + +TIMEX introduces its own syntax here as an extension to the ISO 8601 format. The XXXX in the previous example, appears in place of the 4 characters that make up the year component. This at first appears to resemble the approach of regular expressions or COBOL pictures but there is less flexibility. In the case of the year component you only ever see XXXX and never a partial pattern such as 19XX. + +A time can also be included, for example, 4pm: + +``` +XXXX-06-23T16 +``` + +This wildcard mechanism is only defined for the date part and not the time part. If you want to represent ambiguity in the time part then you will need multiple TIMEX expressions as we will see later. + +In terms of type, all the examples so far have been dates and date-times. (When we say "type" it is just something we have inferred from the underlying TIMEX expression - its does not add any additional semantics, it just might be a classificaton application logic could make use of. For example, if you know you have a date when you wanted a datetime then you know you are missing the time component.) It is possible to also just have the time component by itself, for example 4pm would be represented as: + +``` +T16 +``` + +The use of X to blank out the characters is also applies to the representation of weeks, for example, "Monday," blanks out both the year and the ISO week number: + +``` +XXXX-WXX-1 +``` + +Here XXXX means *any* year and WXX means *any* week, so what remains is the day component. And with the ISO week starting on a Monday and indexing from 1 we get Monday. + +The Text.Recognizers are written to attempt to resolve to a specific date if they can. This can result in some surprisingly subtle behavior. For exampe, if we had said "this Monday" it would have resolved to a specific date such as this: + +``` +2020-06-15 +``` + +Although we onlt had a small change in the text, we ended out with quite a significant change in the resulting TIMEX. + +Similarly for weeks, the Text.Recognizers will attempt to resolve when they see a word like "this" that grounds things. For example, the phrase "this week" might result to a TIMEX like this: + +``` +2020-W25 +``` + +In general care should be taken with logic based around weeks of the year as this can be a source of bugs in application code. How the ISO standard defines this is well documented online. Its important to note the ISO week (and therefore the TIMEX week) starts on a Monday with days of the week being numbered from 1. + +Note TIMEX also applies the ISO 8601 syntax of week number to describe the week *within* a month. Representing "the first week of June" as follows: + +``` +XXXX-06-W01 +``` + +## Representing Duration + +TIMEX expressions can represent duration. There are both date durations and time durations. A date duration is indicated by a leading P and a time duration is indicated by a leading PT. Durations have units, formatted as a letter following the value, and for date durations these are D, W, M and Y for day, week, month and year respectively. For time durations these are S, M and H for seconds, minutes and hours. The value is not padded and may contain a decimal point. + +Here are some examples: + +1 week is: +``` +P1W +``` +16 years is: +``` +P16Y +``` +Decimal is supported, so the recognizers would take the string "three and a half months" and return the TIMEX: + +``` +P3.5M +``` + +30 second is: +``` +PT30S +``` +and 4 hours is: +``` +PT4H +``` + +Given the nature of the problem and the fact that decimal is supported, means there are many different ways to express the same duration, for example PT0.5H is the same as PT30M just as P1W is the same as P7D. The Text.Recognizers make no attempt to normalize such things, instead they just try to render the original natural language utterance as directly as possible. The Text.Recognizers also don't try to merge separate durations they find in the input. For example, the text "4 hours 30 minutes" will result in two results. + +## Representing Ranges + +### Date Ranges + +TIMEX expressions often represent ranges. For example the TIMEX expression: + +``` +1912 +``` + +is intended to represents all the possible dates in the year 1912. As such it is described as a daterange. The month of June in that year is represented as follows: + +``` +1912-06 +``` + +This is also a daterange and intended to represent all the dates of June in 1912. The year could be blanked out here too, as follows: + +``` +XXXX-06 +``` + +Where this means all the dates in June and that's any June in any year not one particular June. + +TIMEX breaks with the ISO 8601 pattern when it comes to representing seasons and uses a special two letter codes for Summer, Fall, Winter and Spring: SU, FA, WI and SP respectively. Again these are all date ranges. + +More complex data ranges are captured with a begin, end and duration structure. Each of these components in themselves is a TIMEX expression. For example, teh American President JFK was born on May 29th 1917 and died November 22nd 1963, his lifespan can can be captured with the following TIMEX: + +``` +(1917-05-29,1963-11-22,P16978D) +``` + +The start and end dates should be read as inclusive. + +Natural language contains many different ways to refer to date ranges, for example a Text Recognizer can take the natural language phrase "next two weeks" and assuming today as the start would produce the following TIMEX: + +``` +(2020-06-19,2020-07-03,P2W) +``` + +Expressing the duration in addition to the begin and end seems redundant but that is the way it is done. The duration unit used is somewhat arbitrary, in this last example, P14D would have been equivalent. + +### Time Ranges + +Time ranges are very similar, for example given the text "9am to 5pm" the Text.Recognizers would produce the following: + +``` +(T09,T17,PT8H) +``` + +There are a number of well known time range constants in TIMEX. These represent the concepts of morning, afternoon, evening, daytime and nighttime, encoded as two characters MO, AF, EV, DT and NI respectively. Although these are time ranges they don't bother with the (start, end, duration) syntax, they simply start with a T followed by the two character code. For example, morning is respresents like this: + +``` +TMO +``` + +### Date Time Range + +Date and time can be combined in the same range and the Text.Recognizers would recognize the text "this friday 9am to next friday 5pm" as the TIMEX: + +``` +(2020-06-19T09,2020-06-26T17,PT176H) +``` + +When the time component of a date time range can be represented with the shortened 2 characters the resulting expression is simplified appropriately. For example "this afternoon" is a date time range that would resemble this: + +``` +2020-06-19TAF +``` + +If there is ambiguity in the date portion that will follow the blanking out approach described earlier. For example, "friday evening" because it doesn't say which Friday is ambiguous and evening is a time range, so we end up with a date time range TIMEX that looks like this: + +``` +XXXX-WXX-5TEV +``` + +## Special concepts + +TIMEX includes a special representation "now" meaning the present moment. It looks like this: + +``` +PRESENT_REF +``` + +## Limitations + +TIMEX as it is currently defined and implemented has some inherent limitations. Perhaps the most obvious is that although TIMEX manages to capture ambiguity in the date component it can't in the time component. + +Consider the text "Wednesday 4 O'clock," we are not saying which particular Wednesday, it could be *any* Wednesday. As we saw in the earlier examples TIMEX deals with this by blanking out the parts of a date that could vary, specifically for Wednesday we have: + +``` +XXXX-WXX-3 +``` + +Meaning the 3 day of any week of any year. + +However, the language used for the time component is also ambiguous. When we see "4 O'clock" it could mean either 4am or 4pm. + +The solution in TIMEX is to provide multiple TIMEX expressions. In fact if you hand this string to the Text.Recognizers it will return two distinct TIMEX expressions in its results: + +``` +XXXX-WXX-3T04 +XXXX-WXX-3T16 +``` + +It is instructive to compare that with the result if teh language had not beed ambiguous. Trying the Text.Recognizer with the text "next Wednesday 4pm" and we will see a result resembling this: + +``` +2020-06-24T16 +``` + +Note the Text.Recognizers generally look for "last", "this" and "next" and include that in the scope when they can. + +This leads us to another conceptual limitation of the current TIMEX implementation and that is the concept of *relative time* is not captured. Specifically, looking at the last example, we said *next* Wednesday and this was recognized *and resolved* to a specific date. This is often what we want, however, sometimes we actually wanted to recognize the concept of *next* in and of itself rather than it being resolved. For example in a booking application we might want to travel out on a particular date and return on the "next Friday." We would want to calculate exactly which Friday the input refered to relative to the particular departure date and almost definitely not the not the current booking date! (Perhaps it would be more correct to have said "following Friday" but applying such strictness to our human users is a challenge. And anyhow, ultimately natural language is always understood by common usage in particular context rather than strict logical structures.) + +## Resolution + +A TIMEX expression such as: + +``` +XXXX-WXX-3T16 +``` + +Means Wednesday 4PM, however, something like a travel booking scenario would generally require something less ambiguous, that is to say, we need to know exactly which Wednesday. That is, we need to *resolve* the TIMEX expression to a specific date time. + +This can be achieved by constraining the orignal TIMEX expression with a date range, naturally expressed in TIMEX. So for example, applying the TIMEX date range: + +``` +2020-W27 +``` + +Meaning the 27th week of the year. + +Will result in the specific or definite date time: + +``` +2020-07-01T16 +``` + +This idea generalizes to dealing with collections. Both the original TIMEX could have been a set of TIMEX expressions and the constraint could have been a set of TIMEX ranges. + +As we could now have various differing time parts it makes sense to also have time ranges amongst the constraints. + +All the TIMEX expressions in the original data should be read as *or* and the TIMEX expressions in the constrains should be read as *and*. + +For example give the original set of TIMEX expressions: + +``` +XXXX-WXX-3T04 +XXXX-WXX-3T16 +``` + +Meaning Wednesday at 4AM *or* Wednesday ay 4PM. + +And applying the constraints: + +``` +2020-W27 +TAF +``` + +Meaning the 27th week of the year *and* in the afternoon. + +And we get to the specific date: + +``` +2020-07-01T16 +``` + +Another aspect to resolution is whether the original TIMEX expression is missing some part. For example, we might have just been given a date part to resolve. In this case the resolution is the process of adding the time part. For example, the original TIMEX expression: + +``` +2020-07-01 +``` + +Can be resolved with the constraint of T14 to get to the specific date time of: + +``` +2020-07-01T14 +``` + +## TIMEX resolution using the TimexExpressions library + +The approach to dealing with TIMEX expressions outlines in above is implemented in the [TimexExpressions](https://github.com/microsoft/Recognizers-Text/tree/master/Java/libraries/recognizers-text-datatypes-timex-expression) library current available for .NET, Java and JavaScript. And examples of its usage are included in this sample. + +This library includes support for parsing TIMEX expressions to extract their component parts. As described above, the datatype can be inferred from the underlying TIMEX expression. This notion of datatype has more in common with tagging. That is, a particular TIMEX instance can often be multiple types. For example, a datetime is also a date and also a time. This allows application code (and the resolution logic itself) to switch appropriately gives the content of the underlying TIMEX. + +It also includes support for generating natural language from the underlying TIMEX. Its behavior is to act as the reverse of the Text Recognizer. + +This library can also be used to generate locally the examples that LUIS provides in its results. In outline, this is basically forward and backward in time. So "Wednesday" would result in two examples, the date of last Wednesday and the date of this Wednesday. This way of resolution works perfectly well for many simple scenarios. However, its not as flexible nor as complete as the application of ranges described above. + +So in summary the library can: + +- Parse TIMEX expressions to give you the properties contained there in. +- Generate TIMEX expressions based on setting raw properties. +- Generate natural language from the TIMEX expression. (This is logically the reverse of the Recognizer.) +- Resolve TIMEX expressions to produce example date-times. (This produces the same result as the Recognizer (and therefore LUIS)). +- Evaluate TIMEX expressions against constraints such that new more precise TIMEX expressions are produced. +- It make take several steps, but ultimately you can resolve to a datetime instance, which is probably what your application is looking for. + +The code of sample 40 includes examples of all these different features. + +### Where is the source code? + +The TIMEX expression library is contained in the same GitHub repo as the recognizers. Refer to the further reading section below. + +## Further reading + +- [Bot Framework Documentation](https://docs.botframework.com) +- [Bot Basics](https://docs.microsoft.com/azure/bot-service/bot-builder-basics?view=azure-bot-service-4.0) +- [TIMEX](https://en.wikipedia.org/wiki/TimeML#TIMEX3) +- [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) +- [Recognizers Text](https://github.com/Microsoft/recognizers-text) +- [Activity processing](https://docs.microsoft.com/en-us/azure/bot-service/bot-builder-concept-activity-processing?view=azure-bot-service-4.0) +- [Azure Bot Service Introduction](https://docs.microsoft.com/azure/bot-service/bot-service-overview-introduction?view=azure-bot-service-4.0) +- [Azure Bot Service Documentation](https://docs.microsoft.com/azure/bot-service/?view=azure-bot-service-4.0) +- [Azure CLI](https://docs.microsoft.com/cli/azure/?view=azure-cli-latest) +- [Azure Portal](https://portal.azure.com) +- [Channels and Bot Connector Service](https://docs.microsoft.com/en-us/azure/bot-service/bot-concepts?view=azure-bot-service-4.0) From f61710b6eca1f23faf8e1e000047db65e4aa1c39 Mon Sep 17 00:00:00 2001 From: Martin Battaglino Date: Fri, 9 Apr 2021 15:10:37 -0300 Subject: [PATCH 6/7] Change HashMap to LinkedHashMap in Recognizers-Text Datetime due to an issue --- .../text/datetime/parsers/BaseMergedDateTimeParser.java | 2 +- .../recognizers/text/datetime/utilities/TimexUtility.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/parsers/BaseMergedDateTimeParser.java b/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/parsers/BaseMergedDateTimeParser.java index 7039f98b1..434d5372b 100644 --- a/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/parsers/BaseMergedDateTimeParser.java +++ b/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/parsers/BaseMergedDateTimeParser.java @@ -438,7 +438,7 @@ public SortedMap dateTimeResolution(DateTimeParseResult slot) { } List> resolutions = new ArrayList<>(); - Map res = new HashMap<>(); + LinkedHashMap res = new LinkedHashMap<>(); DateTimeResolutionResult val = (DateTimeResolutionResult)slot.getValue(); if (val == null) { diff --git a/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/utilities/TimexUtility.java b/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/utilities/TimexUtility.java index 7c6e79aa5..ce68c0bb3 100644 --- a/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/utilities/TimexUtility.java +++ b/libraries/bot-dialogs/src/main/java/com/microsoft/recognizers/text/datetime/utilities/TimexUtility.java @@ -13,6 +13,7 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -281,7 +282,7 @@ public static String mergeTimexAlternatives(String timex1, String timex2) { return timex1 + Constants.CompositeTimexDelimiter + timex2; } - public static Map processDoubleTimex(Map resolutionDic, String futureKey, String pastKey, String originTimex) { + public static LinkedHashMap processDoubleTimex(LinkedHashMap resolutionDic, String futureKey, String pastKey, String originTimex) { String[] timexes = originTimex.split(Constants.CompositeTimexSplit); if (!resolutionDic.containsKey(futureKey) || !resolutionDic.containsKey(pastKey) || timexes.length != 2) { From 82933df379abe2b3dfb56864775a963a4535762a Mon Sep 17 00:00:00 2001 From: Martin Battaglino Date: Fri, 9 Apr 2021 15:10:50 -0300 Subject: [PATCH 7/7] Add sample as module in pom.xml of samples folder --- samples/pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/pom.xml b/samples/pom.xml index 411e6aa0a..c8f23ac82 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -462,6 +462,7 @@ 23.facebook-events 24.bot-authentication-msgraph 25.message-reaction + 40.timex-resolution 43.complex-dialog 44.prompt-users-for-input 45.state-management