ex
ex
nlpcraft.{sh|cmd}
This example provides very simple implementation for NLI-powered light switch. You can say something like "Turn the lights off in the entire house" or "Switch on the illumination in the master bedroom closet". You can modify intent callbacks to perform the actual light switching using HomeKit or Arduino-based controllers.
Complexity:
Source code: GitHub
You can create new Scala project in many different ways - we'll use NLPCraft CLI to accomplish this task:
$ bin/nlpcraft.sh gen-project --baseName=LightSwitch --outputDir=~ --pkgName=demo --lang=scala
NOTES:
/home/LightSwitch
directory.gen-project
command defaults to Java and Maven as its built tool.bin/nlpcraft.sh help --cmd=gen-project
to get a full help on gen-project
command.nlpcraft.sh
for and nlpcraft.cmd
for . We are going to start with declaring the static part of our model using YAML which we will later load using NCModelFileAdapter
in our Scala-based model implementation. Open src/main/resources/light_switch.yaml
file and replace its content with the following YAML:
id: "nlpcraft.lightswitch.ex" name: "Light Switch Example Model" version: "1.0" description: "NLI-powered light switch example model." macros: - name: "<ACTION>" macro: "{turn|switch|dial|control|let|set|get|put}" - name: "<ENTIRE_OPT>" macro: "{entire|full|whole|total|*}" - name: "<LIGHT>" macro: "{all|*} {it|them|light|illumination|lamp|lamplight}" enabledBuiltInTokens: [] # This example doesn't use any built-in tokens. elements: - id: "ls:loc" description: "Location of lights." synonyms: - "<ENTIRE_OPT> {upstairs|downstairs|*} {kitchen|library|closet|garage|office|playroom|{dinning|laundry|play} room}" - "<ENTIRE_OPT> {upstairs|downstairs|*} {master|kid|children|child|guest|*} {bedroom|bathroom|washroom|storage} {closet|*}" - "<ENTIRE_OPT> {house|home|building|{1st|first} floor|{2nd|second} floor}" - id: "ls:on" groups: - "act" description: "Light switch ON action." synonyms: - "<ACTION> <LIGHT>" - "<ACTION> on <LIGHT>" - id: "ls:off" groups: - "act" description: "Light switch OFF action." synonyms: - "<ACTION> <LIGHT> {off|out}" - "{<ACTION>|shut|kill|stop|eliminate} {off|out} <LIGHT>" - "no <LIGHT>" intents: - "intent=ls term(act)={groups @@ 'act'} term(loc)={id == 'ls:loc'}*"
There are number of important points here:
Line 10
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.Lines 19, 26, 34
define three model elements: the location of the light, and actions to turn the light on and off. Note that action elements belong to the same group act
which will be used in our intent (line 42
).line 42
we define a non-conversational intent ls
that requires one action (a token belonging to the group act
) and optional light location - we assume all lights by default. Now that our model is ready let's create a Java class that would load this model and provide the actual callback for when the intent ls
is detected in the user input.
Open src/main/scala/demo/LightSwitch.scala
with the following code:
package demo import org.apache.nlpcraft.model.{NCIntentTerm, _} class LightSwitch extends NCModelFileAdapter("light_switch.yaml") { @NCIntentRef("ls") @NCIntentSample(Array( "Turn the lights off in the entire house.", "Switch on the illumination in the master bedroom closet.", "Get the lights on.", "Please, put the light out in the upstairs bedroom.", "Set the lights on in the entire house.", "Turn the lights off in the guest bedroom.", "Could you please switch off all the lights?", "Dial off illumination on the 2nd floor.", "Please, no lights!", "Kill off all the lights now!", "No lights in the bedroom, please." )) 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(_.meta[String]("nlpcraft:nlp:origtext")).mkString(", ") // Add HomeKit, Arduino or other integration here. // By default - return a descriptive action string. NCResult.text(s"Lights '$status' in '${locations.toLowerCase}'.") } }
The intent callback logic is very simple - we simply return a descriptive confirmation message back (explaining what lights were changed). With action and location detected - you can add the actual light switching using HomeKit or Arduino devices. Let's review this implementation step by step:
line 5
our class extends NCModelFileAdapter
that allows us to load most of the model declaration from the external YAML file and only provide functionality that we couldn't express in declarative portion in JSON.Line 6
annotates method onMatch
as a callback for the intent ls
when it is detected in the user input.Lines 21 and 22
map terms from detected intent to the formal method parameters of the onMatch
method.line 34
the intent callback simply returns a confirmation message. Once we have our model ready let's go to ~/LightSwitch
directory and run the Maven build:
$ cd ~/LightSwitch $ mvn clean package
At this stage we have our project built and we are ready to start testing.
Run the following command to start local REST server, if it hasn't been started already, from the NLPCraft installation directory:
$ bin/nlpcraft.sh start-server
NOTES:
bin/nlpcraft.sh help --cmd=start-server
to get a full help on this command.nlpcraft.sh
for and nlpcraft.cmd
for .Remember the @NCIntentSample annotation we have used in our model code next to intent definition?
Part of the test framework, the auto-validator class NCTestAutoModelValidator takes one or more model IDs (or class names) and performs validation. Validation consists of starting an embedded probe with a given model, scanning for @NCIntentSample annotations and their corresponding callback methods, submitting each sample input sentences from @NCIntentSample annotation and checking that resulting intent matches the intent the sample was attached to. Note that auto-testing does not require any additional code to be written - the class gathers all required information from the model itself.
As always, you can launch model auto-validator as any other Java class but we'll use NLPCraft CLI to do it more conveniently:
$ bin/nlpcraft.sh test-model --cp=~/LightSwitch/target/classes --mdls=demo.LightSwitch
NOTES:
bin/nlpcraft.sh help --cmd=test-model
to get a full help on this command.nlpcraft.sh
for and nlpcraft.cmd
for .Look at the output of this command and you will see the test results for all our sample utterances:
Typical development cycle consists of:
All of these operations can be performed from NLPCraft CLI in REPL mode or from any IDE.
NOTE: you don't need to restart REST server every time - it only needs to be started once.
You've created light switch data model, started the REST server and tested this model using the built-in test framework.