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


The following commit(s) were added to refs/heads/NLPCRAFT-513 by this push:
     new 7c7f528  WIP.
7c7f528 is described below

commit 7c7f528765f646b9791343bd34ff3c5c7a472b76
Author: skhdl <[email protected]>
AuthorDate: Wed Oct 19 13:40:25 2022 +0400

    WIP.
---
 _includes/left-side-menu.html |   7 +
 examples/time.html            | 326 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 333 insertions(+)

diff --git a/_includes/left-side-menu.html b/_includes/left-side-menu.html
index 1c22b51..8b4e1d0 100644
--- a/_includes/left-side-menu.html
+++ b/_includes/left-side-menu.html
@@ -131,6 +131,13 @@
         <a href="/examples/calculator.html">Calculator</a>
         {% endif %}
     </li>
+    <li>
+        {% if page.id == "time" %}
+        <a class="active" href="/examples/time.html">Time</a>
+        {% else %}
+        <a href="/examples/time.html">Time</a>
+        {% endif %}
+    </li>
     <li>
         {% if page.id == "light_switch" %}
         <a class="active" href="/examples/light_switch.html">Light Switch</a>
diff --git a/examples/time.html b/examples/time.html
new file mode 100644
index 0000000..a249c47
--- /dev/null
+++ b/examples/time.html
@@ -0,0 +1,326 @@
+---
+active_crumb: Time <code><sub>ex</sub></code>
+layout: documentation
+id: time
+fa_icon: fa-cube
+---
+
+<!--
+ 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.
+-->
+
+<div class="col-md-8 second-column example">
+    <section id="overview">
+        <h2 class="section-title">Overview <a href="#"><i class="top-link fas 
fa-fw fa-angle-double-up"></i></a></h2>
+        <p>
+            This example provides a very simple implementation for world time 
bot. You can say something like
+            "What time is it now in New York City" or "What's the local time?".
+        </p>
+        <p>
+            <b>Complexity:</b> <span class="complexity-one-star"><i class="fas 
fa-star"></i> <i class="far fa-star"></i> <i class="far 
fa-star"></i></span><br/>
+            <span class="ex-src">Source code: <a target="github" 
href="https://github.com/apache/incubator-nlpcraft/tree/master/nlpcraft-examples/time";>GitHub
 <i class="fab fa-fw fa-github"></i></a><br/></span>
+            <span class="ex-review-all">Review: <a target="github" 
href="https://github.com/apache/incubator-nlpcraft/tree/master/nlpcraft-examples";>All
 Examples at GitHub <i class="fab fa-fw fa-github"></i></a></span>
+        </p>
+    </section>
+    <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 SBT
+            to accomplish this task. Make sure that <code>build.sbt</code> 
file has the following content:
+        </p>
+        <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 Time Example",
+                version := "{{site.latest_version}}"
+              )
+        </pre>
+        <p><b>NOTE: </b>use the latest versions of Scala and ScalaTest.</p>
+        <p>Create the following files so that resulting project structure 
would look like the following:</p>
+        <ul>
+            <li><code>time_model.yaml</code> - YAML configuration file, which 
contains model description.</li>
+            <li><code>cities_timezones.txt</code> - Cities timezones 
database.</li>
+            <li><code>TimeModel.scala</code> - Scala class, model 
implementation.</li>
+            <li><code>CitiesDataProvider.scala</code> - Scala class, helper 
service which loads timezones database.</li>
+            <li><code>GeoManager.scala</code> - Scala class, helper service 
which provides cities timezones information for user request.</li>
+            <li><code>TimeModelSpec.scala</code> - Scala tests class, which 
allows to test your model.</li>
+        </ul>
+        <pre class="brush: plain, highlight: [7, 10, 14]">
+            |  build.sbt
+            +--project
+            |    build.properties
+            \--src
+               +--main
+               |  +--resources
+               |  |    time_model.yaml
+               |  |    cities_timezones.txt
+               |  \--scala
+               |     \--demo
+               |        \--utils
+               |           \--cities
+               |                CitiesDataProvider.scala
+               |           \--keycdn
+               |                GeoManager.scala
+               |          TimeModel.scala
+               \--test
+                  \--scala
+                     \--demo
+                          TimeModelSpec.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>
+        <p>
+            We are going to start with declaring the static part of our model 
using YAML which we will later load using
+            <code>NCModelAdapter</code> in our Scala-based model 
implementation.
+            Open <code>src/main/resources/<b>time.yaml</b></code>
+            file and replace its content with the following YAML:
+        </p>
+        <pre class="brush: js, highlight: [1, 10, 17, 25]">
+            macros:
+              "&lt;OF&gt;": "{of|for|per}"
+              "&lt;CUR&gt;": "{current|present|now|local}"
+              "&lt;TIME&gt;": "{time &lt;OF&gt; day|day 
time|date|time|moment|datetime|hour|o'clock|clock|date time|date and time|time 
and date}"
+            elements:
+              - id: "x:time"
+                description: "Date and/or time token indicator."
+                synonyms:
+                  - "{&lt;CUR&gt;|_} &lt;TIME&gt;"
+                  - "what &lt;TIME&gt; {is it now|now|is it|_}"
+        </pre>
+        <p>There are number of important points here:</p>
+        <ul>
+            <li>
+                <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>
+                On <code>line 6</code> defined <code>x:time</code> model 
elements, which
+                will be used in our intent, defined in <code>TimeModel</code> 
class. Note that these model
+                elements are defined mostly through macros we have defined 
above.
+            </li>
+        </ul>
+        <div class="bq info">
+            <p><b>YAML vs. API</b></p>
+            <p>
+                As usual, this YAML-based static model definition is 
convenient but totally optional. All elements definitions
+                can be provided programmatically inside Scala model 
<code>TimeModel</code> class as well.
+            </p>
+        </div>
+    </section>
+    <section id="code">
+        <h2 class="section-title">Model Class <a href="#"><i class="top-link 
fas fa-fw fa-angle-double-up"></i></a></h2>
+        <p>
+            Open <code>src/main/scala/demo/<b>TimeModel.scala</b></code> file 
and replace its content with the following code:
+        </p>
+        <pre class="brush: scala, highlight: [16, 17, 18, 19, 20, 21, 56, 57, 
70, 71]">
+            package demo
+
+            import com.fasterxml.jackson.core.JsonProcessingException
+            import com.fasterxml.jackson.databind.ObjectMapper
+            import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
+            import org.apache.nlpcraft.*
+            import org.apache.nlpcraft.annotations.*
+            import demo.utils.cities.*
+            import demo.utils.keycdn.GeoManager
+            import org.apache.nlpcraft.internal.util.NCResourceReader
+            import org.apache.nlpcraft.nlp.parsers.NCOpenNLPEntityParser
+            import java.time.format.DateTimeFormatter
+            import java.time.format.FormatStyle.MEDIUM
+            import java.time.*
+
+            @NCIntent("fragment=city term(city)~{# == 'opennlp:location'}")
+            @NCIntent("intent=intent2 term~{# == 'x:time'} fragment(city)")
+            @NCIntent("intent=intent1 term={# == 'x:time'}")
+            class TimeModel extends NCModelAdapter(
+                NCModelConfig("nlpcraft.time.ex", "Time Example Model", "1.0"),
+                new NCPipelineBuilder().
+                    withSemantic("en", "time_model.yaml").
+                    withEntityParser(NCOpenNLPEntityParser(
+                        
NCResourceReader.getPath("opennlp/en-ner-location.bin"))
+                    ).
+                    build
+            ):
+                private val FMT: DateTimeFormatter = 
DateTimeFormatter.ofLocalizedDateTime(MEDIUM)
+
+                private val citiesData: Map[City, CityData] = 
CitiesDataProvider.get
+
+                private def mkResult(
+                    city: String, cntry: String, tmz: String, lat: Double, 
lon: Double
+                ): NCResult =
+                    val m =
+                        Map(
+                            "city" -> capitalize(city),
+                            "country" -> capitalize(cntry),
+                            "timezone" -> tmz,
+                            "lat" -> lat,
+                            "lon" -> lon,
+                            "localTime" -> 
ZonedDateTime.now(ZoneId.of(tmz)).format(FMT)
+                        )
+
+                    try
+                        NCResult(new ObjectMapper(new 
YAMLFactory).writeValueAsString(m))
+                    catch
+                        case e: JsonProcessingException =>
+                            throw new RuntimeException("YAML conversion 
error.", e)
+
+                private def capitalize(s: String): String =
+                    if s == null || s.isEmpty
+                        then s
+                        else s"${s.substring(0, 
1).toUpperCase}${s.substring(1, s.length)}"
+
+                @NCIntentRef("intent2")
+                private def onRemoteMatch(
+                    ctx: NCContext, im: NCIntentMatch, @NCIntentTerm("city") 
cityEnt: NCEntity
+                ): NCResult =
+                    val cityName: String = cityEnt.mkText
+
+                    val (city, data) =
+                        citiesData.find(_._1.name.equalsIgnoreCase(cityName)).
+                        getOrElse(
+                            throw new NCRejection(String.format("No timezone 
mapping for %s.", cityName))
+                        )
+
+                    mkResult(city.name, city.country, data.timezone, 
data.latitude, data.longitude)
+
+                @NCIntentRef("intent1")
+                private def onLocalMatch(ctx: NCContext, im: NCIntentMatch): 
NCResult =
+                    val geo = 
GeoManager.get(ctx.getRequest).getOrElse(GeoManager.getSiliconValley)
+
+                    mkResult(geo.city, geo.country_name, geo.timezone, 
geo.latitude, geo.longitude)
+        </pre>
+        <p>
+            There are two intents, for local and remote location time. Result 
is represented as JSON value.
+            Let's review this implementation step by step:
+        </p>
+        <ul>
+            <li>
+                On <code>line 19</code> our class extends 
<code>NCModelAdapter</code> that allows us to pass
+                prepared configuration and pipeline into model.
+            </li>
+            <li>
+                On <code>line 16</code> created <code>IDL fragment</code>, 
which is used in <code>intent2</code> definition below.
+            </li>
+            <li>
+                On <code>lines 17 and 18</code> annotates two intents 
definitions <code>intent1</code> and <code>intent2</code> ,
+                callbacks below have references on them by their identifiers.
+            </li>
+            <li>
+                On <code>line 20</code> created model configuration with most 
default parameters.
+            </li>
+            <li>
+                On <code>line 21</code> created pipeline, based on built 
components.
+                <ul>
+                    <li>This pipeline is based on built EN semantic entity 
enrichers, configured with <code>time_model.yaml</code>.</li>
+                    <li>Also there is used entity parser 
<code>NCOpenNLPEntityParser</code>,
+                        configured with 
<code>opennlp/en-ner-location.bin</code> for detection GEO locations.
+                    </li>
+                </ul>
+                Look at documentations of these built components for more 
details.
+            </li>
+            <li>
+                <code>Lines 56 and 57</code> annotates intents 
<code>intent2</code> and its callback method <code>onRemoteMatch</code>.
+                This intent requires one mandatory entity - city, which is 
used for getting time for its timezone.
+            </li>
+            <li>
+                <code>Lines 70 and 71</code> annotates intents 
<code>intent1</code> and its callback method <code>onLocalMatch</code>.
+                This intent is triggered by default and tries to detect 
timezone by request data  and return time for this timezone.
+                Otherwise, it returns Silicon Valley current time.
+            </li>
+        </ul>
+
+        <p>
+            Implementations of helper classes <code>GeoManager</code> and 
<code>CitiesDataProvider</code> are not related to given example.
+            Just copy these classes and <code>cities_timezones.txt</code> from 
project source code into your demo project.
+        </p>
+    </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>
+            The test defined in <code>TimeModelSpec</code> allows to check 
that all input test sentences are
+            processed correctly and trigger the expected intents 
<code>intent2</code> and <code>intent1</code>:
+        </p>
+        <pre class="brush: scala, highlight: [9, 11]">
+            package demo
+
+            import org.apache.nlpcraft.*
+            import org.scalatest.funsuite.AnyFunSuite
+            import scala.util.Using
+
+            class TimeModelSpec extends AnyFunSuite:
+                test("test") {
+                    Using.resource(new NCModelClient(new TimeModel())) { 
client =>
+                        def check(txt: String, intentId: String): Unit =
+                            require(client.debugAsk(txt, "userId", 
true).getIntentId == intentId)
+
+                        check("What time is it now in New York City?", 
"intent2")
+                        check("What's the current time in Moscow?", "intent2")
+                        check("Show me time of the day in London.", "intent2")
+                        check("Can you please give me the Tokyo's current date 
and time.", "intent2")
+
+                        check("What's the local time?", "intent1")
+                    }
+                }
+        </pre>
+        <ul>
+            <li>
+                On <code>line 9</code> the client for our model is created.
+            </li>
+            <li>
+                On <code>line 11</code> a special method <code>debugAsk</code> 
is called.
+                It allows to check the winning intent and its callback 
parameters without actually
+                calling the intent.
+            </li>
+            <li>
+                <code>Lines 13-18</code> define all the test input sentences 
that should all
+                trigger <code>ls</code> intent.
+            </li>
+        </ul>
+        <p>
+            You can run this test via SBT task <code>executeTests</code> or 
using IDE.
+        </p>
+        <pre class="brush: scala, highlight: []">
+            PS C:\apache\incubator-nlpcraft-examples\time> sbt executeTests
+        </pre>
+    </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 time data model and tested it.
+        </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="#model">Data Model</a></li>
+        <li><a href="#code">Model Class</a></li>
+        <li><a href="#testing">Testing</a></li>
+        {% include quick-links.html %}
+    </ul>
+</div>
+
+
+
+
+
+

Reply via email to