You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nlpcraft.apache.org by ar...@apache.org on 2020/08/13 22:44:01 UTC

[incubator-nlpcraft] branch NLPCRAFT-41 updated: Refactored weather example.

This is an automated email from the ASF dual-hosted git repository.

aradzinski pushed a commit to branch NLPCRAFT-41
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git


The following commit(s) were added to refs/heads/NLPCRAFT-41 by this push:
     new 292f1af  Refactored weather example.
292f1af is described below

commit 292f1afafb998c117baae9a73e52359c8a910539
Author: Aaron Radzinski <ar...@datalingvo.com>
AuthorDate: Thu Aug 13 15:43:45 2020 -0700

    Refactored weather example.
---
 .../examples/misc/darksky/DarkSkyService.java      |   2 +-
 .../nlpcraft/examples/weather/WeatherModel.java    | 190 ++++++---------------
 .../nlpcraft/examples/weather/weather_model.json   | 113 ++++--------
 3 files changed, 93 insertions(+), 212 deletions(-)

diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/misc/darksky/DarkSkyService.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/misc/darksky/DarkSkyService.java
index c58bdb9..10995a2 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/misc/darksky/DarkSkyService.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/misc/darksky/DarkSkyService.java
@@ -175,7 +175,7 @@ public class DarkSkyService {
         log.debug("DarkSky time machine API call [lat={}, lon={}, from={}, to={}]", lat, lon, from, to);
 
         if (Duration.between(from, to).get(SECONDS) > maxDaysSecs)
-            throw new DarkSkyException(String.format("Too long request period [from=%s, to=%s]", from, to));
+            throw new DarkSkyException(String.format("Request period is too long [from=%s, to=%s]", from, to));
 
         long durMs = to.toEpochMilli() - from.toEpochMilli();
 
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/WeatherModel.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/WeatherModel.java
index 7bc6d3e..4534e6b 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/WeatherModel.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/WeatherModel.java
@@ -44,30 +44,21 @@ import static java.time.temporal.ChronoUnit.DAYS;
 public class WeatherModel extends NCModelFileAdapter {
     // Please register your own account at https://darksky.net/dev/docs/libraries and
     // replace this demo token with your own.
-    private final DarkSkyService srv = new DarkSkyService("097e1aad75b22b88f494cf49211975aa", 31);
+    private final DarkSkyService darkSky = new DarkSkyService("097e1aad75b22b88f494cf49211975aa", 31);
 
     // Geo manager.
     private final GeoManager geoMrg = new GeoManager();
-    
+
+    // Default shift in days for history and forecast.
+    private static final int DAYS_SHIFT = 5;
+
+    // GSON instance.
     private static final Gson GSON = new Gson();
-    
+
     // Keywords for 'local' weather.
     private static final Set<String> LOCAL_WORDS = new HashSet<>(Arrays.asList("my", "local", "hometown"));
 
     /**
-     * Date range holder.
-     */
-    private static class DateRange {
-        private final Instant from;
-        private final Instant to;
-
-        DateRange(Instant from, Instant to) {
-            this.from = from;
-            this.to = to;
-        }
-    }
-
-    /**
      * Coordinates holder.
      */
     private static class Coordinate {
@@ -81,46 +72,23 @@ public class WeatherModel extends NCModelFileAdapter {
     }
 
     /**
-     * Makes JSON result.
-     *
-     * @param res Weather holder.
-     * @return Query result.
-     */
-    private NCResult makeResult(Object res) {
-        return NCResult.json(GSON.toJson(res));
-    }
-
-    /**
-     * Extracts date range from given solver context.
-     *
-     * @param tok date token.
-     * @return Pair of dates.
-     */
-    private DateRange extractDate(NCToken tok) {
-        return new DateRange(
-            Instant.ofEpochMilli(tok.meta("nlpcraft:date:from")),
-            Instant.ofEpochMilli(tok.meta("nlpcraft:date:to"))
-        );
-    }
-
-    /**
      * Extracts geo location (city) from given solver context that is suitable for Dark Sky API weather service.
      *
      * @param ctx Intent solver context.
-     * @param dateTokOpt Optional date token.
+     * @param geoTokOpt Optional geo token.
      * @return Geo location.
      */
-    private Coordinate prepGeo(NCIntentMatch ctx, Optional<NCToken> dateTokOpt) throws NCRejection {
-        if (dateTokOpt.isPresent()) {
-            NCToken tok = dateTokOpt.get();
+    private Coordinate prepGeo(NCIntentMatch ctx, Optional<NCToken> geoTokOpt) throws NCRejection {
+        if (geoTokOpt.isPresent()) {
+            NCToken geoTok = geoTokOpt.get();
 
-            Map<String, Object> cityMeta = tok.meta("nlpcraft:city:citymeta");
+            Map<String, Object> cityMeta = geoTok.meta("nlpcraft:city:citymeta");
 
             Double lat = (Double)cityMeta.get("latitude");
             Double lon = (Double)cityMeta.get("longitude");
 
             if (lat == null || lon == null) {
-                String city = tok.meta("nlpcraft:city:city");
+                String city = geoTok.meta("nlpcraft:city:city");
 
                 throw new NCRejection(String.format("Latitude and longitude not found for: %s", city));
             }
@@ -172,108 +140,62 @@ public class WeatherModel extends NCModelFileAdapter {
     /**
      *
      * @param ctx
-     * @param shift
      * @return
      */
-    private NCResult onPeriodMatch(
-        NCIntentMatch ctx,
-        Optional<NCToken> cityTokOpt,
-        Optional<NCToken> dateTokOpt,
-        int shift
-    ) {
-        assert shift != 0;
-
-        checkMatch(ctx);
-
-        try {
-            Coordinate cr = prepGeo(ctx, cityTokOpt);
-
-            Instant now = Instant.now();
-
-            DateRange range = dateTokOpt.map(this::extractDate).orElseGet(
-                () -> shift > 0 ?
-                    new DateRange(now, now.plus(shift, DAYS)) :
-                    new DateRange(now.plus(shift, DAYS), now)
-            );
-
-            return makeResult(srv.getTimeMachine(cr.latitude, cr.longitude, range.from, range.to));
-        }
-        catch (DarkSkyException e) {
-            throw new NCRejection(e.getLocalizedMessage());
-        }
-        catch (NCRejection e) {
-            throw e;
-        }
-        catch (Exception e) {
-            throw new NCRejection("Weather provider error.", e);
-        }
-    }
-
-    /**
-     * Callback on forecast intent match.
-     *
-     * @param ctx Intent solver context.
-     * @return Query result.
-     */
-    @NCIntent("intent=fcast conv=true term={id == 'wt:fcast'} term(city)={id == 'nlpcraft:city'}? term(date)={id == 'nlpcraft:date'}?")
-    @NCIntentSample({
-        "What's the weather forecast in Moscow?",
-        "Will it be hot next Sunday?",
-        "How about a rain next week in London"
-    })
-    public NCResult onForecastMatch(
-        NCIntentMatch ctx,
-        @NCIntentTerm("city") Optional<NCToken> cityTokOpt,
-        @NCIntentTerm("date") Optional<NCToken> dateTokOpt
-    ) {
-        return onPeriodMatch(ctx, cityTokOpt, dateTokOpt, 5);
-    }
-
-    /**
-     * Callback on history intent match.
-     *
-     * @param ctx Intent solver context.
-     * @return Query result.
-     */
-    @NCIntent("intent=hist conv=true term={id == 'wt:hist'} term(city)={id == 'nlpcraft:city'}? term(date)={id == 'nlpcraft:date'}?")
-    @NCIntentSample({
-        "What the weather history in Moscow last week?"
-    })
-    public NCResult onHistoryMatch(
-        NCIntentMatch ctx,
-        @NCIntentTerm("city") Optional<NCToken> cityTokOpt,
-        @NCIntentTerm("date") Optional<NCToken> dateTokOpt
-    ) {
-        return onPeriodMatch(ctx, cityTokOpt, dateTokOpt, -5);
-    }
-
-    /**
-     * Callback on current date intent match.
-     *
-     * @param ctx Intent solver context.
-     * @return Query result.
-     */
-    @NCIntent("intent=curr conv=true term={id == 'wt:curr'} term(city)={id == 'nlpcraft:city'}? term(date)={id == 'nlpcraft:date'}?")
+    @NCIntent(
+        "intent=req " +
+        "conv=true " + // Support conversation context (i.e. short term memory).
+        "term={id == 'wt:phen'}+ " + // One or more weather phenomenon (at least is mandatory).
+        "term(ind)={groups @@ 'indicator'}* " + // Optional indicator words (zero or more).
+        "term(city)={id == 'nlpcraft:city'}? " + // Optional city.
+        "term(date)={id == 'nlpcraft:date'}?" // Optional date (overrides indicator words).
+    )
     @NCIntentSample({
-        "What's the current weather in Moscow"
+        "What's the local weather forecast?",
+        "What's the weather in Moscow?",
+        "What is the weather like outside?",
+        "How's the weather?",
+        "What's the weather forecast for the rest of the week?",
+        "What's the weather forecast this week?",
+        "What's the weather out there?",
+        "Is it cold outside?",
+        "Is it hot outside?",
+        "Will it rain today?",
+        "When it will rain in Delhi?",
+        "Is there any possibility of rain in Delhi?",
+        "Is it raining now?",
+        "Is there any chance of rain today?"
     })
-    public NCResult onCurrentMatch(
+    public NCResult onMatch(
         NCIntentMatch ctx,
+        @NCIntentTerm("ind") List<NCToken> indToksOpt,
         @NCIntentTerm("city") Optional<NCToken> cityTokOpt,
         @NCIntentTerm("date") Optional<NCToken> dateTokOpt
     ) {
         checkMatch(ctx);
 
         try {
-            Coordinate cr = prepGeo(ctx, cityTokOpt);
+            Instant now = Instant.now();
+
+            Instant from = now;
+            Instant to = now;
 
-            if (dateTokOpt.isPresent()) {
-                DateRange range = extractDate(dateTokOpt.get());
+            if (indToksOpt.stream().anyMatch(tok -> tok.getId().equals("wt:hist")))
+                from = from.minus(DAYS_SHIFT, DAYS);
+            else if (indToksOpt.stream().anyMatch(tok -> tok.getId().equals("wt:fcast")))
+                to = from.plus(DAYS_SHIFT, DAYS);
 
-                return makeResult(srv.getTimeMachine(cr.latitude, cr.longitude, range.from, range.to));
+            if (dateTokOpt.isPresent()) { // Date token overrides any indicators.
+                NCToken dateTok = dateTokOpt.get();
+
+                from = Instant.ofEpochMilli(dateTok.meta("nlpcraft:date:from"));
+                to = Instant.ofEpochMilli(dateTok.meta("nlpcraft:date:to"));
             }
 
-            return makeResult(srv.getCurrent(cr.latitude, cr.longitude));
+            Coordinate latLon = prepGeo(ctx, cityTokOpt); // Handles optional city too.
+
+            return NCResult.json(GSON.toJson(from == to ? darkSky.getCurrent(latLon.latitude, latLon.longitude) :
+                darkSky.getTimeMachine(latLon.latitude, latLon.longitude, from, to)));
         }
         catch (DarkSkyException e) {
             throw new NCRejection(e.getLocalizedMessage());
@@ -287,7 +209,7 @@ public class WeatherModel extends NCModelFileAdapter {
     }
 
     /**
-     * Initializes the model.
+     * Loads the model.
      */
     public WeatherModel() {
         // Load model from external JSON file on classpath.
@@ -296,6 +218,6 @@ public class WeatherModel extends NCModelFileAdapter {
 
     @Override
     public void onDiscard() {
-        srv.stop();
+        darkSky.stop();
     }
 }
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/weather_model.json b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/weather_model.json
index 14d43ab..b5d6577 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/weather_model.json
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/weather/weather_model.json
@@ -16,81 +16,40 @@
  */
 
 {
-    "id": "nlpcraft.weather.ex",
-    "name": "Weather Example Model",
-    "version": "1.0",
-    "description": "Weather example model.",
-    "examples": [
-        "What's the local weather forecast?",
-        "What's the weather in Moscow?",
-        "What is the weather like outside?",
-        "How's the weather?",
-        "What's the weather forecast for the rest of the week?",
-        "What's the weather forecast this week?",
-        "What's the weather out there?",
-        "Is it cold outside?",
-        "Is it hot outside?",
-        "Will it rain today?",
-        "When it will rain in Delhi?",
-        "Is there any possibility of rain in Delhi?",
-        "Is it raining now?",
-        "Is there any chance of rain today?"
-    ],
-    "macros": [
-        {
-            "name": "<OF>",
-            "macro": "{of|for|per}"
-        },
-        {
-            "name": "<CHANCE>",
-            "macro": "{chance|possibility|probability|odds|likelihood|potential|risk|opportunity}"
-        },
-        {
-            "name": "<PHENOMENON>",
-            "macro": "{high sea|severe weather|hail|heat wave|cold wave|derecho|supercell|avalanche|cyclone|wildfire|landslide|firestorm|dust storm|thunder snow|winter storm|cloudburst|shower|condensation|precipitation|drizzle|rainstorm|rain storm|rainfall|rain|storm|sun|sunshine|cloud|hot|cold|dry|wet|wind||hurricane|typhoon|sand-storm|sand storm|tornado|humid|fog|snow|smog|black ice|haze|thundershower|thundersnow|sleet|drought|wildfire|blizzard|avalanche|mist|thunderstorm}"
-        },
-        {
-            "name": "<CUR>",
-            "macro": "{current|present|moment|now}"
-        },
-        {
-            "name": "<WEATHER>",
-            "macro": "{weather {condition|temp|temperature|data|*}|condition|temp|temperature}"
-        },
-        {
-            "name": "<FORECAST>",
-            "macro": "{forecast|prognosis|prediction}"
-        },
-        {
-            "name": "<HISTORY>",
-            "macro": "{history|past}"
-        }
-    ],
-    "elements": [
-        {
-            "id": "wt:hist",
-            "description": "Past weather conditions.",
-            "synonyms": [
-                "{<WEATHER>|*} <HISTORY>",
-                "<HISTORY> {<OF>|*} {<WEATHER>|<PHENOMENON>}"
-            ]
-        },
-        {
-            "id": "wt:curr",
-            "description": "Current weather conditions.",
-            "synonyms": [
-                "{<CUR>|*} {<WEATHER>|<PHENOMENON>}",
-                "<CHANCE> <OF> <PHENOMENON>",
-                "<PHENOMENON> {<CHANCE>|*}"
-            ]
-        },
-        {
-            "id": "wt:fcast",
-            "description": "Future weather forecast.",
-            "synonyms": [
-                "{<PHENOMENON>|<WEATHER>|*} <FORECAST>",
-                "<FORECAST> {<OF>|*} {<WEATHER>|<PHENOMENON>}"
-            ]
-        }
-    ]
+  "id": "nlpcraft.weather.ex",
+  "name": "Weather Example Model",
+  "version": "1.0",
+  "description": "Weather example model.",
+  "macros": [
+  ],
+  "elements": [
+    {
+      "id": "wt:phen",
+      "description": "Weather phenomenon.",
+      "synonyms": [
+        "{high sea|severe weather|hail|heat wave|cold wave|derecho|supercell|avalanche|cyclone|wildfire|landslide|firestorm|dust storm|thunder snow|winter storm|cloudburst|shower|condensation|precipitation|drizzle|rainstorm|rain storm|rainfall|rain|storm|sun|sunshine|cloud|hot|cold|dry|wet|wind||hurricane|typhoon|sand-storm|sand storm|tornado|humid|fog|snow|smog|black ice|haze|thundershower|thundersnow|sleet|drought|wildfire|blizzard|avalanche|mist|thunderstorm}",
+        "{weather {condition|temp|temperature|data|*}|condition|temp|temperature}"
+      ]
+    },
+    {
+      "id": "wt:hist",
+      "description": "History (past) indicator.",
+      "groups": [
+        "indicator"
+      ],
+      "synonyms": [
+        "{history|past|previous}"
+      ]
+    },
+    {
+      "id": "wt:fcast",
+      "description": "Forecast (future) indicator.",
+      "groups": [
+        "indicator"
+      ],
+      "synonyms": [
+        "{future|forecast|prognosis|prediction}"
+      ]
+    }
+  ]
 }
\ No newline at end of file