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 2ceff3f1 WIP.
2ceff3f1 is described below

commit 2ceff3f1b780ebdd9fd22e11858ea29c0e056539
Author: Sergey Kamov <[email protected]>
AuthorDate: Thu Apr 7 14:43:31 2022 +0300

    WIP.
---
 .../examples/order/NCModelValidationSpec.scala     | 30 --------
 nlpcraft-examples/{order => pizzeria}/README.md    |  0
 nlpcraft-examples/{order => pizzeria}/pom.xml      |  2 +-
 .../nlpcraft/examples/order/PizzeriaModel.scala}   | 90 +++++++++++-----------
 .../examples/order/PizzeriaModelPipeline.scala}    | 30 ++------
 .../nlpcraft/examples/order/PizzeriaOrder.scala}   | 66 +++++++++++-----
 .../order/components/ElementExtender.scala}        |  8 +-
 .../order/components/RequestValidator.scala        |  0
 .../src/main/resources/pizzeria_model.yaml}        | 16 ++--
 .../examples/order/PizzeriaModelSpec.scala}        | 36 +++++----
 .../order/cli/PizzeriaModelClientCli.scala}        |  4 +-
 .../examples/order/cli/PizzeriaModelServer.scala}  |  6 +-
 pom.xml                                            |  2 +-
 13 files changed, 139 insertions(+), 151 deletions(-)

diff --git 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/NCModelValidationSpec.scala
 
b/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/NCModelValidationSpec.scala
deleted file mode 100644
index 52100509..00000000
--- 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/NCModelValidationSpec.scala
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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
-
-import org.apache.nlpcraft.*
-import org.junit.jupiter.api.*
-
-import scala.util.Using
-
-/**
-  * JUnit models validation.
-  */
-class NCModelValidationSpec:
-    @Test
-    def test(): Unit = Using.resource(new NCModelClient(new OrderModel())) { 
_.validateSamples() }
\ No newline at end of file
diff --git a/nlpcraft-examples/order/README.md 
b/nlpcraft-examples/pizzeria/README.md
similarity index 100%
rename from nlpcraft-examples/order/README.md
rename to nlpcraft-examples/pizzeria/README.md
diff --git a/nlpcraft-examples/order/pom.xml 
b/nlpcraft-examples/pizzeria/pom.xml
similarity index 97%
rename from nlpcraft-examples/order/pom.xml
rename to nlpcraft-examples/pizzeria/pom.xml
index df729acd..c1c06bab 100644
--- a/nlpcraft-examples/order/pom.xml
+++ b/nlpcraft-examples/pizzeria/pom.xml
@@ -22,7 +22,7 @@
     <modelVersion>4.0.0</modelVersion>
 
     <name>NLPCraft Example Order</name>
-    <artifactId>nlpcraft-example-order</artifactId>
+    <artifactId>nlpcraft-example-pizzeria</artifactId>
 
     <parent>
         <artifactId>nlpcraft-parent</artifactId>
diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderModel.scala
 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaModel.scala
similarity index 70%
rename from 
nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderModel.scala
rename to 
nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaModel.scala
index 58c84685..1f5817f2 100644
--- 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderModel.scala
+++ 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaModel.scala
@@ -18,18 +18,10 @@
 package org.apache.nlpcraft.examples.order
 
 import com.typesafe.scalalogging.LazyLogging
-import edu.stanford.nlp.pipeline.StanfordCoreNLP
-import opennlp.tools.stemmer.PorterStemmer
 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 org.apache.nlpcraft.nlp.entity.parser.semantic.*
-import org.apache.nlpcraft.nlp.entity.parser.stanford.*
-import org.apache.nlpcraft.nlp.token.parser.stanford.*
 
 import java.util.Properties
 import scala.collection.mutable
@@ -39,10 +31,10 @@ import scala.jdk.OptionConverters.*
 /**
   *
   */
-object OrderModel extends LazyLogging:
+object PizzeriaModel extends LazyLogging:
     private val DFLT_QTY = 1
-    private val UNEXPECTED = new NCRejection("Unexpected request in given 
context.")
-    private def toStr[T](name: String, seq: Iterable[T]): String = if 
seq.nonEmpty then s"$name: ${seq.mkString(", ")}." else ""
+    private val UNEXPECTED_REQUEST = new NCRejection("Unexpected request for 
current dialog context.")
+
     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).toDouble.toInt)
     private def extractPizza(e: NCEntity): Pizza =
@@ -50,38 +42,44 @@ object OrderModel extends LazyLogging:
     private def extractDrink(e: NCEntity): Drink =
         Drink(e.get[String]("ord:drink:value"), extractQty(e, "ord:drink:qty"))
 
-    private def getDescription(o: Order): String =
+    private def getDescription(o: PizzeriaOrder): 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)}"))
+            def s(name: String, seq: Iterable[String]): String = if 
seq.nonEmpty then s"$name: ${seq.mkString(", ")}" else ""
+            val s1 = s("Pizza", o.getPizzas.map(p => s"${p.name}, 
'${p.size.getOrElse("undefined size")}' ${p.qty.getOrElse(DFLT_QTY)} p."))
+            val s2 = s("Drinks", o.getDrinks.map(p => s"${p.name} 
${p.qty.getOrElse(DFLT_QTY)} p."))
 
-            if s2.isEmpty then s1
-            else if s1.isEmpty then s2 else s"$s1 $s2"
+            if s2.isEmpty then s1 else if s1.isEmpty then s2 else s"$s1 $s2"
         else "Nothing ordered."
 
 
-import org.apache.nlpcraft.examples.order.OrderModel.*
+import org.apache.nlpcraft.examples.order.PizzeriaModel.*
 
 /**
   *
   */
-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]
+class PizzeriaModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.pizzeria.ex", "Pizzeria Example Model", "1.0"), 
PizzeriaModelPipeline.PIPELINE) with LazyLogging:
+    private def withLog(im: NCIntentMatch, body: PizzeriaOrder => NCResult): 
NCResult =
+        val usrId = im.getContext.getRequest.getUserId
+        val data = im.getContext.getConversation.getData
+
+        var o: PizzeriaOrder = data.get(usrId)
+
+        if o == null then
+            o = new PizzeriaOrder()
+            data.put(usrId, o)
 
-    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 =
+    private def askIsReady(o: PizzeriaOrder): NCResult =
         val res = NCResult(s"Is order ready?", ASK_DIALOG)
         o.setState(DIALOG_IS_READY)
         res
 
-    private def askSpecify(o: Order) =
+    private def askSpecify(o: PizzeriaOrder) =
         require(!o.isValid)
         val res = o.findPizzaNoSize match
             case Some(p) => NCResult(s"Choose size (large, medium or small) 
for: '${p.name}'", ASK_DIALOG)
@@ -91,7 +89,7 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
         o.setState(DIALOG_SPECIFY)
         res
 
-    private def askShouldStop(o: Order) =
+    private def askShouldStop(o: PizzeriaOrder) =
         val res = NCResult(s"Should current order be canceled?", ASK_DIALOG)
         o.setState(DIALOG_SHOULD_CANCEL)
         res
@@ -103,45 +101,45 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
             ASK_RESULT
         )
 
-    private def doShowStatus(o: Order, newState: State) =
+    private def doShowStatus(o: PizzeriaOrder, newState: State) =
         val res = NCResult(s"Current order state: ${getDescription(o)}", 
ASK_RESULT)
         o.setState(newState)
         res
 
-    private def askConfirm(o: Order): NCResult =
+    private def askConfirm(o: PizzeriaOrder): 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)
+    private def clear(im: NCIntentMatch, o: PizzeriaOrder): Unit =
+        
im.getContext.getConversation.getData.remove(im.getContext.getRequest.getUserId)
         val conv = im.getContext.getConversation
         conv.clearStm(_ => true)
         conv.clearDialog(_ => true)
 
-    private def doExecute(im: NCIntentMatch, o: Order): NCResult =
+    private def doExecute(im: NCIntentMatch, o: PizzeriaOrder): 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 =
+    private def doStop(im: NCIntentMatch, o: PizzeriaOrder): 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 =
+    private def doContinue(o: PizzeriaOrder): 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)
+    private def askConfirmOrAskSpecify(o: PizzeriaOrder): NCResult = if 
o.isValid then askConfirm(o) else askSpecify(o)
+    private def askIsReadyOrAskSpecify(o: PizzeriaOrder): NCResult = if 
o.isValid then askIsReady(o) else askSpecify(o)
+    private def doExecuteOrAskSpecify(im: NCIntentMatch, o: PizzeriaOrder): 
NCResult = if o.isValid then doExecute(im, o) else askSpecify(o)
+    private def askStopOrDoStop(im: NCIntentMatch, o: PizzeriaOrder): NCResult 
= if o.isValid then askShouldStop(o) else doStop(im, o)
 
     /**
       *
@@ -151,13 +149,13 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
     @NCIntent("intent=yes term(yes)={# == 'ord:yes'}")
     def onYes(im: NCIntentMatch): NCResult = withLog(
         im,
-        (o: Order) => o.getState match
+        (o: PizzeriaOrder) => 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 UNEXPECTED
+            case DIALOG_SPECIFY | NO_DIALOG => throw UNEXPECTED_REQUEST
     )
 
     /**
@@ -168,10 +166,10 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
     @NCIntent("intent=no term(no)={# == 'ord:no'}")
     def onNo(im: NCIntentMatch): NCResult = withLog(
         im,
-        (o: Order) => o.getState match
+        (o: PizzeriaOrder) => o.getState match
             case DIALOG_CONFIRM | DIALOG_IS_READY => doContinue(o)
             case DIALOG_SHOULD_CANCEL => askConfirmOrAskSpecify(o)
-            case DIALOG_SPECIFY | NO_DIALOG => throw UNEXPECTED
+            case DIALOG_SPECIFY | NO_DIALOG => throw UNEXPECTED_REQUEST
         )
     /**
       *
@@ -182,7 +180,7 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
     def onStop(im: NCIntentMatch): NCResult = withLog(
         im,
         // It doesn't depend on order validity and dialog state.
-        (o: Order) => askStopOrDoStop(im, o)
+        (o: PizzeriaOrder) => askStopOrDoStop(im, o)
     )
 
     /**
@@ -195,7 +193,7 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
     @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 = withLog(
         im,
-        (o: Order) =>
+        (o: PizzeriaOrder) =>
             require(ps.nonEmpty || ds.nonEmpty);
             o.add(ps.map(extractPizza), ds.map(extractDrink)); // It doesn't 
depend on order validity and dialog state.
             askIsReadyOrAskSpecify(o)
@@ -209,13 +207,13 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
     @NCIntent("intent=orderPizzaSize term(size)={# == 'ord:pizza:size'}")
     def onOrderPizzaSize(im: NCIntentMatch, @NCIntentTerm("size") size: 
NCEntity): NCResult = withLog(
         im,
-        (o: Order) => o.getState match
+        (o: PizzeriaOrder) => o.getState match
             case DIALOG_SPECIFY =>
                 if o.setPizzaNoSize(extractPizzaSize(size)) then
                     o.setState(NO_DIALOG);
                     askIsReadyOrAskSpecify(o)
-                else throw UNEXPECTED
-            case DIALOG_CONFIRM | NO_DIALOG | DIALOG_IS_READY | 
DIALOG_SHOULD_CANCEL => throw UNEXPECTED
+                else throw UNEXPECTED_REQUEST
+            case DIALOG_CONFIRM | NO_DIALOG | DIALOG_IS_READY | 
DIALOG_SHOULD_CANCEL => throw UNEXPECTED_REQUEST
         )
     /**
       *
@@ -225,7 +223,7 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
     @NCIntent("intent=status term(status)={# == 'ord:status'}")
     def onStatus(im: NCIntentMatch): NCResult = withLog(
         im,
-        (o: Order) => o.getState match
+        (o: PizzeriaOrder) => o.getState match
             case DIALOG_CONFIRM =>
                 require(o.isValid);
                 askConfirm(o) // Ignore `status`, confirm again.
@@ -241,7 +239,7 @@ class OrderModel extends NCModelAdapter (new 
NCModelConfig("nlpcraft.order.ex",
     @NCIntent("intent=finish term(finish)={# == 'ord:finish'}")
     def onFinish(im: NCIntentMatch): NCResult = withLog(
         im,
-        (o: Order) => o.getState match
+        (o: PizzeriaOrder) => 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)
diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/StanfordPipeline.scala
 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaModelPipeline.scala
similarity index 63%
rename from 
nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/StanfordPipeline.scala
rename to 
nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaModelPipeline.scala
index 34bebf67..b8b73a65 100644
--- 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/StanfordPipeline.scala
+++ 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaModelPipeline.scala
@@ -1,29 +1,13 @@
-/*
- * 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
+package org.apache.nlpcraft.examples.order
 
 import edu.stanford.nlp.pipeline.StanfordCoreNLP
 import opennlp.tools.stemmer.PorterStemmer
-import org.apache.nlpcraft.*
+import org.apache.nlpcraft.examples.order.components.*
 import org.apache.nlpcraft.nlp.entity.parser.semantic.*
 import org.apache.nlpcraft.nlp.entity.parser.stanford.NCStanfordNLPEntityParser
 import org.apache.nlpcraft.nlp.token.enricher.NCEnStopWordsTokenEnricher
 import org.apache.nlpcraft.nlp.token.parser.stanford.NCStanfordNLPTokenParser
+import org.apache.nlpcraft.*
 
 import scala.jdk.CollectionConverters.*
 import java.util.Properties
@@ -31,7 +15,7 @@ import java.util.Properties
 /**
   *
   */
-object StanfordPipeline:
+object PizzeriaModelPipeline:
     val PIPELINE: NCPipeline =
         val stanford =
             val props = new Properties()
@@ -42,14 +26,14 @@ object StanfordPipeline:
             private val ps = new PorterStemmer
             override def stem(txt: String): String = ps.synchronized { 
ps.stem(txt) }
 
-        import EntityExtender as Ex
+        import ElementExtender as Ex
         import EntityData as D
 
         new NCPipelineBuilder().
             withTokenParser(tokParser).
             withTokenEnricher(new NCEnStopWordsTokenEnricher()).
             withEntityParser(new NCStanfordNLPEntityParser(stanford, 
"number")).
-            withEntityParser(new NCSemanticEntityParser(stemmer, tokParser, 
"order_model.yaml")).
+            withEntityParser(new NCSemanticEntityParser(stemmer, tokParser, 
"pizzeria_model.yaml")).
             withEntityMappers(
                 Seq(
                     Ex(Seq(D("ord:pizza", "ord:pizza:size")), 
D("ord:pizza:size", "ord:pizza:size:value")),
@@ -57,4 +41,4 @@ object StanfordPipeline:
                 ).asJava
             ).
             withEntityValidator(new RequestValidator()).
-            build()
\ No newline at end of file
+            build()
diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala
 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaOrder.scala
similarity index 56%
rename from 
nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala
rename to 
nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaOrder.scala
index 395cc20a..d9445826 100644
--- 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala
+++ 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/PizzeriaOrder.scala
@@ -19,19 +19,41 @@ package org.apache.nlpcraft.examples.order
 
 import scala.collection.mutable
 
-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]):
+/**
+  *
+  */
+private abstract class OrderElement:
+    val name: String
+    var qty: Option[Int]
     require(name != null && name.nonEmpty)
+
+/**
+  *
+  * @param name
+  * @param size
+  * @param qty
+  */
+case class Pizza(name: String, var size: Option[String], var qty: Option[Int]) 
extends OrderElement
+
+/**
+  *
+  * @param name
+  * @param qty
+  */
+case class Drink(name: String, var qty: Option[Int]) extends OrderElement
+
 enum State:
     case NO_DIALOG, DIALOG_IS_READY, DIALOG_SHOULD_CANCEL, DIALOG_SPECIFY, 
DIALOG_CONFIRM
 
 import org.apache.nlpcraft.examples.order.State.*
 
-class Order:
+/**
+  *
+  */
+class PizzeriaOrder:
     private var state = NO_DIALOG
-    private val pizzas = mutable.LinkedHashMap.empty[String, Pizza]
-    private val drinks = mutable.LinkedHashMap.empty[String, Drink]
+    private val pizzas = mutable.ArrayBuffer.empty[Pizza]
+    private val drinks = mutable.ArrayBuffer.empty[Drink]
 
     /**
       *
@@ -51,35 +73,43 @@ class Order:
       * @param ds
       */
     def add(ps: Seq[Pizza], ds: Seq[Drink]): Unit =
+        def setByName[T <: OrderElement](buf: mutable.ArrayBuffer[T], t: T) =
+            buf.find(_.name == t.name) match
+                case Some(found) => if t.qty.nonEmpty then found.qty = t.qty
+                case None => buf += t
+
         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
+            def setPizza[T](pred: Pizza => Boolean, notFound: => () => Unit): 
Unit =
+                pizzas.find(pred) match
+                    case Some(found) =>
+                        if p.size.nonEmpty then found.size = p.size
+                        if p.qty.nonEmpty then found.qty = p.qty
+                    case None => notFound()
 
-        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
+            if p.size.nonEmpty then setPizza(
+                x => x.name == p.name && x.size == p.size,
+                () => setPizza(x => x.name == p.name && x.size.isEmpty, () => 
pizzas += p)
+            )
+            else setByName(pizzas, p)
 
+        for (d <- ds) setByName(drinks, d)
     /**
       *
       * @return
       */
-    def getPizzas: Map[String, Pizza] = pizzas.toMap
+    def getPizzas: Seq[Pizza] = pizzas.toSeq
 
     /**
       *
       * @return
       */
-    def getDrinks: Map[String, Drink] = drinks.toMap
+    def getDrinks: Seq[Drink] = drinks.toSeq
 
     /**
       *
       * @return
       */
-    def findPizzaNoSize: Option[Pizza] = pizzas.values.find(_.size.isEmpty)
+    def findPizzaNoSize: Option[Pizza] = pizzas.find(_.size.isEmpty)
 
     /**
       *
diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/EntityExtender.scala
 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/components/ElementExtender.scala
similarity index 90%
rename from 
nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/EntityExtender.scala
rename to 
nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/components/ElementExtender.scala
index dbd772c3..6797a742 100644
--- 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/EntityExtender.scala
+++ 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/components/ElementExtender.scala
@@ -27,14 +27,14 @@ import scala.jdk.CollectionConverters.*
 /**
   *
   * @param id
-  * @param copyProperty
+  * @param property
   */
-case class EntityData(id: String, copyProperty: String)
+case class EntityData(id: String, property: String)
 
 /**
   *
   */
-case class EntityExtender(mainDataSeq: Seq[EntityData], extraData: EntityData) 
extends NCEntityMapper:
+case class ElementExtender(mainDataSeq: Seq[EntityData], extraData: 
EntityData) extends NCEntityMapper:
     private def getToks(e: NCEntity): mutable.Seq[NCToken] = 
e.getTokens.asScala
     override def map(req: NCRequest, cfg: NCModelConfig, entities: 
util.List[NCEntity]): util.List[NCEntity] =
         val mainDataMap = mainDataSeq.map(p => p.id -> p).toMap
@@ -54,7 +54,7 @@ case class EntityExtender(mainDataSeq: Seq[EntityData], 
extraData: EntityData) e
                         val (mEnt, eEnt) = if mainDataMap.contains(e1.getId) 
then (e1, e2) else (e2, e1)
                         new NCPropertyMapAdapter with NCEntity:
                             mEnt.keysSet().forEach(k => put(k, mEnt.get(k)))
-                            put[String](mainDataMap(mEnt.getId).copyProperty, 
eEnt.get[String](extraData.copyProperty).toLowerCase)
+                            put[String](mainDataMap(mEnt.getId).property, 
eEnt.get[String](extraData.property).toLowerCase)
                             override val getTokens: JList[NCToken] = 
(getToks(mEnt) ++ getToks(eEnt)).sortBy(_.getIndex).asJava
                             override val getRequestId: String = 
req.getRequestId
                             override val getId: String = mEnt.getId
diff --git 
a/nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/RequestValidator.scala
 
b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/components/RequestValidator.scala
similarity index 100%
rename from 
nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/components/RequestValidator.scala
rename to 
nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/order/components/RequestValidator.scala
diff --git a/nlpcraft-examples/order/src/main/resources/order_model.yaml 
b/nlpcraft-examples/pizzeria/src/main/resources/pizzeria_model.yaml
similarity index 80%
rename from nlpcraft-examples/order/src/main/resources/order_model.yaml
rename to nlpcraft-examples/pizzeria/src/main/resources/pizzeria_model.yaml
index 450d3a0d..25676fb0 100644
--- a/nlpcraft-examples/order/src/main/resources/order_model.yaml
+++ b/nlpcraft-examples/pizzeria/src/main/resources/pizzeria_model.yaml
@@ -27,8 +27,8 @@ elements:
     description: "Size of pizza."
     values:
       "small": [ "{small|smallest|min|minimal} {size|_}" ]
-      "medium": [ "{medium|intermediate} {size|_}" ]
-      "large": [ "{big|biggest|large|max|maximum} {size|_}" ]
+      "medium": [ "{medium|intermediate|normal|regular} {size|_}" ]
+      "large": [ "{big|biggest|large|max|maximum|huge} {size|_}" ]
 
   - id: "ord:drink"
     description: "Kinds of drinks."
@@ -41,7 +41,7 @@ elements:
   - id: "ord:yes"
     description: "Conformation (yes)."
     synonyms:
-      - "{yes|yeah|right|fine|nice|excellent|good}"
+      - "{yes|yeah|right|fine|nice|excellent|good|correct|sure}"
       - "{you are|_} {correct|right}"
 
   - id: "ord:no"
@@ -53,20 +53,20 @@ elements:
   - id: "ord:stop"
     description: "Stop and cancel all."
     synonyms:
-      - "{stop|cancel} {it|all|everything|_}"
+      - "{stop|cancel|clear} {it|all|everything|_}"
 
   - id: "ord:status"
     description: "Order status information."
     synonyms:
-      - "{order|_} {status|state}"
+      - "{current|_} {order|_} {status|state|info|information}"
 
   - id: "ord:finish"
     description: "Order finish."
     synonyms:
-      - "order"
-      - "{order|I|_} {is|are|have|has|_} {ready|done|finish}"
+      - "{i|everything|order|_} {is|_} {finish|ready|done}"
 
   - id: "ord:menu"
     description: "Order menu."
     synonyms:
-      - "{menu|order list}"
+      - "{menu|carte|card}"
+      - "{products|goods|food|_} list"
diff --git 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelSpec.scala
 
b/nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/PizzeriaModelSpec.scala
similarity index 59%
rename from 
nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelSpec.scala
rename to 
nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/PizzeriaModelSpec.scala
index 3ae7ed2e..afe36b93 100644
--- 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelSpec.scala
+++ 
b/nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/PizzeriaModelSpec.scala
@@ -26,29 +26,35 @@ import scala.collection.mutable
 /**
   *
   */
-class OrderModelSpec:
+class PizzeriaModelSpec:
     @Test
     def test(): Unit =
         val buf = mutable.ArrayBuffer.empty[String]
 
-        def printDialog(): Unit = for (line <- buf) println(line)
+        def printDialog(): Unit = buf.foreach(println)
 
-        Using.resource(new NCModelClient(new OrderModel)) { client =>
+        Using.resource(new NCModelClient(new PizzeriaModel)) { client =>
             def ask(txt: String, expResType: NCResultType): Unit =
-                val resp = client.ask(txt, null, "userId")
-
-                buf += s">> $txt"
-                buf += s">> '${resp.getType}': ${resp.getBody}"
-                buf += ""
-
-                if expResType != resp.getType then
-                    printDialog()
-                    require(false, s"Unexpected type: ${resp.getType}, 
expected: $expResType.")
-
-            ask("I want to order margherita medium size, marbonara, marinara 
and tea", ASK_DIALOG)
+                try
+                    val resp = client.ask(txt, null, "userId")
+
+                    buf += s">> Request: $txt"
+                    buf += s">> Response: '${resp.getType}': ${resp.getBody}"
+                    buf += ""
+
+                    if expResType != resp.getType then
+                        printDialog()
+                        require(false, s"Unexpected type: ${resp.getType}, 
expected: $expResType.")
+                catch {
+                    case e: Exception =>
+                        printDialog()
+                        throw e
+                }
+            ask("I want to order carbonara, marinara and tea", ASK_DIALOG)
             ask("large size please", ASK_DIALOG)
             ask("smallest", ASK_DIALOG)
-            ask("you are right", ASK_RESULT)
+            ask("yes", ASK_DIALOG)
+            ask("correct", ASK_RESULT)
 
             printDialog()
         }
\ No newline at end of file
diff --git 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala
 
b/nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/cli/PizzeriaModelClientCli.scala
similarity index 96%
rename from 
nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala
rename to 
nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/cli/PizzeriaModelClientCli.scala
index 35c8ae0b..b621d1f8 100644
--- 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala
+++ 
b/nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/cli/PizzeriaModelClientCli.scala
@@ -28,7 +28,7 @@ import java.net.http.HttpRequest.*
 import java.net.http.HttpResponse.*
 import scala.util.Using
 
-object OrderModelClientCli extends LazyLogging :
+object PizzeriaModelClientCli extends LazyLogging :
     private val client = HttpClient.newHttpClient()
 
     private def ask(req: String): String =
@@ -36,7 +36,7 @@ object OrderModelClientCli extends LazyLogging :
             val resp: HttpResponse[String] = client.send(
                 HttpRequest.
                     newBuilder().
-                    uri(new URI(OrderModelServer.URI)).
+                    uri(new URI(PizzeriaModelServer.URI)).
                     headers("Content-Type", "text/plain;charset=UTF-8").
                     POST(BodyPublishers.ofString(req)).
                     build(),
diff --git 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelServer.scala
 
b/nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/cli/PizzeriaModelServer.scala
similarity index 96%
rename from 
nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelServer.scala
rename to 
nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/cli/PizzeriaModelServer.scala
index 09c3fa53..e345dbe4 100644
--- 
a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelServer.scala
+++ 
b/nlpcraft-examples/pizzeria/src/test/java/org/apache/nlpcraft/examples/order/cli/PizzeriaModelServer.scala
@@ -20,7 +20,7 @@ package org.apache.nlpcraft.examples.order.cli
 import com.sun.net.httpserver.*
 import org.apache.nlpcraft.*
 import org.apache.nlpcraft.NCResultType.*
-import org.apache.nlpcraft.examples.order.OrderModel
+import org.apache.nlpcraft.examples.order.PizzeriaModel
 
 import java.io.*
 import java.net.InetSocketAddress
@@ -29,14 +29,14 @@ import scala.util.Using
 /**
   *
   */
-object OrderModelServer:
+object PizzeriaModelServer:
     private val host = "localhost"
     private val port = 8087
     private val path = "ask"
 
     val URI = s"http://$host:$port/$path";
 
-    def main(args: Array[String]): Unit = Using.resource(new NCModelClient(new 
OrderModel)) { nlpClient =>
+    def main(args: Array[String]): Unit = Using.resource(new NCModelClient(new 
PizzeriaModel)) { nlpClient =>
         val srv = HttpServer.create(new InetSocketAddress(host, port), 0)
 
         srv.createContext(
diff --git a/pom.xml b/pom.xml
index 3238a20c..3342e52b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -392,7 +392,7 @@
                 <module>nlpcraft-examples/lightswitch</module>
                 <module>nlpcraft-examples/lightswitch-ru</module>
                 <module>nlpcraft-examples/lightswitch-fr</module>
-                <module>nlpcraft-examples/order</module>
+                <module>nlpcraft-examples/pizzeria</module>
             </modules>
         </profile>
     </profiles>

Reply via email to