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/06/01 23:35:30 UTC
[incubator-nlpcraft-website] branch master updated: Documentation &
code cleanup on weather example.
This is an automated email from the ASF dual-hosted git repository.
aradzinski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft-website.git
The following commit(s) were added to refs/heads/master by this push:
new 51b9c8a Documentation & code cleanup on weather example.
51b9c8a is described below
commit 51b9c8af86b96973a4f00a8e8fe439259e5f9ae2
Author: Aaron Radzinzski <ar...@datalingvo.com>
AuthorDate: Mon Jun 1 16:32:56 2020 -0700
Documentation & code cleanup on weather example.
---
_layouts/documentation.html | 7 +
examples/alarm_clock.html | 21 +-
examples/light_switch.html | 22 ++-
examples/weather_bot.html | 468 +++++++++++++++++++++++++++++++++++++++++++-
first-example.html | 2 +-
tools/embedded_probe.html | 2 +-
tools/test_framework.html | 2 +-
7 files changed, 506 insertions(+), 18 deletions(-)
diff --git a/_layouts/documentation.html b/_layouts/documentation.html
index 2a4d342..1d697b2 100644
--- a/_layouts/documentation.html
+++ b/_layouts/documentation.html
@@ -142,6 +142,13 @@ layout: interior
<a href="/examples/light_switch.html">Light Switch</a>
{% endif %}
</li>
+ <li>
+ {% if page.id == "weather_bot" %}
+ <a class="active" href="/examples/weather_bot.html">Weather Bot</a>
+ {% else %}
+ <a href="/examples/weather_bot.html">Weather Bot</a>
+ {% endif %}
+ </li>
</ul>
</div>
diff --git a/examples/alarm_clock.html b/examples/alarm_clock.html
index 4bfc704..ca9d50f 100644
--- a/examples/alarm_clock.html
+++ b/examples/alarm_clock.html
@@ -105,7 +105,8 @@ id: alarm_clock
<section id="model">
<h3 class="section-title">Data Model</h3>
<p>
- We are going to start with declaring our semantic model using JSON. Create new <code>alarm_model.json</code>
+ We are going to start with declaring the static part of our semantic model using JSON which we will later load using
+ <code>NCModelFileAdapter</code> in our Java-based model implementation. Create new <code>alarm_model.json</code>
file and add the following model declaration into it:
</p>
<pre class="brush: js, highlight: [7, 16, 25]">
@@ -275,7 +276,7 @@ public class AlarmModel extends NCModelFileAdapter {
</li>
</ul>
</section>
- <section>
+ <section id="start_probe">
<h3 class="section-title">Start Data Probe</h3>
<p>
NLPCraft data models get deployed into data probe. Let's start data probe with our newly
@@ -290,7 +291,7 @@ public class AlarmModel extends NCModelFileAdapter {
<b>VM arguments:</b> <code>-Dconfig.override_with_env_vars=true</code>
</li>
<li>
- <b>Environment variable:</b> <code>CONFIG_FORCE_nlpcraft_probe_models.0=path.to.AlarmModel</code>
+ <b>Environment variable:</b> <code>CONFIG_FORCE_nlpcraft_probe_models.0=org.apache.nlpcraft.examples.alarm.AlarmModel</code>
</li>
<li>
<b>Program arguments: </b> <code>-probe</code>
@@ -307,7 +308,7 @@ public class AlarmModel extends NCModelFileAdapter {
has been successfully loaded and probe started.
</p>
</section>
- <section>
+ <section id="start_server">
<h3 class="section-title">Start REST Server</h3>
<p>
REST server listens for requests from client applications and routes them to the requested data models
@@ -328,14 +329,14 @@ public class AlarmModel extends NCModelFileAdapter {
</p>
<p>
At this point we've developed our data model, deployed it into the data probe, and started the REST server.
- To test it, we'll use the built-in <a href="/testing-data-model.html">test framework</a>
+ To test it, we'll use the built-in <a href="/tools/test_framework.html">test framework</a>
that allows you to write convenient unit tests against your data model.
</p>
</section>
- <section>
+ <section id="testing">
<h3 class="section-title">Testing</h3>
<p>
- NLPCraft comes with easy to use <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/test/package-summary.html">test framework</a> for
+ NLPCraft comes with easy to use <a href="/tools/test_framework.html">test framework</a> for
data models that can be used with
any unit testing framework like JUnit or ScalaTest. It is essentially a simplified
version of Java REST client that is custom designed for data model testing.
@@ -413,6 +414,12 @@ class AlarmTest {
<ul class="side-nav">
<li class="side-nav-title">On This Page</li>
<li><a href="#overview">Overview</a></li>
+ <li><a href="#new_project">New Project</a></li>
+ <li><a href="#add_nlpcraft">Add NLPCraft</a></li>
+ <li><a href="#model">Data Model</a></li>
+ <li><a href="#code">Model Class</a></li>
+ <li><a href="#start_probe">Start Probe</a></li>
+ <li><a href="#start_server">Start Server</a></li>
{% include quick-links.html %}
</ul>
</div>
diff --git a/examples/light_switch.html b/examples/light_switch.html
index fc720db..6a9161c 100644
--- a/examples/light_switch.html
+++ b/examples/light_switch.html
@@ -105,7 +105,8 @@ id: light_switch
<section id="model">
<h3 class="section-title">Data Model</h3>
<p>
- We are going to start with declaring our semantic model using YAML. Create new <code>lightswitch_model.yaml</code>
+ We are going to start with declaring the static part of our semantic model using YAML which we will later load using
+ <code>NCModelFileAdapter</code> in our Sccla-based model implementation. Create new <code>lightswitch_model.yaml</code>
file and add the following model declaration into it:
</p>
<pre class="brush: js, highlight: [10, 19, 26, 34, 42]">
@@ -229,7 +230,7 @@ class LightSwitchModel extends NCModelFileAdapter("org/apache/nlpcraft/examples/
</li>
</ul>
</section>
- <section>
+ <section id="start_probe">
<h3 class="section-title">Start Data Probe</h3>
<p>
NLPCraft data models get deployed into data probe. Let's start data probe with our newly
@@ -244,7 +245,7 @@ class LightSwitchModel extends NCModelFileAdapter("org/apache/nlpcraft/examples/
<b>VM arguments:</b> <code>-Dconfig.override_with_env_vars=true</code>
</li>
<li>
- <b>Environment variable:</b> <code>CONFIG_FORCE_nlpcraft_probe_models.0=path.to.LightSwitchModel</code>
+ <b>Environment variable:</b> <code>CONFIG_FORCE_nlpcraft_probe_models.0=org.apache.nlpcraft.examples.lightswitch.LightSwitchModel</code>
</li>
<li>
<b>Program arguments: </b> <code>-probe</code>
@@ -262,7 +263,7 @@ class LightSwitchModel extends NCModelFileAdapter("org/apache/nlpcraft/examples/
has been successfully loaded and probe started.
</p>
</section>
- <section>
+ <section id="start_server">
<h3 class="section-title">Start REST Server</h3>
<p>
REST server listens for requests from client applications and routes them to the requested data models
@@ -283,14 +284,14 @@ class LightSwitchModel extends NCModelFileAdapter("org/apache/nlpcraft/examples/
</p>
<p>
At this point we've developed our data model, deployed it into the data probe, and started the REST server.
- To test it, we'll use the built-in <a href="/testing-data-model.html">test framework</a>
+ To test it, we'll use the built-in <a href="/tools/test_framework.html">test framework</a>
that allows you to write convenient unit tests against your data model.
</p>
</section>
- <section>
+ <section id="testing">
<h3 class="section-title">Testing</h3>
<p>
- NLPCraft comes with easy to use <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/test/package-summary.html">test framework</a> for
+ NLPCraft comes with easy to use <a href="/tools/test_framework.html">test framework</a> for
data models that can be used with
any unit testing framework like JUnit or ScalaTest. It is essentially a simplified
version of Java REST client that is custom designed for data model testing.
@@ -383,6 +384,13 @@ class LightSwitchTest {
<ul class="side-nav">
<li class="side-nav-title">On This Page</li>
<li><a href="#overview">Overview</a></li>
+ <li><a href="#new_project">New Project</a></li>
+ <li><a href="#add_nlpcraft">Add NLPCraft</a></li>
+ <li><a href="#model">Data Model</a></li>
+ <li><a href="#code">Model Class</a></li>
+ <li><a href="#start_probe">Start Probe</a></li>
+ <li><a href="#start_server">Start Server</a></li>
+ <li><a href="#testing">Testing</a></li>
{% include quick-links.html %}
</ul>
</div>
diff --git a/examples/weather_bot.html b/examples/weather_bot.html
index a5ae4f9..afb9e86 100644
--- a/examples/weather_bot.html
+++ b/examples/weather_bot.html
@@ -26,7 +26,7 @@ id: weather_bot
<h2 class="section-title">Overview</h2>
<p>
This example demonstrates relatively complete NLI-based weather service with JSON output and a non-trivial
- intent matching logic. It uses <a target="new" href="https://www.apixu.com">https://www.apixu.com</a>
+ intent matching logic. It uses Apple's <a target="new" href="https://darksky.net">DarkSky</a>
REST service for the actual weather information.
</p>
<p>
@@ -34,11 +34,477 @@ id: weather_bot
Source code: <a target="github" href="https://github.com/apache/incubator-nlpcraft/tree/master/src/main/scala/org/apache/nlpcraft/examples/weather">GitHub</a>
</p>
</section>
+ <section id="new_project">
+ <h3 class="section-title">Create New Project</h3>
+ <p>
+ You can create new Java project in many different ways - we'll use Maven archetype generation
+ for that. In your home folder run the following command:
+ </p>
+ <pre class="brush: text">
+ mvn archetype:generate -DgroupId=examples -DartifactId=my-app -DarchetypeVersion=1.4 -DinteractiveMode=false
+ </pre>
+ <p>
+ This will create <code>my-app</code> folder with the following default maven project structure:
+ </p>
+ <pre class="console">
+├── <b>pom.xml</b>
+└── src
+ ├── main
+ │ └── java
+ │ └── examples
+ │ └── App.java
+ └── test
+ └── java
+ └── examples
+ └── AppTest.java
+ </pre>
+ <div class="bq info">
+ <p>
+ Note that this setup is same for all examples. Note also that you can use any other tools for
+ creating and managing Java project with or without Maven.
+ </p>
+ </div>
+ <p>
+ For our example we'll use JetBrain's <a target=_new href="https://www.jetbrains.com/idea/">IntelliJ IDEA</a>.
+ Create new IDEA project from this source folder (make sure to pick JDK 8 or later JDK and language support).
+ Let's also delete auto-generated files <code>App.java</code> and <code>AppTest.java</code> from our
+ project as we won't be using them.
+ </p>
+ </section>
+ <section id="add_nlpcraft">
+ <h3 class="section-title">Add NLPCraft</h3>
+ <p>
+ Next we need to add NLPCraft dependency to our new project. Open <code>pom.xml</code> file and replace
+ <code>dependencies</code> section with the following code:
+ </p>
+ <pre class="brush: xml, highlight: [3, 4, 5]">
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.nlpcraft</groupId>
+ <artifactId>nlpcraft</artifactId>
+ <version>{{site.latest_version}}</version>
+ </dependency>
+ </dependencies>
+ </pre>
+ <p>
+ Also make sure that you have correct JDK version (1.8 or above) for the maven compiler plugin:
+ </p>
+ <pre class="brush: xml, highlight: [3, 4]">
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ </properties>
+ </pre>
+ <p>
+ IDEA should automatically reload the project with newly updated <code>pom.xml</code> file and
+ we should be ready now to develop our data model.
+ </p>
+ </section>
+ <section id="model">
+ <h3 class="section-title">Data Model</h3>
+ <p>
+ We are going to start with declaring the static part of our semantic model using JSON which we will later load using
+ <code>NCModelFileAdapter</code> in our Java-based model implementation. Create new <code>weather_model.json</code>
+ file and add the following model declaration into it:
+ </p>
+ <pre class="brush: js, highlight: [10, 42, 50, 59]">
+{
+ "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?"
+ ],
+ "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>}"
+ ]
+ }
+ ]
+}
+ </pre>
+ <p>There are number of important points here:</p>
+ <ul>
+ <li>
+ <code>Line 10</code> defines several macros that are used later on throughout the model's elements
+ to shorten the synonym declarations. Note how macros coupled with option groups
+ shorten overall synonym declarations 1000:1 vs. manually listing all possible word permutations.
+ </li>
+ <li>
+ <code>Lines 42, 50, 59</code> define three model elements: the past, present and future (forecast) weather
+ condition.
+ </li>
+ </ul>
+ <p>
+ Now that our model is ready let's create a Java class that would load this model and define intents
+ that use the model elements we have just defined.
+ </p>
+ </section>
+ <section id="code">
+ <h3 class="section-title">Model Class</h3>
+ <p>
+ Our Java implementation uses one auxiliary class <a target="github" href="https://github.com/apache/incubator-nlpcraft/blob/master/src/main/scala/org/apache/nlpcraft/examples/weather/WeatherResultWrapper.java">WeatherResultWrapper.java</a>
+ that is used for JSON result formatting. Note that the main <a target="github" href="https://github.com/apache/incubator-nlpcraft/blob/master/src/main/scala/org/apache/nlpcraft/examples/weather/WeatherModel.java">WeatherModel</a> class
+ have number of utility methods that we'll skip here (you can see the entire class by following the link above) and
+ we'll concentrate on the intents only:
+ </p>
+ <pre class="brush: java, highlight: [1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 19, 20, 21, 22, 23]">
+ @NCIntent("intent=fcast term={id == 'wt:fcast'} term(city)={id == 'nlpcraft:city'}? term(date)={id == 'nlpcraft:date'}?")
+ public NCResult onForecastMatch(
+ NCIntentMatch ctx,
+ @NCIntentTerm("city") Optional<NCToken> cityTokOpt,
+ @NCIntentTerm("date") Optional<NCToken> dateTokOpt
+ ) {
+ return onPeriodMatch(ctx, cityTokOpt, dateTokOpt, 5);
+ }
+
+ @NCIntent("intent=hist term={id == 'wt:hist'} term(city)={id == 'nlpcraft:city'}? term(date)={id == 'nlpcraft:date'}?")
+ public NCResult onHistoryMatch(
+ NCIntentMatch ctx,
+ @NCIntentTerm("city") Optional<NCToken> cityTokOpt,
+ @NCIntentTerm("date") Optional<NCToken> dateTokOpt
+ ) {
+ return onPeriodMatch(ctx, cityTokOpt, dateTokOpt, -5);
+ }
+
+ @NCIntent("intent=curr term={id == 'wt:curr'} term(city)={id == 'nlpcraft:city'}? term(date)={id == 'nlpcraft:date'}?")
+ public NCResult onCurrentMatch(
+ NCIntentMatch ctx,
+ @NCIntentTerm("city") Optional<NCToken> cityTokOpt,
+ @NCIntentTerm("date") Optional<NCToken> dateTokOpt
+ ) {
+ checkMatch(ctx);
+
+ try {
+ Coordinate cr = prepGeo(ctx, cityTokOpt);
+
+ if (dateTokOpt.isPresent()) {
+ DateRange range = extractDate(dateTokOpt.get());
+
+ return makeResult(srv.getTimeMachine(cr.latitude, cr.longitude, range.from, range.to), ctx.getIntentId());
+ }
+
+ return makeResult(srv.getCurrent(cr.latitude, cr.longitude), ctx.getIntentId());
+ }
+ catch (DarkSkyException e) {
+ throw new NCRejection(e.getLocalizedMessage());
+ }
+ catch (NCRejection e) {
+ throw e;
+ }
+ catch (Exception e) {
+ throw new NCRejection("Weather provider error.", e);
+ }
+ }
+ </pre>
+ <p>
+ There three methods define three intents. Each intent is defined "in place", i.e. as an annotation on the
+ method that acts as a callback for that intent:
+ </p>
+ <ul>
+ <li>
+ Line 1 defines intent and the callback for the weather forecast (weather in the future):
+ <ul>
+ <li>Intent is ordered (default), supports conversation (default) and has ID <code>fcast</code></li>
+ <li>Intent has one mandatory term and two optional terms:
+ <ul>
+ <li>
+ Mandatory term is defined as a token with ID <code>wt:fcast</code> as defined
+ in the model.
+ </li>
+ <li>
+ Two optional terms (their IDs are <code>city</code> and <code>date</code>) define
+ optional city and date for the weather report. If not provided, their will be taken
+ from either conversation context or assume the default value (current geo location
+ and current time, if available).
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li>
+ Lines 3-5 define formal parameters for the <code>fcast</code> intent callback method. Note that we use term IDs
+ (<code>city</code> and <code>date</code>) in <code>@NCIntentTerm</code> annotations to automatically
+ assign tokens from the detected terms to their corresponding method formal parameters.
+ </li>
+ <li>
+ Lines 10-14 and lines 19-23 define two other intents and their callbacks methods in the same manner.
+ </li>
+ <li>
+ Implementation of all intent callback method is pretty straightforward and deals mostly with figuring
+ out the default location and time if either one isn't provided.
+ </li>
+ </ul>
+ </section>
+ <section id="tools">
+ <h3 class="section-title">External Tools</h3>
+ <p>
+ This example uses several external tools to implement its functionality:
+ </p>
+ <ul>
+ <li>
+ <a target=_ href="https://darksky.net">Apple DarkSky</a> - to provide actual weather data service
+ See <code>org.apache.nlpcraft.examples.misc.darksky</code> package for details.
+ </li>
+ <li>
+ <a target="_" href="https://tools.keycdn.com/geo">KeyCDN's IP Location Finder</a> - to provide IP location
+ service. See <code>org.apache.nlpcraft.examples.misc.geo.keycdn</code> package for details.
+ </li>
+ <li>
+ City to timezone mapper. See <code>org.apache.nlpcraft.examples.misc.geo.cities</code> package for details.
+ </li>
+ </ul>
+ </section>
+ <section id="start_probe">
+ <h3 class="section-title">Start Data Probe</h3>
+ <p>
+ NLPCraft data models get deployed into data probe. Let's start data probe with our newly
+ created data model. To start data probe we need to configure Run Configuration in IDEA with
+ the following parameters:
+ </p>
+ <ul>
+ <li>
+ <b>Main class:</b> <code>org.apache.nlpcraft.NCStart</code>
+ </li>
+ <li>
+ <b>VM arguments:</b> <code>-Dconfig.override_with_env_vars=true</code>
+ </li>
+ <li>
+ <b>Environment variable:</b> <code>CONFIG_FORCE_nlpcraft_probe_models.0=org.apache.nlpcraft.examples.weather.WeatherModel</code>
+ </li>
+ <li>
+ <b>Program arguments: </b> <code>-probe</code>
+ </li>
+ </ul>
+ <div class="bq info">
+ <p>
+ <b>NOTE:</b> instead of supplying a <a href="/server-and-probe.html">full configuration file</a> we just
+ use the default configuration and override one configuration property using
+ configuration override via environment variables.
+ </p>
+ </div>
+ <p>
+ Start this run configuration and make sure you have positive console output indicating that our model
+ has been successfully loaded and probe started.
+ </p>
+ </section>
+ <section id="start_server">
+ <h3 class="section-title">Start REST Server</h3>
+ <p>
+ REST server listens for requests from client applications and routes them to the requested data models
+ via connected data probes. REST server starts the same way as the data probe. Configure new
+ Run Configuration in IDEA with the following parameters:
+ </p>
+ <ul>
+ <li>
+ <b>Main class:</b> <code>org.apache.nlpcraft.NCStart</code>
+ </li>
+ <li>
+ <b>Program arguments: </b> <code>-server</code>
+ </li>
+ </ul>
+ <p>
+ Once started ensure that your REST server console output shows that data probe is connected and the
+ REST server is listening on the default <code>localhost:8081</code> endpoint.
+ </p>
+ <p>
+ At this point we've developed our data model, deployed it into the data probe, and started the REST server.
+ To test it, we'll use the built-in <a href="/tools/test_framework.html">test framework</a>
+ that allows you to write convenient unit tests against your data model.
+ </p>
+ </section>
+ <section id="testing">
+ <h3 class="section-title">Testing</h3>
+ <p>
+ NLPCraft comes with easy to use <a href="/tools/test_framework.html">test framework</a> for
+ data models that can be used with
+ any unit testing framework like JUnit or ScalaTest. It is essentially a simplified
+ version of Java REST client that is custom designed for data model testing.
+ </p>
+ <p>
+ We would like to test with following user requests:
+ </p>
+ <ul>
+ <li><code>"What's the local weather forecast?"</code></li>
+ <li><code>"What's the weather in Moscow?"</code></li>
+ <li><code>"Chance of snow?"</code> (using conversation context)</li>
+ <li><code>"Moscow?"</code> (using conversation context).</li>
+ </ul>
+ <p>
+ Let's create new Java class <code>WeatherTest.java</code> with the following code:
+ </p>
+ <pre class="brush: java, highlight: [15, 24]">
+package org.apache.nlpcraft.examples.weather;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import org.apache.nlpcraft.common.NCException;
+import org.apache.nlpcraft.model.tools.test.NCTestClient;
+import org.apache.nlpcraft.model.tools.test.NCTestClientBuilder;
+import org.apache.nlpcraft.model.tools.test.NCTestResult;
+import org.apache.nlpcraft.probe.embedded.NCEmbeddedProbe;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class WeatherTest {
+ private static final Gson GSON = new Gson();
+ private static final Type TYPE_MAP_RESP = new TypeToken<HashMap<String, Object>>() {}.getType();
+ private NCTestClient cli;
+
+ private void checkIntent(String txt, String intentId, boolean shouldBeSame) throws NCException, IOException {
+ NCTestResult res = cli.ask(txt);
+
+ assertTrue(res.isOk(), () -> res.getResultError().get());
+
+ assert res.getResult().isPresent();
+
+ Map<String, Object> map = GSON.fromJson(res.getResult().get(), TYPE_MAP_RESP);
+
+ if (shouldBeSame)
+ assertEquals(intentId, map.get("intentId"));
+ else
+ assertNotEquals(intentId, map.get("intentId"));
+ }
+
+ @BeforeEach
+ void setUp() throws NCException, IOException {
+ NCEmbeddedProbe.start(WeatherModel.class);
+
+ cli = new NCTestClientBuilder().newBuilder().build();
+
+ cli.open("nlpcraft.weather.ex"); // See weather_model.json
+ }
+
+ @AfterEach
+ void tearDown() throws NCException, IOException {
+ if (cli != null)
+ cli.close();
+
+ NCEmbeddedProbe.stop();
+ }
+
+ @Test
+ void test() throws NCException, IOException {
+ // Empty parameter.
+ assertTrue(cli.ask("").isFailed());
+
+ // Only latin charset is supported.
+ assertTrue(cli.ask("El tiempo en España").isFailed());
+
+ // Should be passed.
+ checkIntent("What's the local weather forecast?", "fcast", true);
+ checkIntent("What's the weather in Moscow?", "curr", true);
+ // Can be answered with conversation.
+ checkIntent("Chance of snow?", "curr", true);
+ checkIntent("Moscow", "curr", true);
+
+ cli.clearConversation();
+
+ // Cannot be answered without conversation.
+ assertTrue(cli.ask("Moscow").isFailed());
+ }
+}
+ </pre>
+ <p>
+ This test is pretty straight forward:
+ </p>
+ <ul>
+ <li>
+ On <code>line 15</code> we open the test client with the model ID (see <code>lightswitch_model.yaml</code>
+ file for where we declared it).
+ </li>
+ <li>
+ Test on <code>line 24</code> is where we issue our test sentences and we should see
+ the confirmation messages in our test console output.
+ </li>
+ </ul>
+ <p>
+ Right click on this class in the project view and run it. You should be getting standard output in
+ JUnit panel as well as the output in the data probe console.
+ </p>
+ </section>
+ <section>
+ <h2 class="section-title">Done! 👌</h2>
+ <p>
+ You've created pretty full featured weather bot data model, deployed it into the data probe, started the
+ REST server and tested this model using JUnit 5 and the built-in test framework.
+ </p>
+ </section>
</div>
<div class="col-md-2 third-column">
<ul class="side-nav">
<li class="side-nav-title">On This Page</li>
<li><a href="#overview">Overview</a></li>
+ <li><a href="#new_project">New Project</a></li>
+ <li><a href="#add_nlpcraft">Add NLPCraft</a></li>
+ <li><a href="#model">Data Model</a></li>
+ <li><a href="#code">Model Class</a></li>
+ <li><a href="#tools">External Tools</a></li>
+ <li><a href="#start_probe">Start Probe</a></li>
+ <li><a href="#start_server">Start Server</a></li>
+ <li><a href="#testing">Testing</a></li>
{% include quick-links.html %}
</ul>
</div>
diff --git a/first-example.html b/first-example.html
index fad60d3..28265f3 100644
--- a/first-example.html
+++ b/first-example.html
@@ -280,7 +280,7 @@ class LightSwitchModel extends NCModelFileAdapter("org/apache/nlpcraft/examples/
<p>
At this point we've developed our data model, deployed it into the data probe, and started the REST server.
Our NLI-based light switch is ready to accept user requests. Instead of using direct REST calls we'll
- demonstrate the built-in <a href="/testing-data-model.html">test framework</a> that allows you to write
+ demonstrate the built-in <a href="/tools/test_framework.html">test framework</a> that allows you to write
convenient unit tests against your data model.
</p>
</section>
diff --git a/tools/embedded_probe.html b/tools/embedded_probe.html
index a69b929..ed2435a 100644
--- a/tools/embedded_probe.html
+++ b/tools/embedded_probe.html
@@ -73,7 +73,7 @@ id: embedded_probe
</li>
</ul>
<p>
- Here's an code snippet from <a target="javadoc" href="https://github.com/apache/incubator-nlpcraft/blob/master/src/main/scala/org/apache/nlpcraft/examples/alarm/AlarmTest.java">Alarm Clock</a>
+ Here's an code snippet from <a href="/examples/alarm_clock.html">Alarm Clock</a>
example illustrating the usage of embedded probe together with NLPCraft test framework and JUnit 5:
</p>
<pre class="brush: java, highlight: [6, 18]">
diff --git a/tools/test_framework.html b/tools/test_framework.html
index 8b393a7..2cd613d 100644
--- a/tools/test_framework.html
+++ b/tools/test_framework.html
@@ -67,7 +67,7 @@ id: test_framework
<section id="usage">
<h2 class="section-title">Usage</h2>
<p>
- Here's an code snippet from <a target="javadoc" href="https://github.com/apache/incubator-nlpcraft/blob/master/src/main/scala/org/apache/nlpcraft/examples/alarm/AlarmTest.java">Alarm Clock</a>
+ Here's an code snippet from <a href="/examples/alarm_clock.html">Alarm Clock</a>
example illustrating the usage of test framework together with JUnit 5:
</p>
<pre class="brush: java, highlight: [8, 10, 16, 24, 25, 26]">