blob: e9b8c05bce0296a91d129afab2d6b4165d2f59c5 [file] [log] [blame]
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!doctype html><html lang="en"><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><meta name="description" content="An open source API to convert natural language into actions."><meta name="author" content="NLPCraft."><title>Apache NLPCraft - Natural Language Interface</title><link href="//netdna.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet"><link href="//use.fontawesome.com/releases/v5.7.1/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" rel="stylesheet" crossorigin="anonymous"><link href="/ext/syntaxhighlighter/styles/shCoreNLPCraft.css" rel="stylesheet" type="text/css"><link href="/ext/syntaxhighlighter/styles/shThemeNLPCraft.css" rel="stylesheet" type="text/css"><link href="//fonts.googleapis.com/css?family=Amatic+SC|Roboto+Mono" rel="stylesheet"> <script src="/ext/syntaxhighlighter/scripts/XRegExp.js" type="text/javascript"></script> <script src="/ext/syntaxhighlighter/scripts/shCore.js" type="text/javascript"></script> <script src="/ext/syntaxhighlighter/scripts/shBrushXml.js" type="text/javascript"></script> <script src="/ext/syntaxhighlighter/scripts/shBrushPlain.js" type="text/javascript"></script> <script src="/ext/syntaxhighlighter/scripts/shBrushJava.js" type="text/javascript"></script> <script src="/ext/syntaxhighlighter/scripts/shBrushScala.js" type="text/javascript"></script> <script src="/ext/syntaxhighlighter/scripts/shBrushPython.js" type="text/javascript"></script> <script src="/ext/syntaxhighlighter/scripts/shBrushJScript.js" type="text/javascript"></script> <script async defer src="https://buttons.github.io/buttons.js"></script><link rel="stylesheet" type="text/css" href="/assets/css/style.css"/> <script type="text/javascript" src="//use.typekit.net/pso2adz.js"></script> <script type="text/javascript"> try { Typekit.load(); } catch(e) { // Ignore. } </script><nav class="navbar navbar-expand-lg navbar-light bg-light" id="top-header"> <a class="navbar-brand mr-4" href="/index.html"> <img src="/images/nlpcraft_logo_white.gif" height="24px"> </a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button><div class="collapse navbar-collapse" id="navbarSupportedContent"><ul class="navbar-nav mr-auto"><li class="nav-item"> <a class="nav-link" href="/index.html#features">Features</a><li class="nav-item"> <a class="nav-link" href="/docs.html">Docs</a><li class="nav-item"> <a class="nav-link" href="/download.html">Downloads <i class="fas fa-download"></i></a><li class="nav-item"> <a class="nav-link" href="/community.html">Community</a><li class="nav-item"> <a class="nav-link" href="/use-cases.html">Use Cases</a></ul><ul class="navbar-nav ml-auto"><li class="nav-item mr-2"> <a class="nav-link" href="/download.html">v.0.5.0</a><li class="nav-item"> <a class="nav-link fork-link" target="github" href="https://github.com/apache/incubator-nlpcraft">GitHub <img height="20px" src="/images/github_logo_white.png"></a></ul></div></nav><div class="container-fluid"><div class="navbar-aligned"><ol class="breadcrumb"><li class="mr-1"><a href="/index.html">Home</a><li class="mr-1 active">First Example</ol><h1 class="page-title"> <span><i class="fas fa-fw fa-book"></i> First Example</span></h1><div class="three-cols-container"><div class="col-md-2 first-column"><ul class="side-nav"><li class="side-nav-title">Introduction<li> <a href="/docs.html">Overview</a><li> <a href="/installation.html">Installation</a><li> <a href="/getting-started.html">Getting Started</a><li class="side-nav-title">Developer Guide<li> <a href="/basic-concepts.html">Basic Concepts</a><li> <a class="active" href="/first-example.html">First Example</a><li> <a href="/data-model.html">Data Model</a><li> <a href="/intent-matching.html">Intent Matching</a><li> <a href="/using-rest.html">REST API</a><li> <a href="/server-and-probe.html">Server <span class="amp">&amp;</span> Probe</a><li> <a href="/metrics-and-tracing.html">Metrics <span class="amp">&amp;</span> Tracing</a><li> <a href="/integrations.html">Integrations</a><li class="side-nav-title">Examples<li> <a href="/examples/alarm_clock.html">Alarm Clock</a><li> <a href="/examples/light_switch.html">Light Switch</a></ul></div><div class="col-md-8 second-column"><section id="setup"><h2 class="section-title">Project Setup</h2><p> Let's setup a project for our first example with the following assumptions:</p><ul><li>We'll use Mac OS/Linux environment<li>We'll use Scala to implement our model<li>We'll use <a target=_ href="https://maven.apache.org/install.html">Maven</a> to create and build our project<li>We'll use <a target=_ href="https://www.jetbrains.com/idea/">JetBrains IDEA</a> as our Scala/Java IDE</ul></section><section id="new_project"><h3 class="section-title">Create New Project</h3><p> You can create new Maven-based 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><p> 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> We also 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]">
&lt;dependencies&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.nlpcraft&lt;/groupId&gt;
&lt;artifactId&gt;nlpcraft&lt;/artifactId&gt;
&lt;version&gt;0.5.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;/dependencies&gt;
</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]">
&lt;properties&gt;
&lt;project.build.sourceEncoding&gt;UTF-8&lt;/project.build.sourceEncoding&gt;
&lt;maven.compiler.source&gt;1.8&lt;/maven.compiler.source&gt;
&lt;maven.compiler.target&gt;1.8&lt;/maven.compiler.target&gt;
&lt;/properties&gt;
</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 new first data model.</p></section><section id="data_model"><h2 class="section-title">Data Model</h2><p> For our example we'll develop a prototypical light switch that can be controlled through the natural language. We'll keep <a target=_ href="https://cloud.google.com/speech-to-text/">speech-to-text conversion</a> and integration with <a target=_ href="https://developer.apple.com/homekit/">HomeKit</a> or <a href="https://www.arduino.cc/" target=_>Ardunio</a> outside of this example - and concentrate only on understanding the natural language commands. At the end, we should be able to say <code>"Turn the lights off in the guest bedroom"</code> or <code>"Could you please switch off all the lights?"</code></p><p> In NLPCraft a data model is simply an implementation of <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCModel.html">NCModel</a> interface. You can move most of the model configuration out to an external JSON or YAML file and use <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCModelFileAdapter.html">NCModelFileAdapter</a> to load this external configuration when creating a new model. Note that this is a canonical pattern to build models in NLPCraft and it allows you cleanly separate the logic of the model from its declarative configuration.</p><p> Let's add new <code>lightswitch_model.yml</code> file containing our model's static configuration in YAML into <code>src/main/java/examples</code> folder with the following content:</p><pre class="brush: js, highlight: [1, 14, 21, 28]">
id: "nlpcraft.lightswitch.ex"
name: "Light Switch Example Model"
version: "1.0"
description: "NLI-powered light switch example model."
macros:
- name: "&lt;ACTION&gt;"
macro: "{turn|switch|dial|control|let|set|get|put}"
- name: "&lt;ENTIRE_OPT&gt;"
macro: "{entire|full|whole|total|*}"
- name: "&lt;LIGHT&gt;"
macro: "{it|them|light|illumination|lamp|lamplight}"
enabledBuiltInTokens: [] # Don't use any built-in tokens.
elements:
- id: "ls:loc"
description: "Location of lights."
synonyms:
- "&lt;ENTIRE_OPT&gt; {upstairs|downstairs|*} {kitchen|library|closet|garage|office|playroom|{dinning|laundry|play} room}"
- "&lt;ENTIRE_OPT&gt; {upstairs|downstairs|*} {master|kid|children|child|guest|*} {bedroom|bathroom|washroom|storage} {closet|*}"
- "&lt;ENTIRE_OPT&gt; {house|home|building|{1st|first} floor|{2nd|second} floor}"
- id: "ls:on"
group: "act"
description: "Light switch ON action."
synonyms:
- "&lt;ACTION&gt; &lt;LIGHT&gt; on"
- "&lt;ACTION&gt; on &lt;LIGHT&gt;"
- id: "ls:off"
group: "act"
description: "Light switch OFF action."
synonyms:
- "&lt;ACTION&gt; &lt;LIGHT&gt; {off|out}"
- "{&lt;ACTION&gt;|shut|kill|stop|eliminate} {off|out} &lt;LIGHT&gt;"
- "no &lt;LIGHT&gt;"
</pre><p> Notice the model ID <code>nlpcraft.lightswitch.ex</code> as well as semantic model elements that we'll use later:</p><ul><li><code>ls:loc</code><li><code>ls:on</code><li><code>ls:off</code></ul><p> Model element <code>ls:loc</code> defines a location where we want to control the lights. Model elements <code>ls:on</code> and <code>ls:off</code> defines corresponding "on" and "off" lights actions. We'll use these elements in our model's intent-based matching logic.</p><p> Next let's go ahead and add model's logic. Create new <code>LightSwitchModel.scala</code> file along side <code>lightswitch_model.json</code> configuration file and copy the following model code into it:</p><pre class="brush: java, highlight: [7,9,10]">
package examples;
import org.apache.nlpcraft.model._
import org.apache.nlpcraft.model.NCIntentTerm
class LightSwitchModel extends NCModelFileAdapter("org/apache/nlpcraft/examples/lightswitch/lightswitch_model.yaml") {
@NCIntent("intent=ls conv=false term(act)={groups @@ 'act'} term(loc)={id == 'ls:loc'}*")
def onMatch(
@NCIntentTerm("act") actTok: NCToken,
@NCIntentTerm("loc") locToks: List[NCToken]
): NCResult = {
val status = if (actTok.getId == "ls:on") "on" else "off"
val locations =
if (locToks.isEmpty)
"entire house"
else
locToks.map(_.getOriginalText).mkString(", ")
// Add HomeKit, Arduino or other integration here.
NCResult.text(s"Lights '$status' in '${locations.toLowerCase}'.")
}
}
</pre><p> Chapter <a href="/data-model.html">Data Model</a> will provide detailed explanation on how data models work. Here are few comments as to what this code does and how it is organized:</p><ul><li> On line 6 we use <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCModelFileAdapter.html">NCModelFileAdapter</a> adapter and load model static configuration from <code>lightswitch_model.yml</code> file.<li> Our data model uses intent-based matching of the user input. Intent is a template and a callback for when a template is matched. Lines 7, 9 and 10 show the usage of <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/inteint/NCIntent.html">@NCIntent</a> and <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/inteint/NCIntent.html">@NCIntentTerm</a> annotations that are used to connect the matching logic with a callback method.<li> The intent defined through <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/inteint/NCIntent.html">@NCIntent</a> annotation matches two parts: first should be any token belonging to <code>act</code> group (i.e. "on" or "off" action), and the second should be a zero or more tokens with ID equal to <code>ls:loc</code> (i.e. optional list of locations).<li> If and when our intent is matched the method <code>onMatch(...)</code> on line 8 is invoked. It simply returns a text response that indicates the light status at a requested location. That's where you can also add <a target=_ href="https://developer.apple.com/homekit/">HomeKit</a>, <a href="https://www.arduino.cc/" target=_>Ardunio</a> or other integrations to make a real lightswitch in your home.</ul></section><section><h3 class="section-title">Start Data Probe</h3><p> NLPCraft data models get deployed into data probe. Let's start data probe to deploy our newly created light switch 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> <b>VM arguments:</b> <code>-Dconfig.override_with_env_vars=true</code><li> <b>Environment variable:</b> <code>CONFIG_FORCE_nlpcraft_probe_models.0=org.apache.nlpcraft.examples.lightswitch.LightSwitchModel</code><li> <b>Program arguments: </b> <code>-probe</code></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><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> <b>Program arguments: </b> <code>-server</code></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. 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 convenient unit tests against your data model.</p></section><section><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 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 the following user requests:</p><ul><li><code>"Turn the lights off in the entire house."</code><li><code>"Switch on the illumination in the master bedroom closet."</code><li><code>"Get the lights on."</code><li><code>"Please, put the light out in the upstairs bedroom."</code><li><code>"Set the lights on in the entire house."</code><li><code>"Turn the lights off in the guest bedroom."</code><li><code>"Could you please switch off all the lights?"</code><li><code>"Dial off illumination on the 2nd floor."</code><li><code>"Please, no lights!"</code><li><code>"Kill off all the lights now!"</code><li><code>"No lights in the bedroom, please."</code></ul><p> Let's create new Java class <code>LightSwitchTest.java</code> in <code>src/<b>test</b>/java/examples</code> folder with the following code:</p><pre class="brush: java, highlight: [17]">
package examples;
import org.junit.jupiter.api.*;
import org.apache.nlpcraft.common.*;
import org.apache.nlpcraft.model.tools.test.*;
import java.io.*;
import static org.junit.jupiter.api.Assertions.*;
public class LightSwitchTest {
private NCTestClient cli;
@BeforeEach
void setUp() throws NCException, IOException {
cli = new NCTestClientBuilder().newBuilder().build();
cli.open("nlpcraft.lightswitch.ex");
}
@AfterEach
void tearDown() throws NCException, IOException {
cli.close();
}
@Test
public void test() throws NCException, IOException {
assertTrue(cli.ask("Turn the lights off in the entire house.").isOk());
assertTrue(cli.ask("Switch on the illumination in the master bedroom closet.").isOk());
assertTrue(cli.ask("Get the lights on.").isOk());
assertTrue(cli.ask("Please, put the light out in the upstairs bedroom.").isOk());
assertTrue(cli.ask("Set the lights on in the entire house.").isOk());
assertTrue(cli.ask("Turn the lights off in the guest bedroom.").isOk());
assertTrue(cli.ask("Could you please switch off all the lights?").isOk());
assertTrue(cli.ask("Dial off illumination on the 2nd floor.").isOk());
assertTrue(cli.ask("Please, no lights!").isOk());
assertTrue(cli.ask("Kill off all the lights now!").isOk());
assertTrue(cli.ask("No lights in the bedroom, please.").isOk());
}
}
</pre><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 lights status based on the above requests.</p></section><section><h2 class="section-title">Congratulation! 👌</h2><p> You've created your first data model, deployed it into the data probe, started the REST server and tested the 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><a href="#setup">Project Setup</a><li><a href="#data_model">Data Model</a><li class="side-nav-title">Quick Links<li> <i class="fab fa-fw fa-github mr-2"></i><a target="github" href="https://github.com/apache/incubator-nlpcraft/tree/master/src/main/scala/org/apache/nlpcraft/examples">Examples</a><li> <i class="fab fa-fw fa-java mr-2"></i><a target="_" href="/apis/latest/index.html">Javadoc</a><li> <i class="fas fa-fw fa-code mr-2"></i><a href="https://github.com/apache/incubator-nlpcraft/blob/master/openapi/nlpcraft_swagger.yml" target="github">REST API</a><li> <i class="fas fa-fw fa-download mr-2"></i><a href="/download.html">Download</a><li class="side-nav-title">Support<li> <nobr> <i class="fab fa-fw fa-jira mr-2"></i><a target="jira" href="https://issues.apache.org/jira/projects/NLPCRAFT/issues">JIRA</a> </nobr><li> <nobr> <i class="far fa-fw fa-envelope mr-2"></i><a href="http://mail-archives.apache.org/mod_mbox/nlpcraft-dev/">Dev List</a> </nobr><li> <nobr> <i class="fab fa-fw fa-stack-overflow mr-2"></i><a target="so" href="https://stackoverflow.com/questions/ask">Stack Overflow</a> </nobr><li> <nobr> <i class="fab fa-fw fa-github mr-2"></i><a target="github" href="https://github.com/apache/incubator-nlpcraft">GitHub</a> </nobr></ul></div></div></div></div><div id="footer"><div class="container"><div class="text-muted text-center"> <span>Copyright &copy; 2020 Apache Software Foundation</span> <span> <a target=_new href="https://apache.org"><img alt="asf" src="/images/asf_logo.png" height="24px"></a> </span> <a target="asf" href="http://apache.org/foundation/policies/privacy.html" class="btn btn-link ml-4">Privacy</a> <span class="sep"></span> <a href="/index.html#news" class="btn btn-link">News</a> <span class="sep"></span> <a href="/docs.html" class="btn btn-link">Docs</a> <span class="ml-4">release: <a href="/download.html"><code>0.5.0</code></a></span> <span class="ml-2"> <a target="jenkins" href="https://builds.apache.org/view/Incubator%20Projects/job/incubator-nlpcraft/"><img src="https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fbuilds.apache.org%2Fview%2FIncubator%2520Projects%2Fjob%2Fincubator-nlpcraft%2F"></a> <a target=_ href="https://gitter.im/apache-nlpcraft/community"><img alt="Gitter" src="https://badges.gitter.im/apache-nlpcraft/community.svg"></a> </span></div></div></div><script src="//code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js" integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ" crossorigin="anonymous"></script> <script src="//stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js" integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm" crossorigin="anonymous"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js" type="text/javascript" ></script> <script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js" type="text/javascript" ></script> <script src="//cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.5/moment-timezone-with-data.min.js" type="text/javascript" ></script> <script type="text/javascript"> SyntaxHighlighter.defaults["auto-links"] = false; SyntaxHighlighter.defaults["tab-size"] = 2; SyntaxHighlighter.all(); </script>