This is an automated email from the ASF dual-hosted git repository.

sergeykamov pushed a commit to branch NLPCRAFT-491
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git


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

commit c50ad6bfc522ed8bc94d8dcc749335488fe36228
Author: Sergey Kamov <skhdlem...@gmail.com>
AuthorDate: Wed Apr 6 15:11:16 2022 +0300

    WIP.
---
 .../org/apache/nlpcraft/examples/order/Order.scala |  91 ++++--
 .../nlpcraft/examples/order/OrderModel.scala       | 358 ++++++++++++---------
 .../order/components/StanfordPipeline.scala        |  49 +++
 .../order/src/main/resources/order_model.yaml      |   3 +-
 .../examples/order/cli/OrderModelClientCli.scala   |   6 +-
 5 files changed, 323 insertions(+), 184 deletions(-)

diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala
 
b/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala
index 5b14b106..395cc20a 100644
--- 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala
+++ 
b/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala
@@ -19,43 +19,86 @@ package org.apache.nlpcraft.examples.order
 
 import scala.collection.mutable
 
-case class Pizza(name: String, var size: Option[String], qty: Option[Int])
-case class Drink(name: String, qty: Option[Int])
-
+case class Pizza(name: String, var size: Option[String], var qty: Option[Int]):
+    require(name != null && name.nonEmpty)
+case class Drink(name: String, var qty: Option[Int]):
+    require(name != null && name.nonEmpty)
 enum State:
-    case ORDER_EMPTY, ORDER_INVALID, ORDER_VALID, ASK_CONTINUE, ASK_CONFIRM, 
ASK_CANCEL
+    case NO_DIALOG, DIALOG_IS_READY, DIALOG_SHOULD_CANCEL, DIALOG_SPECIFY, 
DIALOG_CONFIRM
 
 import org.apache.nlpcraft.examples.order.State.*
 
 class Order:
-    private var state =  ORDER_EMPTY
+    private var state = NO_DIALOG
     private val pizzas = mutable.LinkedHashMap.empty[String, Pizza]
     private val drinks = mutable.LinkedHashMap.empty[String, Drink]
 
-    private def findPizzaNoSize: Option[Pizza] = 
pizzas.values.find(_.size.isEmpty)
+    /**
+      *
+      * @return
+      */
+    def isEmpty: Boolean = pizzas.isEmpty && drinks.isEmpty
 
-    def addPizza(p: Pizza): Unit =
-        pizzas += p.name -> p
-        state = if findPizzaNoSize.nonEmpty then ORDER_INVALID else ORDER_VALID
-    def addDrink(d: Drink): Unit =
-        if state == ORDER_EMPTY then state = ORDER_VALID
-            drinks += d.name -> d
+    /**
+      *
+      * @return
+      */
+    def isValid: Boolean = !isEmpty && findPizzaNoSize.isEmpty
 
-    def getState: State = state
-    def setState(state: State) = this.state = state
+    /**
+      *
+      * @param ps
+      * @param ds
+      */
+    def add(ps: Seq[Pizza], ds: Seq[Drink]): Unit =
+        for (p <- ps)
+            pizzas.get(p.name) match
+                case Some(ex) =>
+                    if p.size.nonEmpty then ex.size = p.size
+                    if p.qty.nonEmpty then ex.qty = p.qty
+                case None => pizzas += p.name -> p
+
+        for (d <- ds)
+            drinks.get(d.name) match
+                case Some(ex) => if d.qty.nonEmpty then ex.qty = d.qty
+                case None => drinks += d.name -> d
 
+    /**
+      *
+      * @return
+      */
     def getPizzas: Map[String, Pizza] = pizzas.toMap
+
+    /**
+      *
+      * @return
+      */
     def getDrinks: Map[String, Drink] = drinks.toMap
 
-    def getPizzaNoSize: Pizza =
-        require(state == ORDER_INVALID)
-        findPizzaNoSize.get
-    def setPizzaNoSize(size: String): Unit =
-        require(state == ORDER_INVALID)
-        require(size != null)
-        findPizzaNoSize.get.size = Option(size)
-    def clear(): Unit =
-        pizzas.clear()
-        drinks.clear()
+    /**
+      *
+      * @return
+      */
+    def findPizzaNoSize: Option[Pizza] = pizzas.values.find(_.size.isEmpty)
 
+    /**
+      *
+       * @param size
+      */
+    def setPizzaNoSize(size: String): Boolean =
+        findPizzaNoSize match
+            case Some(p) =>
+                p.size = Option(size)
+                true
+            case None => false
+    /**
+      *
+      * @return
+      */
+    def getState: State = state
 
+    /**
+      *
+      * @param state
+      */
+    def setState(state: State): Unit = this.state = state
\ No newline at end of file
diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderModel.scala
 
b/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderModel.scala
index 47ab58e6..9f4ba3bf 100644
--- 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderModel.scala
+++ 
b/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderModel.scala
@@ -20,198 +20,240 @@ package org.apache.nlpcraft.examples.order
 import com.typesafe.scalalogging.LazyLogging
 import edu.stanford.nlp.pipeline.StanfordCoreNLP
 import opennlp.tools.stemmer.PorterStemmer
-import org.antlr.v4.runtime.misc.Predicate
 import org.apache.nlpcraft.*
+import org.apache.nlpcraft.NCResultType.*
+import org.apache.nlpcraft.examples.order.State.*
+import org.apache.nlpcraft.examples.order.components.*
 import org.apache.nlpcraft.internal.util.NCResourceReader
 import org.apache.nlpcraft.nlp.*
 import org.apache.nlpcraft.nlp.entity.parser.*
-
-import scala.collection.mutable
-import org.apache.nlpcraft.NCResultType.*
-import org.apache.nlpcraft.examples.order.components.*
 import org.apache.nlpcraft.nlp.entity.parser.semantic.*
 import org.apache.nlpcraft.nlp.entity.parser.stanford.*
 import org.apache.nlpcraft.nlp.token.parser.stanford.*
-import org.apache.nlpcraft.examples.order.State.*
 
-import scala.jdk.CollectionConverters.*
 import java.util.Properties
-import scala.jdk.OptionConverters._
-
-object StanfordEn:
-    val PIPELINE: NCPipeline =
-        val stanford =
-            val props = new Properties()
-            props.setProperty("annotators", "tokenize, ssplit, pos, lemma, 
ner")
-            new StanfordCoreNLP(props)
-        val tokParser = new NCStanfordNLPTokenParser(stanford)
-        val stemmer = new NCSemanticStemmer():
-            private val ps = new PorterStemmer
-            override def stem(txt: String): String = ps.synchronized { 
ps.stem(txt) }
-
-        new NCPipelineBuilder().
-            withTokenParser(tokParser).
-            withEntityParser(new NCStanfordNLPEntityParser(stanford, 
"number")).
-            withEntityParser(new NCSemanticEntityParser(stemmer, tokParser, 
"order_model.yaml")).
-            withEntityMappers(Seq(new PizzaSizeExtender, new PizzaQtyExtender, 
new DrinkQtyExtender).asJava).
-            withEntityValidator(new OrderValidator).
-            build()
+import scala.collection.mutable
+import scala.jdk.CollectionConverters.*
+import scala.jdk.OptionConverters.*
 
+/**
+  *
+  */
 object OrderModel extends LazyLogging:
-    private def norm(s: String) = s.trim.replaceAll("(?m)^[ \t]*\r?\n", "")
-    private def withComma[T](iter: Iterable[T]): String = iter.mkString(", ")
-    private def seq2Str[T](name: String, seq: Iterable[T]): String = if 
seq.nonEmpty then s"$name: ${withComma(seq)}." else ""
-
+    private val DFLT_QTY = 1
+    private def toStr[T](name: String, seq: Iterable[T]): String = if 
seq.nonEmpty then s"$name: ${seq.mkString(", ")}." else ""
     private def extractPizzaSize(e: NCEntity): String = 
e.get[String]("ord:pizza:size:value")
-    private def extractQty(e: NCEntity, qty: String): Option[Int] = 
Option.when(e.contains(qty))(e.get[String](qty).toInt)
+    private def extractQty(e: NCEntity, qty: String): Option[Int] = 
Option.when(e.contains(qty))(e.get[String](qty).toDouble.toInt)
     private def extractPizza(e: NCEntity): Pizza =
         Pizza(e.get[String]("ord:pizza:value"), 
e.getOpt[String]("ord:pizza:size").toScala, extractQty(e, "ord:pizza:qty"))
-    private def extractDrink(e: NCEntity): Drink = 
Drink(e.get[String]("ord:drink:value"), extractQty(e, "ord:drink:qty"))
+    private def extractDrink(e: NCEntity): Drink =
+        Drink(e.get[String]("ord:drink:value"), extractQty(e, "ord:drink:qty"))
 
-    private def getContent(o: Order): String =
-        s"""
-       |${seq2Str("Pizza", o.getPizzas.values.map(p => s"${p.name} 
${p.size.getOrElse("undefined")} ${p.qty.getOrElse(1)}"))}
-       |${seq2Str("Drinks", o.getDrinks.values.map(p => s"${p.name} 
${p.qty.getOrElse(1)}"))}
-        """.stripMargin
+    private def getDescription(o: Order): String =
+        if !o.isEmpty then
+            val s1 = toStr("Pizza", o.getPizzas.values.map(p => s"${p.name} 
size: ${p.size.getOrElse("undefined")} count: ${p.qty.getOrElse(DFLT_QTY)}"))
+            val s2 = toStr("Drinks", o.getDrinks.values.map(p => s"${p.name} 
count: ${p.qty.getOrElse(DFLT_QTY)}"))
 
+            if s2.isEmpty then s1
+            else if s1.isEmpty then s2 else s"$s1 $s2"
+        else "Nothing ordered."
 
-    private def toString(o: Order): String =
-        norm(
-            s"""
-           |Order
-           |${getContent(o)}
-            """.stripMargin
-        )
 
 import org.apache.nlpcraft.examples.order.OrderModel.*
+
 /**
   *
   */
-class OrderModel extends NCModelAdapter (
-    new NCModelConfig("nlpcraft.order.ex", "Order Example Model", "1.0"), 
StanfordEn.PIPELINE
-) with LazyLogging:
-    private val ords = mutable.HashMap.empty[String, Order]
-
-    private def getOrder(im: NCIntentMatch): Order = 
ords.getOrElseUpdate(im.getContext.getRequest.getUserId, new Order)
-    private def getLastIntentId(im: NCIntentMatch): Option[String] =
-        im.getContext.getConversation.getDialogFlow.asScala.lastOption match
-            case Some(e) => Some(e.getIntentMatch.getIntentId)
-            case None => None
-
-    private def mkOrderFinishDialog(o: Order): NCResult =
-//        if o.isValid then
-//            o.wait4Approve(true)
-//            new NCResult("Is order ready?", ASK_DIALOG)
-//        else NCResult(s"What is size size (large, medium or small) for: 
${o.getPizzaNoSize.name}", ASK_DIALOG)
-        null
-
-    private def mkOrderContinueDialog(o: Order): NCResult =
-//        require(o.inProgress)
-//        NCResult("OK. Please continue", ASK_DIALOG)
-        null
-
-    private def mkOrderConfirmDialog(o: Order): NCResult =
+class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex", "Order Example Model", "1.0"), 
StanfordPipeline.PIPELINE) with LazyLogging:
+    private val userOrders = mutable.HashMap.empty[String, Order]
+
+    private def withLog(im: NCIntentMatch, body: Order => NCResult): NCResult =
+        val o = userOrders.getOrElseUpdate(im.getContext.getRequest.getUserId, 
new Order)
+        def getState: String = o.getState.toString.toLowerCase
+        val state = getState
+
+        try body.apply(o)
+        finally println(s"'${im.getIntentId}' called ($state -> $getState)")
+
+    private def askIsReady(o: Order): NCResult =
+        val res = NCResult(s"Is order ready?", ASK_DIALOG)
+        o.setState(DIALOG_IS_READY)
+        res
+
+    private def askSpecify(o: Order) =
+        require(!o.isValid)
+        val res = o.findPizzaNoSize match
+            case Some(p) => NCResult(s"Choose size (large, medium or small) 
for: '${p.name}'", ASK_DIALOG)
+            case None =>
+                require(o.isEmpty)
+                NCResult(s"Please order something. Ask `menu` to look what you 
can order.", ASK_DIALOG)
+        o.setState(DIALOG_SPECIFY)
+        res
+
+    private def askShouldStop(o: Order) =
+        val res = NCResult(s"Should current order be canceled?", ASK_DIALOG)
+        o.setState(DIALOG_SHOULD_CANCEL)
+        res
+
+    private def doShowMenu() =
         NCResult(
-            norm(
-                s"""
-                   |Let me specify your order.
-                   |${getContent(o)}
-                   |Is it correct?
-                """.stripMargin
-            ),
-            ASK_DIALOG
+            "There are accessible for order: margherita, carbonara and 
marinara. Sizes: large, medium or small. " +
+            "Also there are tea, green tea, coffee and cola.",
+            ASK_RESULT
         )
 
-    private def mkClearResult(im: NCIntentMatch, o: Order): NCResult =
-        o.clear()
+    private def doShowStatus(o: Order, newState: State) =
+        val res = NCResult(s"Current order state: ${getDescription(o)}", 
ASK_RESULT)
+        o.setState(newState)
+        res
+
+    private def askConfirm(o: Order): NCResult =
+        require(o.isValid)
+        val res = NCResult(s"Let's specify your order. ${getDescription(o)} Is 
it correct?", ASK_DIALOG)
+        o.setState(DIALOG_CONFIRM)
+        res
+
+    private def clear(im: NCIntentMatch, o: Order): Unit =
+        userOrders.remove(im.getContext.getRequest.getUserId)
         val conv = im.getContext.getConversation
         conv.clearStm(_ => true)
         conv.clearDialog(_ => true)
-        NCResult("Order canceled. We are ready for new orders.", ASK_RESULT)
-
-    private def mkExecuteResult(o: Order): NCResult =
-        println(s"EXECUTED:")
-        println(OrderModel.toString(o))
-        o.clear()
-        NCResult("Congratulations. Your order executed. You can start make new 
orders.", ASK_RESULT)
 
+    private def doExecute(im: NCIntentMatch, o: Order): NCResult =
+        require(o.isValid)
+        val res = NCResult(s"Executed: ${getDescription(o)}", ASK_RESULT)
+        clear(im, o)
+        res
+
+    private def doStop(im: NCIntentMatch, o: Order): NCResult =
+        val res =
+            if !o.isEmpty then NCResult(s"Everything cancelled. Ask `menu` to 
look what you can order.", ASK_RESULT)
+            else NCResult(s"Nothing to cancel. Ask `menu` to look what you can 
order.", ASK_RESULT)
+        clear(im, o)
+        res
+
+    private def doContinue(o: Order): NCResult =
+        val res = NCResult(s"OK, please continue.", ASK_RESULT)
+        o.setState(NO_DIALOG)
+        res
+
+    private def askConfirmOrAskSpecify(o: Order): NCResult = if o.isValid then 
askConfirm(o) else askSpecify(o)
+    private def askIsReadyOrAskSpecify(o: Order): NCResult = if o.isValid then 
askIsReady(o) else askSpecify(o)
+    private def doExecuteOrAskSpecify(im: NCIntentMatch, o: Order): NCResult = 
if o.isValid then doExecute(im, o) else askSpecify(o)
+    private def askStopOrDoStop(im: NCIntentMatch, o: Order): NCResult = if 
o.isValid then askShouldStop(o) else doStop(im, o)
+
+    /**
+      *
+      * @param im
+      * @return
+      */
     @NCIntent("intent=yes term(yes)={# == 'ord:yes'}")
-    def onYes(im: NCIntentMatch, @NCIntentTerm("yes") yes: NCEntity): NCResult 
=
-        val o = getOrder(im)
-        val lastIntentId = getLastIntentId(im).orNull
-
-//        if o.isWait4Approve then
-//            o.wait4Approve(false)
-//            mkOrderConfirmDialog(o)
-//        else if lastIntentId == "stop" then mkOrderContinueDialog(o)
-//        else mkOrderFinishDialog(o)
-        null
-
+    def onYes(im: NCIntentMatch): NCResult = withLog(
+        im,
+        (o: Order) => o.getState match
+            case DIALOG_CONFIRM =>
+                require(o.isValid);
+                doExecute(im, o)
+            case DIALOG_SHOULD_CANCEL => doStop(im, o)
+            case DIALOG_IS_READY => askConfirmOrAskSpecify(o)
+            case DIALOG_SPECIFY | NO_DIALOG => throw new 
NCRejection("Unexpected request.")
+    )
+
+    /**
+      *
+      * @param im
+      * @return
+      */
     @NCIntent("intent=no term(no)={# == 'ord:no'}")
-    def onNo(im: NCIntentMatch, @NCIntentTerm("no") no: NCEntity): NCResult =
-        val o = getOrder(im)
-        val lastIntentId = getLastIntentId(im).orNull
-
-//        if o.isWait4Approve then
-//            o.wait4Approve(false)
-//            mkClearResult(im, o)
-//        else if lastIntentId == "stop" then mkOrderContinueDialog(o)
-//        else mkOrderFinishDialog(o)
-        null
-
+    def onNo(im: NCIntentMatch): NCResult = withLog(
+        im,
+        (o: Order) => o.getState match
+            case DIALOG_CONFIRM | DIALOG_IS_READY => doContinue(o)
+            case DIALOG_SHOULD_CANCEL => askConfirmOrAskSpecify(o)
+            case DIALOG_SPECIFY | NO_DIALOG => throw new 
NCRejection("Unexpected request.")
+        )
+    /**
+      *
+      * @param im
+      * @return
+      */
     @NCIntent("intent=stop term(stop)={# == 'ord:stop'}")
-    def onStop(im: NCIntentMatch, @NCIntentTerm("stop") stop: NCEntity): 
NCResult =
-        val o = getOrder(im)
-
-        o.getState match
-            case ORDER_VALID | ORDER_INVALID =>
-                o.setState(ASK_CANCEL)
-                NCResult("Are you sure that you want to cancel current 
order?", ASK_DIALOG)
-            case _ => NCResult("Nothing to cancel.", ASK_RESULT)
-
+    def onStop(im: NCIntentMatch): NCResult = withLog(
+        im,
+        // It doesn't depend on order validity and dialog state.
+        (o: Order) => askStopOrDoStop(im, o)
+    )
+
+    /**
+      *
+      * @param im
+      * @param ps
+      * @param ds
+      * @return
+      */
     @NCIntent("intent=order term(ps)={# == 'ord:pizza'}* term(ds)={# == 
'ord:drink'}*")
-    def onOrder(im: NCIntentMatch, @NCIntentTerm("ps") ps: List[NCEntity], 
@NCIntentTerm("ds") ds: List[NCEntity]): NCResult =
-        if ps.isEmpty && ds.isEmpty then throw new NCRejection("Please order 
some pizza or drinks")
-
-        val o = getOrder(im)
-
-        for (p <- ps) o.addPizza(extractPizza(p))
-        for (d <- ds) o.addDrink(extractDrink(d))
-
-        mkOrderFinishDialog(o)
-
+    def onOrder(im: NCIntentMatch, @NCIntentTerm("ps") ps: List[NCEntity], 
@NCIntentTerm("ds") ds: List[NCEntity]): NCResult = withLog(
+        im,
+        (o: Order) =>
+            if ps.isEmpty && ds.isEmpty then throw new NCRejection("Please 
order some pizza or drinks");
+            o.add(ps.map(extractPizza), ds.map(extractDrink)); // It doesn't 
depend on order validity and dialog state.
+            askIsReadyOrAskSpecify(o)
+        )
+    /**
+      *
+      * @param im
+      * @param size
+      * @return
+      */
     @NCIntent("intent=orderPizzaSize term(size)={# == 'ord:pizza:size'}")
-    def onOrderPizzaSize(im: NCIntentMatch, @NCIntentTerm("size") size: 
NCEntity): NCResult =
-        val o = getOrder(im)
-
-        o.getState match
-            case ORDER_INVALID => o.setPizzaNoSize(extractPizzaSize(size))
-            case _ => NCRejection("") // TODO
-
-        mkOrderFinishDialog(o)
-
+    def onOrderPizzaSize(im: NCIntentMatch, @NCIntentTerm("size") size: 
NCEntity): NCResult = withLog(
+        im,
+        (o: Order) => o.getState match
+            case DIALOG_SPECIFY =>
+                if o.setPizzaNoSize(extractPizzaSize(size)) then
+                    o.setState(NO_DIALOG);
+                    askIsReadyOrAskSpecify(o)
+                else
+                    throw new NCRejection("Unexpected request.")
+            case DIALOG_CONFIRM | NO_DIALOG | DIALOG_IS_READY | 
DIALOG_SHOULD_CANCEL => throw new NCRejection("Unexpected request.")
+        )
+    /**
+      *
+      * @param im
+      * @return
+      */
     @NCIntent("intent=status term(status)={# == 'ord:status'}")
-    def onStatus(im: NCIntentMatch, @NCIntentTerm("status") s: NCEntity): 
NCResult =
-        val o = getOrder(im)
-
-        o.getState match
-            case ORDER_VALID | ORDER_INVALID => 
NCResult(OrderModel.toString(o), ASK_RESULT)
-            case _ => NCResult("Nothing ordered.", ASK_RESULT)
-
+    def onStatus(im: NCIntentMatch): NCResult = withLog(
+        im,
+        (o: Order) => o.getState match
+            case DIALOG_CONFIRM =>
+                require(o.isValid);
+                askConfirm(o) // Ignore `status`, confirm again.
+            //case DIALOG_SPECIFY => askSpecify(o) // Ignore `status`, specify 
again.
+            case DIALOG_SHOULD_CANCEL => doShowStatus(o, NO_DIALOG) // Changes 
state.
+            case NO_DIALOG | DIALOG_IS_READY | DIALOG_SPECIFY => 
doShowStatus(o, o.getState)  // Keeps same state.
+        )
+    /**
+      *
+      * @param im
+      * @return
+      */
     @NCIntent("intent=finish term(finish)={# == 'ord:finish'}")
-    def onFinish(im: NCIntentMatch, @NCIntentTerm("finish") f: NCEntity): 
NCResult =
-        val o = getOrder(im)
-
-        o.getState match
-            case ORDER_VALID | ASK_CONTINUE =>
-                o.setState(ASK_CONFIRM)
-                mkOrderConfirmDialog(o)
-            case _ => NCResult("Nothing to finish.", ASK_RESULT)
-
+    def onFinish(im: NCIntentMatch): NCResult = withLog(
+        im,
+        (o: Order) => o.getState match
+            case DIALOG_CONFIRM => doExecuteOrAskSpecify(im, o) // Like YES  
if valid.
+            case DIALOG_SPECIFY => askSpecify(o) // Ignore `finish`, specify 
again.
+            case NO_DIALOG | DIALOG_IS_READY | DIALOG_SHOULD_CANCEL => 
askConfirmOrAskSpecify(o)
+        )
+    /**
+      *
+      * @param im
+      * @return
+      */
     @NCIntent("intent=menu term(menu)={# == 'ord:menu'}")
-    def onMenu(im: NCIntentMatch, @NCIntentTerm("menu") m: NCEntity): NCResult 
=
-        NCResult(
-            "There are margherita, marbonara and marinara. Sizes: large, 
medium or small. " +
-            "Also there are tea, grean tea, coffee and cola.",
-            ASK_RESULT
-        )
\ No newline at end of file
+    def onMenu(im: NCIntentMatch): NCResult = withLog(
+        im,
+        // It doesn't depend and doesn't influence on order validity and 
dialog state.
+        _ => doShowMenu()
+    )
\ No newline at end of file
diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/StanfordPipeline.scala
 
b/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/StanfordPipeline.scala
new file mode 100644
index 00000000..723db572
--- /dev/null
+++ 
b/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/StanfordPipeline.scala
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package org.apache.nlpcraft.examples.order.components
+
+import edu.stanford.nlp.pipeline.StanfordCoreNLP
+import opennlp.tools.stemmer.PorterStemmer
+import org.apache.nlpcraft.*
+import org.apache.nlpcraft.nlp.entity.parser.semantic.*
+import org.apache.nlpcraft.nlp.entity.parser.stanford.NCStanfordNLPEntityParser
+import org.apache.nlpcraft.nlp.token.parser.stanford.NCStanfordNLPTokenParser
+import scala.jdk.CollectionConverters.*
+import java.util.Properties
+
+/**
+  *
+  */
+object StanfordPipeline:
+    val PIPELINE: NCPipeline =
+        val stanford =
+            val props = new Properties()
+            props.setProperty("annotators", "tokenize, ssplit, pos, lemma, 
ner")
+            new StanfordCoreNLP(props)
+        val tokParser = new NCStanfordNLPTokenParser(stanford)
+        val stemmer = new NCSemanticStemmer():
+            private val ps = new PorterStemmer
+            override def stem(txt: String): String = ps.synchronized { 
ps.stem(txt) }
+
+        new NCPipelineBuilder().
+            withTokenParser(tokParser).
+            withEntityParser(new NCStanfordNLPEntityParser(stanford, 
"number")).
+            withEntityParser(new NCSemanticEntityParser(stemmer, tokParser, 
"order_model.yaml")).
+            withEntityMappers(Seq(new PizzaSizeExtender, new PizzaQtyExtender, 
new DrinkQtyExtender).asJava).
+            withEntityValidator(new OrderValidator).
+            build()
\ No newline at end of file
diff --git a/nlpcraft-examples/order/src/main/resources/order_model.yaml 
b/nlpcraft-examples/order/src/main/resources/order_model.yaml
index 40b07c30..450d3a0d 100644
--- a/nlpcraft-examples/order/src/main/resources/order_model.yaml
+++ b/nlpcraft-examples/order/src/main/resources/order_model.yaml
@@ -20,7 +20,7 @@ elements:
     description: "Kinds of pizza."
     values:
       "margherita": [ ]
-      "marbonara": [ ]
+      "carbonara": [ ]
       "marinara": [ ]
 
   - id: "ord:pizza:size"
@@ -63,6 +63,7 @@ elements:
   - id: "ord:finish"
     description: "Order finish."
     synonyms:
+      - "order"
       - "{order|I|_} {is|are|have|has|_} {ready|done|finish}"
 
   - id: "ord:menu"
diff --git 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala
 
b/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala
index 01cd4a1e..35c8ae0b 100644
--- 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala
+++ 
b/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala
@@ -65,7 +65,11 @@ object OrderModelClientCli extends LazyLogging :
             print(s">>> ")
 
             try
-                println(ask(scala.io.StdIn.readLine()))
+                var in = scala.io.StdIn.readLine()
+
+                if in != null then
+                    in = in.trim
+                    if in.nonEmpty then println(ask(in))
                 println
             catch
                 case e: NCRejection => println(s"Request rejected: 
${e.getMessage}")

Reply via email to