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}")