This is an automated email from the ASF dual-hosted git repository. sergeykamov pushed a commit to branch NLPCRAFT-513 in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft-website.git
commit 726c2b0907f2cfb7175038f2f2928c69b88a1e83 Author: skhdl <[email protected]> AuthorDate: Fri Oct 14 12:36:49 2022 +0400 WIP. --- examples/light_switch.html | 410 ++++++++++++++------------------------------- 1 file changed, 123 insertions(+), 287 deletions(-) diff --git a/examples/light_switch.html b/examples/light_switch.html index 81fbaa3..d60700d 100644 --- a/examples/light_switch.html +++ b/examples/light_switch.html @@ -40,137 +40,111 @@ fa_icon: fa-cube <section id="new_project"> <h2 class="section-title">Create New Project <a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> <p> - You can create new Scala projects in many ways - we'll use <a href="/tools/script.html">NLPCraft CLI</a> + You can create new Scala projects in many ways - we'll use SBT to accomplish this task: </p> - <nav> - <div class="nav nav-tabs" role="tablist"> - <a class="nav-item nav-link active" data-toggle="tab" href="#nav-prj-cmd" role="tab">Command</a> - <a class="nav-item nav-link" data-toggle="tab" href="#nav-prj-out" role="tab">Output <i class="fa fa-desktop output"></i></a> - </div> - </nav> - <div class="tab-content"> - <div class="tab-pane fade show active" id="nav-prj-cmd" role="tabpanel"> - <pre class="brush: bash"> - $ bin/nlpcraft.sh gen-project --baseName=LightSwitch --outputDir=~ --pkgName=demo --lang=scala - </pre> - <p> - <b>NOTES:</b> - </p> - <ul> - <li> - New project created in <code>/home/LightSwitch</code> directory. - </li> - <li> - <code>gen-project</code> command defaults to Java and Maven as its built tool. - </li> - <li> - Run <code class="script">bin/nlpcraft.sh help --cmd=gen-project</code> to get a full help on <code>gen-project</code> command. - </li> - <li> - <a href="/tools/script.html">NLPCraft CLI</a> is available as <code>nlpcraft.sh</code> for - <i class="fab fa-fw fa-linux"></i> and <code>nlpcraft.cmd</code> - for <i class="fab fa-fw fa-windows"></i>. - </li> - </ul> - </div> - <div class="tab-pane fade show" id="nav-prj-out" role="tabpanel"> - <p></p> - <img alt="" class="img-fluid" src="/images/light_switch_fig1.png"> - </div> - </div> + <pre class="brush: js, highlight: []"> + ThisBuild / version := "0.1.0-SNAPSHOT" + ThisBuild / scalaVersion := "3.1.3" + lazy val root = (project in file(".")) + .settings( + name := "NLPCraft LightSwitch Example", + version := "1.0.0", + libraryDependencies += "org.apache.nlpcraft" % "nlpcraft" % "1.0.0", + libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.14" % "test" + ) + </pre> + <p> Make in prepared project following files: </p> + <ul> + <li><code>lightswitch_model.yaml</code> - YAML configuration file, which contains model description.</li> + <li><code>LightSwitchScalaModel.scala</code> - scala class, model representation.</li> + <li><code>NCModelValidationSpec.scala</code> - scala tests class, which allows to test your model.</li> + </ul> + <p> Look at the result SBT project files structure below: </p> + <pre class="brush: js, highlight: [10, 18, 27]"> + C:. + | build.sbt + | + +---project + | build.properties + | + \---src + +---main + | +---resources + | | lightswitch_model.yaml + | | + | \---scala + | \---demo + | LightSwitchScalaModel.scala + | + \---test + \---scala + \---demo + NCModelValidationSpec.scala + </pre> </section> <section id="model"> - <h2 class="section-title">Data Model <a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> + <h2 class="section-title">Data Model Description<a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> <p> We are going to start with declaring the static part of our model using YAML which we will later load using - <code>NCModelFileAdapter</code> in our Scala-based model implementation. Open <code>src/main/resources/<b>light_switch.yaml</b></code> + <code>NCModelAdapter</code> in our Scala-based model implementation. + Open <code>src/main/resources/<b>light_switch.yaml</b></code> file and replace its content with the following YAML: </p> - <pre class="brush: js, highlight: [6, 22, 23, 26, 33, 41, 52]"> -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|let|set|get|put}" - - name: "<KILL>" - macro: "{shut|kill|stop|eliminate}" - - name: "<ENTIRE_OPT>" - macro: "{entire|full|whole|total|_}" - - name: "<FLOOR_OPT>" - macro: "{upstairs|downstairs|{1st|2nd|3rd|4th|5th|top|ground} floor|_}" - - name: "<TYPE>" - macro: "{room|closet|attic|loft|{store|storage} {room|_}}" - - name: "<LIGHT>" - macro: "{all|_} {it|them|light|illumination|lamp|lamplight}" - -enabledBuiltInTokens: [] - -permutateSynonyms: true -sparse: true - -elements: - - id: "ls:loc" - description: "Location of lights." - synonyms: - - "<ENTIRE_OPT> <FLOOR_OPT> {kitchen|library|closet|garage|office|playroom|{dinning|laundry|play} <TYPE>}" - - "<ENTIRE_OPT> <FLOOR_OPT> {master|kid|children|child|guest|_} {bedroom|bathroom|washroom|storage} {<TYPE>|_}" - - "<ENTIRE_OPT> {house|home|building|{1st|first} floor|{2nd|second} floor}" - - - id: "ls:on" - groups: - - "act" - description: "Light switch ON action." - synonyms: - - "<ACTION> {on|up|_} <LIGHT> {on|up|_}" - - "<LIGHT> {on|up}" - - - id: "ls:off" - groups: - - "act" - description: "Light switch OFF action." - synonyms: - - "<ACTION> <LIGHT> {off|out}" - - "{<ACTION>|<KILL>} {off|out} <LIGHT>" - - "<KILL> <LIGHT>" - - "<LIGHT> <KILL>" - - "no <LIGHT>" - -intents: - - "intent=ls term(act)={has(tok_groups, 'act')} term(loc)={# == 'ls:loc'}*" + <pre class="brush: js, highlight: [1, 10, 17, 25]"> + macros: + "<ACTION>" : "{turn|switch|dial|let|set|get|put}" + "<KILL>" : "{shut|kill|stop|eliminate}" + "<ENTIRE_OPT>" : "{entire|full|whole|total|_}" + "<FLOOR_OPT>" : "{upstairs|downstairs|{1st|first|2nd|second|3rd|third|4th|fourth|5th|fifth|top|ground} floor|_}" + "<TYPE>" : "{room|closet|attic|loft|{store|storage} {room|_}}" + "<LIGHT>" : "{all|_} {it|them|light|illumination|lamp|lamplight}" + + elements: + - id: "ls:loc" + description: "Location of lights." + synonyms: + - "<ENTIRE_OPT> <FLOOR_OPT> {kitchen|library|closet|garage|office|playroom|{dinning|laundry|play} <TYPE>}" + - "<ENTIRE_OPT> <FLOOR_OPT> {master|kid|children|child|guest|_} {bedroom|bathroom|washroom|storage} {<TYPE>|_}" + - "<ENTIRE_OPT> {house|home|building|{1st|first} floor|{2nd|second} floor}" + + - id: "ls:on" + groups: + - "act" + description: "Light switch ON action." + synonyms: + - "<ACTION> {on|up|_} <LIGHT> {on|up|_}" + - "<LIGHT> {on|up}" + + - id: "ls:off" + groups: + - "act" + description: "Light switch OFF action." + synonyms: + - "<ACTION> <LIGHT> {off|out|down}" + - "{<ACTION>|<KILL>} {off|out|down} <LIGHT>" + - "<KILL> <LIGHT>" + - "<LIGHT> <KILL>" + - "{out|no|off|down} <LIGHT>" + - "<LIGHT> {out|off|down}" </pre> <p>There are number of important points here:</p> <ul> <li> - <code>Line 6</code> defines several macros that are used later on throughout the model's elements + <code>Line 1</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 22, 23</code> define model properties that allow for multi-word synonyms in this model - to be - <a class="not-code" target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCModelView.html#isSparse()">sparse</a> and - <a class="not-code" target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCModelView.html#isPermutateSynonyms()">permutate</a> them for better detection. These two properties generally enable a free-form - natural language comprehension. - </li> - <li> - <code>Lines 26, 33, 41</code> define three model elements: the location of the light, and actions to turn + <code>Lines 10, 17, 25</code> define three model elements: the location of the light, and actions to turn the light on and off. Action elements belong to the same group <code>act</code> which - will be used in our intent (<code>line 42</code>). Note that these model elements are defined mostly + will be used in our intent, defined in <code>LightSwitchScalaModel</code>. Note that these model elements are defined mostly through macros we have provided above. </li> - <li> - On <code>line 52</code> we define a non-conversational intent <code>ls</code> that requires - one action (a token belonging to the group <code>act</code>) and optional list of light locations - (zero or more tokens with ID <code>ls:loc</code>) - by default we assume the entire house as a default location. - </li> </ul> <p> - 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 <code>ls</code> is detected in the user input. + Note that this YAML model elements description is optional and all elements definitions can be provided inside + Scala model <code>LightSwitchScalaModel</code>. </p> </section> <section id="code"> @@ -178,47 +152,29 @@ intents: <p> Open <code>src/main/scala/demo/<b>LightSwitch.scala</b></code> file and replace its content with the following code: </p> - <pre class="brush: scala, highlight: [5, 6, 7, 25, 26, 38]"> -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.", - "Turn off all lights now", - "Switch on the illumination in the master bedroom closet.", - "Get the lights on.", - "Lights up in the kitchen.", - "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.", - "Light up the garage, please!", - "Kill the illumination now!" - )) - 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. - - // By default - return a descriptive action string. - NCResult.text(s"Lights '$status' in '${locations.toLowerCase}'.") - } -} + <pre class="brush: scala, highlight: [6, 7, 8, 10, 11, 14, 15, 22]"> + package demo + + import org.apache.nlpcraft.* + import org.apache.nlpcraft.annotations.* + + class LightSwitchScalaModel extends NCModelAdapter( + NCModelConfig("nlpcraft.lightswitch.java.ex", "LightSwitch Example Model", "1.0"), + new NCPipelineBuilder().withSemantic("en", "lightswitch_model.yaml").build + ): + @NCIntent("intent=ls term(act)={has(ent_groups, 'act')} term(loc)={# == 'ls:loc'}*") + def onMatch( + ctx: NCContext, + im: NCIntentMatch, + @NCIntentTerm("act") actEnt: NCEntity, + @NCIntentTerm("loc") locEnts: List[NCEntity] + ): NCResult = + val status = if actEnt.getId == "ls:on" then "on" else "off" + val locations = if locEnts.isEmpty then "entire house" else locEnts.map(_.mkText).mkString(", ") + + // Add HomeKit, Arduino or other integration here.= + // By default - just return a descriptive action string. + NCResult(s"Lights are [$status] in [${locations.toLowerCase}].") </pre> <p> The intent callback logic is very simple - we return a descriptive confirmation message @@ -227,160 +183,43 @@ class LightSwitch extends NCModelFileAdapter("light_switch.yaml") { </p> <ul> <li> - On <code>line 5</code> our class extends <code>NCModelFileAdapter</code> 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 YAML. - </li> - <li> - <code>Line 6</code> annotates method <code>onMatch</code> as a callback for the intent <code>ls</code> - when it is detected in the user input. Note that intent <code>ls</code> is defined in the <code>light_switch.yaml</code> - file that was loaded by <code>NCModelFileAdapter</code> class. + On <code>line 5</code> our class extends <code>NCModelAdapter</code> that allows us to pass + prepared configuration and pipeline into model. </li> <li> - Note the <code>line 7</code> where we use <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCIntentSample.html">@NCIntentSample</a> - annotation to provide samples of the user input that this intent should match. Apart from documentation - purpose these samples will be used when we will be <a href="#testing">testing out model below.</a> + On <code>line 6</code> created model configuration with most default parameters. </li> <li> - <code>Lines 25 and 26</code> map terms from detected intent to the formal method parameters of the - <code>onMatch</code> method. + On <code>line 7</code> created pipeline, based on semantic model definition, + described in <code>lightswitch_model.yaml</code> file. </li> <li> - On the <code>line 38</code> the intent callback simply returns a confirmation message. - </li> - </ul> - </section> - <section id="build_project"> - <h2 class="section-title">Build Project <a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> - <p> - Once we have our model ready let's go to <code>~/LightSwitch</code> directory and run the Maven build: - </p> - <pre class="brush: bash"> - $ cd ~/LightSwitch - $ mvn clean package - </pre> - <p> - At this stage we have our project built and we are ready to start testing. - </p> - </section> - <section id="start_server"> - <h2 class="section-title">Start Server <a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> - <p> - Run the following command to start local REST server, if it hasn't been started already, from the NLPCraft installation directory: - </p> - <nav> - <div class="nav nav-tabs" role="tablist"> - <a class="nav-item nav-link active" data-toggle="tab" href="#nav-srv-cmd" role="tab">Command</a> - <a class="nav-item nav-link" data-toggle="tab" href="#nav-srv-out" role="tab">Output <i class="fa fa-desktop output"></i></a> - </div> - </nav> - <div class="tab-content"> - <div class="tab-pane fade show active" id="nav-srv-cmd" role="tabpanel"> - <pre class="brush: bash"> - $ bin/nlpcraft.sh start-server - </pre> - </div> - <div class="tab-pane fade show" id="nav-srv-out" role="tabpanel"> - <p></p> - <p> - <img class="img-fluid" alt="" src="/images/server-fig1.png"> - </p> - </div> - </div> - <p> - <b>NOTES:</b> - </p> - <ul> - <li> - <i style="color: #F39C12" class="fa fa-exclamation-triangle"></i> REST server is a "fire-and-forget" component that you generally need to start it only once - for this and other examples. + <code>Lines 10 and 11</code> annotates intents <code>ls</code> and its callback method <code>onMatch</code>. + Intent <code>ls</code> requires one action (a token belonging to the group act) and optional list of light locations + (zero or more tokens with ID ls:loc) - by default we assume the entire house as a default location. </li> <li> - Run <code class="script">bin/nlpcraft.sh help --cmd=start-server</code> to get a full help on this command. + <code>Lines 14 and 15</code> map terms from detected intent to the formal method parameters of the + <code>onMatch</code> method. </li> <li> - <a href="/tools/script.html">NLPCraft CLI</a> is available as <code>nlpcraft.sh</code> for - <i class="fab fa-fw fa-linux"></i> and <code>nlpcraft.cmd</code> - for <i class="fab fa-fw fa-windows"></i>. + On the <code>line 22</code> the intent callback simply returns a confirmation message. </li> </ul> </section> + <section id="testing"> <h2 class="section-title">Testing <a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> <p> - Remember the <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCIntentSample.html">@NCIntentSample</a> - annotation we have used in our model code next to intent definition? - </p> - <p> - Part of the <a href="/tools/test_framework.html">test framework</a>, the auto-validator class <a - target="javadoc" - href="/apis/latest/org/apache/nlpcraft/model/tools/test/NCTestAutoModelValidator.html">NCTestAutoModelValidator</a> takes one or more model IDs - (or class names) and performs validation. Validation consists of starting an <a href="/tools/embedded_probe.html">embedded probe</a> with a given model, - scanning for <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCIntentSample.html">@NCIntentSample</a> and - <a target="javadoc" href="/apis/latest/org/apache/nlpcraft/model/NCIntentSampleRef.html">@NCIntentSampleRef</a> annotations - and their corresponding callback methods, submitting each sample input - sentences from these annotations 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. - </p> - <p> - As always, you can launch model auto-validator as any other Java class but we'll use NLPCraft CLI - to do it more conveniently: - </p> - <pre class="brush: bash"> - $ bin/nlpcraft.sh test-model --cp=~/LightSwitch/target/classes --mdls=demo.LightSwitch - </pre> - <p> - <b>NOTES:</b> - </p> - <ul> - <li> - Run <code class="script">bin/nlpcraft.sh help --cmd=test-model</code> to get a full help on this command. - </li> - <li> - Note that you can use <code>retest-model</code> command in REPL mode to re-run the last model test - avoiding the retyping of all required parameters. - </li> - <li> - <a href="/tools/script.html">NLPCraft CLI</a> is available as <code>nlpcraft.sh</code> for - <i class="fab fa-fw fa-linux"></i> and <code>nlpcraft.cmd</code> - for <i class="fab fa-fw fa-windows"></i>. - </li> - </ul> - <p> - Look at the output of this command and you will see the test results for all our sample utterances: - </p> - <p> - <img style="max-width: 928px !important;" class="img-fluid" alt="" src="/images/light-switch-test.png"> - </p> - </section> - <section id="rinse"> - <h2 class="section-title">Rinse <span class="amp">&</span> Repeat <a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> - <p> - Typical development cycle consists of: - </p> - <ul> - <li> - <a href="#model">Modifying the model</a> - </li> - <li> - <a href="#build_project">Re-building the project</a> - </li> - <li> - <a href="#testing">Re-running the test</a> - </li> - </ul> - <p> - All of these operations can be performed from <a href="/tools/script.html">NLPCraft CLI</a> in REPL mode or from any IDE. - </p> - <p> - NOTE: you don't need to restart REST server every time - it only needs to be started once. + Simple test defined in <code>NCModelValidationSpec</code> allows to check that all input test sentences are + processed expected way and fire intent <code>ls</code>. + You can run this test via SBT task <code>ExecuteTests</code> or using IDE. </p> </section> <section> <h2 class="section-title">Done! 👌 <a href="#"><i class="top-link fas fa-fw fa-angle-double-up"></i></a></h2> <p> - You've created light switch data model, started the REST server and tested this model using the built-in test framework. + You've created light switch data model and tested it. </p> </section> </div> @@ -391,10 +230,7 @@ class LightSwitch extends NCModelFileAdapter("light_switch.yaml") { <li><a href="#new_project">New Project</a></li> <li><a href="#model">Data Model</a></li> <li><a href="#code">Model Class</a></li> - <li><a href="#build_project">Build Project</a></li> - <li><a href="#start_server">Start Server</a></li> <li><a href="#testing">Testing</a></li> - <li><a href="#rinse">Rinse <span class="amp">&</span> Repeat</a></li> {% include quick-links.html %} </ul> </div>
