You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nlpcraft.apache.org by se...@apache.org on 2022/07/13 12:29:55 UTC
[incubator-nlpcraft] branch NLPCRAFT-491 updated: Pizzeria examples refactoring.
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 226ff4b5 Pizzeria examples refactoring.
226ff4b5 is described below
commit 226ff4b547a7af00a7fe1b1b013214de5edf61d2
Author: Sergey Kamov <sk...@gmail.com>
AuthorDate: Wed Jul 13 15:29:45 2022 +0300
Pizzeria examples refactoring.
---
.../nlpcraft/examples/pizzeria/PizzeriaModel.scala | 17 +++----
.../nlpcraft/examples/pizzeria/PizzeriaOrder.scala | 14 +++---
.../{ => components}/PizzeriaModelPipeline.scala | 20 +++-----
...derExtender.scala => PizzeriaOrderMapper.scala} | 58 +++++++++++-----------
.../components/PizzeriaOrderValidator.scala | 2 +-
.../org/apache/nlpcraft/NCPropertyMapAdapter.scala | 2 +-
6 files changed, 52 insertions(+), 61 deletions(-)
diff --git a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaModel.scala b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaModel.scala
index 3a46d562..bb4a5f73 100644
--- a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaModel.scala
+++ b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaModel.scala
@@ -23,12 +23,14 @@ import org.apache.nlpcraft.NCResultType.*
import org.apache.nlpcraft.annotations.*
import org.apache.nlpcraft.examples.pizzeria.{PizzeriaOrder as Order, PizzeriaOrderState as State}
import org.apache.nlpcraft.examples.pizzeria.PizzeriaOrderState.*
+import org.apache.nlpcraft.examples.pizzeria.components.PizzeriaModelPipeline
import org.apache.nlpcraft.nlp.*
/**
* * Pizza model helper.
*/
object PizzeriaModel extends LazyLogging:
+ type Result = (NCResult, State)
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")
@@ -41,13 +43,12 @@ object PizzeriaModel extends LazyLogging:
private def getOrder(ctx: NCContext): Order =
val data = ctx.getConversation.getData
val usrId = ctx.getRequest.getUserId
- var o: Order = data.get(usrId)
-
- if o == null then
- o = new Order()
- data.put(usrId, o)
-
- o
+ data.getOpt[Order](usrId) match
+ case Some(ord) => ord
+ case None =>
+ val ord = new Order()
+ data.put(usrId, ord)
+ ord
private def mkResult(msg: String): NCResult = NCResult(msg, ASK_RESULT)
private def mkDialog(msg: String): NCResult = NCResult(msg, ASK_DIALOG)
@@ -111,8 +112,6 @@ object PizzeriaModel extends LazyLogging:
private def askIsReadyOrAskSpecify(o: Order): Result = if o.isValid then askIsReady() else askSpecify(o)
private def askStopOrDoStop(o: Order)(using ctx: NCContext, im: NCIntentMatch): Result = if o.isValid then askShouldStop() else doStop(o)
- type Result = (NCResult, State)
-
import org.apache.nlpcraft.examples.pizzeria.PizzeriaModel.*
/**
diff --git a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaOrder.scala b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaOrder.scala
index 66cc2c06..f510accd 100644
--- a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaOrder.scala
+++ b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaOrder.scala
@@ -25,12 +25,12 @@ import scala.collection.mutable
enum PizzeriaOrderState:
case DIALOG_EMPTY, DIALOG_IS_READY, DIALOG_SHOULD_CANCEL, DIALOG_SPECIFY, DIALOG_CONFIRM
-private object OrderElement:
+private object OrderPosition:
val DFLT_QTY = 1
/**
*
*/
-private abstract class OrderElement:
+private trait OrderPosition:
val name: String
var qty: Option[Int]
require(name != null && name.nonEmpty)
@@ -42,8 +42,8 @@ private abstract class OrderElement:
* @param size Optional size.
* @param qty Optional quantity.
*/
-case class Pizza(name: String, var size: Option[String], var qty: Option[Int]) extends OrderElement:
- override def toString = s"$name '${size.getOrElse("undefined size")}' ${qty.getOrElse(OrderElement.DFLT_QTY)} pcs"
+case class Pizza(name: String, var size: Option[String], var qty: Option[Int]) extends OrderPosition:
+ override def toString = s"$name '${size.getOrElse("undefined size")}' ${qty.getOrElse(OrderPosition.DFLT_QTY)} pcs"
/**
* Drink order data holder.
@@ -51,8 +51,8 @@ case class Pizza(name: String, var size: Option[String], var qty: Option[Int]) e
* @param name Name.
* @param qty Optional quantity.
*/
-case class Drink(name: String, var qty: Option[Int]) extends OrderElement:
- override def toString = s"$name ${qty.getOrElse(OrderElement.DFLT_QTY)} pcs"
+case class Drink(name: String, var qty: Option[Int]) extends OrderPosition:
+ override def toString = s"$name ${qty.getOrElse(OrderPosition.DFLT_QTY)} pcs"
import org.apache.nlpcraft.examples.pizzeria.PizzeriaOrderState.*
@@ -82,7 +82,7 @@ class PizzeriaOrder:
* @param ds
*/
def add(ps: Seq[Pizza], ds: Seq[Drink]): Unit =
- def setByName[T <: OrderElement](buf: mutable.ArrayBuffer[T], t: T): Unit =
+ def setByName[T <: OrderPosition](buf: mutable.ArrayBuffer[T], t: T): Unit =
buf.find(_.name == t.name) match
case Some(found) => if t.qty.nonEmpty then found.qty = t.qty
case None => buf += t
diff --git a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaModelPipeline.scala b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaModelPipeline.scala
similarity index 71%
rename from nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaModelPipeline.scala
rename to nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaModelPipeline.scala
index ca233a4d..73fafbc0 100644
--- a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/PizzeriaModelPipeline.scala
+++ b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaModelPipeline.scala
@@ -1,19 +1,17 @@
-package org.apache.nlpcraft.examples.pizzeria
+package org.apache.nlpcraft.examples.pizzeria.components
import edu.stanford.nlp.pipeline.StanfordCoreNLP
-import java.util.Properties
import opennlp.tools.stemmer.PorterStemmer
-import org.apache.nlpcraft.examples.pizzeria.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 org.apache.nlpcraft.nlp.entity.parser.stanford.NCStanfordNLPEntityParser
+import java.util.Properties
/**
- * PizzeriaModel pipeline, based on Stanford NLP engine, including model custom components.
- */
+ * PizzeriaModel pipeline, based on Stanford NLP engine, including model custom components. */
object PizzeriaModelPipeline:
val PIPELINE: NCPipeline =
val stanford =
@@ -25,18 +23,14 @@ object PizzeriaModelPipeline:
private val ps = new PorterStemmer
override def stem(txt: String): String = ps.synchronized { ps.stem(txt) }
- import PizzeriaOrderExtender as Ex, EntityData as D
+ import MapperDesc as D
new NCPipelineBuilder().
withTokenParser(tokParser).
withTokenEnricher(new NCEnStopWordsTokenEnricher()).
withEntityParser(new NCStanfordNLPEntityParser(stanford, Set("number"))).
withEntityParser(NCSemanticEntityParser(stemmer, tokParser, "pizzeria_model.yaml")).
- withEntityMappers(
- List(
- Ex(Seq(D("ord:pizza", "ord:pizza:size")), D("ord:pizza:size", "ord:pizza:size:value")),
- Ex(Seq(D("ord:pizza", "ord:pizza:qty"), D("ord:drink", "ord:drink:qty")), D("stanford:number", "stanford:number:nne")),
- )
- ).
+ withEntityMapper(PizzeriaOrderMapper(extra = D("ord:pizza:size", "ord:pizza:size:value"), dests = D("ord:pizza", "ord:pizza:size"))).
+ withEntityMapper(PizzeriaOrderMapper(extra = D("stanford:number", "stanford:number:nne"), dests = D("ord:pizza", "ord:pizza:qty"), D("ord:drink", "ord:drink:qty"))).
withEntityValidator(new PizzeriaOrderValidator()).
build
\ No newline at end of file
diff --git a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderExtender.scala b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderMapper.scala
similarity index 54%
rename from nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderExtender.scala
rename to nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderMapper.scala
index 54816210..a16bf476 100644
--- a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderExtender.scala
+++ b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderMapper.scala
@@ -25,14 +25,14 @@ import scala.collection.*
/**
*
- * @param id
- * @param property
+ * @param elementId Element.
+ * @param propertyName Element's property name.
*/
-case class EntityData(id: String, property: String)
+case class MapperDesc(elementId: String, propertyName: String)
/**
* Element extender.
- * For each 'main' element it tries to find related extra element and convert this pair to new complex element.
+ * For each 'main' dest element it tries to find related extra element and convert this pair to new complex element.
* New element:
* 1. Gets same ID as main element, also all main element properties copied into this new one.
* 2. Gets tokens from both elements.
@@ -41,52 +41,50 @@ case class EntityData(id: String, property: String)
* Note that it is simple example implementation.
* It just tries to unite nearest neighbours and doesn't check intermediate words, order correctness etc.
*/
-object PizzeriaOrderExtender:
+object PizzeriaOrderMapper:
extension(entity: NCEntity)
def position: Double =
val toks = entity.getTokens
(toks.head.getIndex + toks.last.getIndex) / 2.0
def tokens: List[NCToken] = entity.getTokens
-import PizzeriaOrderExtender.*
+ private def str(es: Iterable[NCEntity]): String =
+ es.map(e => s"id=${e.getId}(${e.tokens.map(_.getIndex).mkString("[", ",", "]")})").mkString("{", ", ", "}")
-/**
- *
- * @param mainDataSeq
- * @param extraData
- */
-case class PizzeriaOrderExtender(mainDataSeq: Seq[EntityData], extraData: EntityData) extends NCEntityMapper with LazyLogging:
+ def apply(extra: MapperDesc, dests: MapperDesc*): PizzeriaOrderMapper = new PizzeriaOrderMapper(extra, dests)
+
+import PizzeriaOrderMapper.*
+
+case class PizzeriaOrderMapper(extra: MapperDesc, dests: Seq[MapperDesc]) extends NCEntityMapper with LazyLogging:
override def map(req: NCRequest, cfg: NCModelConfig, ents: List[NCEntity]): List[NCEntity] =
- def combine(mainEnt: NCEntity, mainProp: String, extraEnt: NCEntity): NCEntity =
+ def map(destEnt: NCEntity, destProp: String, extraEnt: NCEntity): NCEntity =
new NCPropertyMapAdapter with NCEntity:
- mainEnt.keysSet.foreach(k => put(k, mainEnt.get(k)))
- put[String](mainProp, extraEnt.get[String](extraData.property).toLowerCase)
- override val getTokens: List[NCToken] = (mainEnt.tokens ++ extraEnt.tokens).sortBy(_.getIndex)
+ destEnt.keysSet.foreach(k => put(k, destEnt.get(k)))
+ put[String](destProp, extraEnt.get[String](extra.propertyName).toLowerCase)
+ override val getTokens: List[NCToken] = (destEnt.tokens ++ extraEnt.tokens).sortBy(_.getIndex)
override val getRequestId: String = req.getRequestId
- override val getId: String = mainEnt.getId
+ override val getId: String = destEnt.getId
- val mainById = mainDataSeq.map(p => p.id -> p).toMap
- val main = mutable.HashSet.empty ++ ents.filter(e => mainById.contains(e.getId))
- val extra = ents.filter(_.getId == extraData.id)
+ val mainById = dests.map(p => p.elementId -> p).toMap
+ val descEnts = mutable.HashSet.empty ++ ents.filter(e => mainById.contains(e.getId))
+ val extraEnts = ents.filter(_.getId == extra.elementId)
- if main.nonEmpty && extra.nonEmpty && main.size >= extra.size then
- val used = (main ++ extra).toSet
+ if descEnts.nonEmpty && extraEnts.nonEmpty && descEnts.size >= extraEnts.size then
+ val used = (descEnts ++ extraEnts).toSet
val main2Extra = mutable.HashMap.empty[NCEntity, NCEntity]
- for (e <- extra)
- val m = main.minBy(m => Math.abs(m.position - e.position))
- main -= m
+ for (e <- extraEnts)
+ val m = descEnts.minBy(m => Math.abs(m.position - e.position))
+ descEnts -= m
main2Extra += m -> e
val unrelated = ents.filter(e => !used.contains(e))
- val artificial = for ((m, e) <- main2Extra) yield combine(m, mainById(m.getId).property, e)
- val unused = main
+ val artificial = for ((m, e) <- main2Extra) yield map(m, mainById(m.getId).propertyName, e)
+ val unused = descEnts
val res = (unrelated ++ artificial ++ unused).sortBy(_.tokens.head.getIndex)
- def s(es: Iterable[NCEntity]) =
- es.map(e => s"id=${e.getId}(${e.tokens.map(_.getIndex).mkString("[", ",", "]")})").mkString("{", ", ", "}")
- logger.debug(s"Elements mapped [input=${s(ents)}, output=${s(res)}]")
+ logger.debug(s"Elements mapped [input=${str(ents)}, output=${str(res)}]")
res
else ents
\ No newline at end of file
diff --git a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderValidator.scala b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderValidator.scala
index 09f653dd..b0d2f8b3 100644
--- a/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderValidator.scala
+++ b/nlpcraft-examples/pizzeria/src/main/java/org/apache/nlpcraft/examples/pizzeria/components/PizzeriaOrderValidator.scala
@@ -31,7 +31,7 @@ class PizzeriaOrderValidator extends NCEntityValidator:
val cntNums = count("stanford:number")
val cntSize = count("ord:pizza:size")
- // Single size - it is order specification request.
+ // Single size - it is order specification request.
if cntSize != 1 && cntSize > cntPizza then
throw new NCRejection("There are unrecognized pizza sizes in the request, maybe because some misprints.")
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.scala
index 1c8c8e86..44430183 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.scala
@@ -44,6 +44,6 @@ class NCPropertyMapAdapter extends NCPropertyMap:
override def remove(key: String, obj: Any): Boolean = map.remove(key, obj)
- override def keysSet = map.keys().asScala.toSet
+ override def keysSet: Set[String] = map.keys().asScala.toSet
override def clear(): Unit = map.clear()
\ No newline at end of file