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
commit 4c01ec8f650b7e9a9b94be27cc22e9b3fe0e6f84 Author: Sergey Kamov <skhdlem...@gmail.com> AuthorDate: Sun Apr 3 12:45:26 2022 +0300 Api extended. Bugfixes. --- .../nlpcraft/examples/order/OrderModel.scala | 17 +++-- .../order/{Order.scala => OrderState.scala} | 6 +- .../order/src/main/resources/order_model.yaml | 14 ++-- .../nlpcraft/examples/order/OrderModelCli.scala | 51 -------------- .../examples/order/cli/OrderModelClientCli.scala | 77 ++++++++++++++++++++++ .../OrderModelServer.scala} | 43 ++++++------ 6 files changed, 118 insertions(+), 90 deletions(-) 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 253acbd..fccb964 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 @@ -18,6 +18,7 @@ package org.apache.nlpcraft.examples.order import com.typesafe.scalalogging.LazyLogging +import org.antlr.v4.runtime.misc.Predicate import org.apache.nlpcraft.* import org.apache.nlpcraft.internal.util.NCResourceReader import org.apache.nlpcraft.nlp.* @@ -33,15 +34,15 @@ object OrderModel extends LazyLogging: private def extractPizzaSize(e: NCEntity): PizzaSize = PizzaSize.valueOf(e.get[String]("ord:pizza:size:value").toUpperCase) private def extractDrink(e: NCEntity): String = e.get[String]("ord:drink:value") private def isStopWord(t: NCToken): Boolean = t.get[Boolean]("stopword") - private def confirmOrSpecify(ord: Order): NCResult = + private def confirmOrSpecify(ord: OrderState): NCResult = NCResult(if ord.isValid() then ord.ask2Confirm() else ord.ask2Specify(), ASK_DIALOG) - private def continue(ord: Order): NCResult = + private def continue(ord: OrderState): NCResult = NCResult(if ord.isValid() then s"OK, please continue your order: $ord" else ord.ask2Specify(), ASK_DIALOG) - private def log(o: Order): Unit = logger.info(o.getState()) - private def onStart(im: NCIntentMatch, o: Order): Unit = + private def log(o: OrderState): Unit = logger.info(o.getState()) + private def onStart(im: NCIntentMatch, o: OrderState): Unit = logger.info(s"Initial state before request: ${im.getContext.getRequest.getText}") - private def onFinish(o: Order): Unit = + private def onFinish(o: OrderState): Unit = logger.info(s"Result state") logger.info(o.getState()) @@ -79,9 +80,9 @@ class OrderModel extends NCModelAdapter ( new NCModelConfig("nlpcraft.order.ex", "Order Example Model", "1.0"), new NCPipelineBuilder().withSemantic("en", "order_model.yaml").build() ) with LazyLogging: - private val ords = mutable.HashMap.empty[String, Order] + private val ords = mutable.HashMap.empty[String, OrderState] - private def getOrder(im: NCIntentMatch): Order = ords.getOrElseUpdate(im.getContext.getRequest.getUserId, new Order) + private def getOrder(im: NCIntentMatch): OrderState = ords.getOrElseUpdate(im.getContext.getRequest.getUserId, new OrderState) @NCIntent("intent=confirm term(confirm)={has(ent_groups, 'confirm')}") def onConfirm(im: NCIntentMatch, @NCIntentTerm("confirm") confirm: NCEntity): NCResult = @@ -91,6 +92,8 @@ class OrderModel extends NCModelAdapter ( def cancelAll(): NCResult = ord.clear() + im.getContext.getConversation.clearStm(_ => true) + im.getContext.getConversation.clearDialog(_ => true) NCResult("Order canceled. We are ready for new orders.", ASK_RESULT) val res = 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/OrderState.scala similarity index 98% rename from nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/Order.scala rename to nlpcraft-examples/order/src/main/java/org/apache/nlpcraft/examples/order/OrderState.scala index 2611ea6..b1c128e 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/OrderState.scala @@ -22,7 +22,7 @@ import scala.collection.mutable private enum PizzaSize: case SMALL, MEDIUM, LARGE -object Order: +object OrderState: private val allPizzaSizeKinds: String = withComma(PizzaSize.values.map(_.toString.toLowerCase)) private def withComma(iter: Iterable[String]): String = iter.mkString(", ") @@ -32,7 +32,7 @@ object Order: if seq.nonEmpty then s"$name: ${withComma(seq.map(toStr))}." else "" private def norm(s: String) = s.trim.replaceAll("(?m)^[ \t]*\r?\n", "") -import Order.* +import OrderState.* /** * Contract. @@ -40,7 +40,7 @@ import Order.* * 2. 'specify' methods (specifyPizzaSize) should specify elements in the same order. * So, we don't need to save which concrete element we treying to specify. */ -class Order: +class OrderState: private val pizza = mutable.LinkedHashMap.empty[String, PizzaSize] private val drinks = mutable.LinkedHashSet.empty[String] diff --git a/nlpcraft-examples/order/src/main/resources/order_model.yaml b/nlpcraft-examples/order/src/main/resources/order_model.yaml index 245294e..798b1f2 100644 --- a/nlpcraft-examples/order/src/main/resources/order_model.yaml +++ b/nlpcraft-examples/order/src/main/resources/order_model.yaml @@ -33,9 +33,9 @@ elements: - id: "ord:pizza:size" description: "Size of pizza." values: - "small": [ "{small|smallest|min|minimal} {size|*}" ] - "medium": [ "{medium|intermediate} {size|*}" ] - "large": [ "{big|large|max|maximum} {size|*}" ] + "small": [ "{small|smallest|min|minimal} {size|_}" ] + "medium": [ "{medium|intermediate} {size|_}" ] + "large": [ "{big|biggest|large|max|maximum} {size|_}" ] - id: "ord:drink" description: "Kinds of drinks." @@ -43,27 +43,27 @@ elements: "tea": [ ] "green tea": [ ] "coffee": [ ] - "cola": [ "{coca|cola|coca cola|cocacola|coca-cola}" ] + "cola": ["{coca|cola|coca cola|cocacola|coca-cola}"] - id: "ord:confirm:yes" description: "Conformation (yes)." groups: ["confirm"] synonyms: - "{yes|yeah|right|fine|nice|excellent|good}" - - "{you are|*} {correct|right}" + - "{you are|_} {correct|right}" - id: "ord:confirm:no" description: "Conformation (no)." groups: ["confirm"] synonyms: - "{no|nope|incorrect|wrong}" - - "{you are|*} {not|are not|aren't } {correct|right}" + - "{you are|_} {not|are not|aren't} {correct|right}" - id: "ord:confirm:continue" description: "Confirmation (continue)." groups: ["confirm"] synonyms: - - "{continue}" + - "continue" - id: "ord:stop" description: "Stop and cancel all." diff --git a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelCli.scala b/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelCli.scala deleted file mode 100644 index 4608bf9..0000000 --- a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelCli.scala +++ /dev/null @@ -1,51 +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 com.typesafe.scalalogging.LazyLogging -import org.apache.nlpcraft.examples.order.OrderModelCli.logger -import org.apache.nlpcraft.* -import org.apache.nlpcraft.NCResultType.* - -import scala.util.Using - -object OrderModelCli extends App with LazyLogging : - main() - - private def main(): Unit = Using.resource(new NCModelClient(new OrderModel)) { client => - logger.info("Application started.") - - var resp: NCResult = null - - while (true) - val prompt = - if resp == null || resp.getType == ASK_RESULT then "Ask your question to the model: " - else "Your should answer on the model's question: " - logger.info(s">>>>>>>>>> $prompt") - - try - resp = client.ask(scala.io.StdIn.readLine(), null, "userId") - - logger.info(s">>>>>>>>>> Response type: ${resp.getType}") - logger.info(s">>>>>>>>>> Response body:\n${resp.getBody}") - catch - case e: NCRejection => logger.info(s"Request rejected: ${e.getMessage}") - case e: Throwable => logger.error(s"Unexpected error: ${e.getMessage}") - logger.error("Application exit.") - System.exit(-1) - } 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 new file mode 100644 index 0000000..01cd4a1 --- /dev/null +++ b/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelClientCli.scala @@ -0,0 +1,77 @@ +/* + * 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.cli + +import com.typesafe.scalalogging.LazyLogging +import org.apache.nlpcraft.* +import org.apache.nlpcraft.NCResultType.* + +import java.io.* +import java.net.URI +import java.net.http.* +import java.net.http.HttpRequest.* +import java.net.http.HttpResponse.* +import scala.util.Using + +object OrderModelClientCli extends LazyLogging : + private val client = HttpClient.newHttpClient() + + private def ask(req: String): String = + try + val resp: HttpResponse[String] = client.send( + HttpRequest. + newBuilder(). + uri(new URI(OrderModelServer.URI)). + headers("Content-Type", "text/plain;charset=UTF-8"). + POST(BodyPublishers.ofString(req)). + build(), + BodyHandlers.ofString() + ) + if resp.statusCode() != 200 then throw new IOException(s"Unexpected response type: ${resp.statusCode()}") + resp.body + catch + case e: IOException => throw e + case e: Throwable => throw new IOException(e) + + def main(args: Array[String]): Unit = + println("Application started.") + + // Clears possible saved sessions. + ask("stop") + + var applStarted = true + + Runtime.getRuntime.addShutdownHook( + new Thread("shutdownHook"): + override def run(): Unit = applStarted = false + ) + + while (true) + print(s">>> ") + + try + println(ask(scala.io.StdIn.readLine())) + println + catch + case e: NCRejection => println(s"Request rejected: ${e.getMessage}") + case e: IOException => if applStarted then println(s"IO error: ${e.getMessage}") + case e: Throwable => + if applStarted then + e.printStackTrace() + println("Application exit.") + System.exit(-1) diff --git a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelRest.scala b/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelServer.scala similarity index 73% rename from nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelRest.scala rename to nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelServer.scala index 7985cfa..5e09e6e 100644 --- a/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/OrderModelRest.scala +++ b/nlpcraft-examples/order/src/test/java/org/apache/nlpcraft/examples/order/cli/OrderModelServer.scala @@ -15,32 +15,32 @@ * limitations under the License. */ -package org.apache.nlpcraft.examples.order +package org.apache.nlpcraft.examples.order.cli import com.sun.net.httpserver.* -import com.typesafe.scalalogging.LazyLogging import org.apache.nlpcraft.* import org.apache.nlpcraft.NCResultType.* +import org.apache.nlpcraft.examples.order.OrderModel import java.io.* -import scala.util.Using -import com.sun.net.httpserver.HttpServer - import java.net.InetSocketAddress -import scala.language.postfixOps - +import scala.util.Using -object OrderModelRest extends App with LazyLogging: - private val HOST = "localhost" - private val PORT = 8087 +/** + * + */ +object OrderModelServer: + private val host = "localhost" + private val port = 8087 + private val path = "ask" - main() + val URI = s"http://$host:$port/$path" - private def main(): Unit = Using.resource(new NCModelClient(new OrderModel)) { client => - val srv = HttpServer.create(new InetSocketAddress(HOST, PORT), 0) + def main(args: Array[String]): Unit = Using.resource(new NCModelClient(new OrderModel)) { nlpClient => + val srv = HttpServer.create(new InetSocketAddress(host, port), 0) srv.createContext( - "/ask", + s"/$path", (e: HttpExchange) => def response(txt: String): Unit = Using.resource(new BufferedOutputStream(e.getResponseBody)) { out => @@ -61,16 +61,15 @@ object OrderModelRest extends App with LazyLogging: if req == null || req.isEmpty then Exception(s"Empty request") - val resp = client.ask(req, null, "userId") - val prompt = - if resp.getType == ASK_RESULT then "Ask your question to the model: " - else "Your should answer on the model's question: " + val resp = nlpClient.ask(req, null, "userId") + val prompt = if resp.getType == ASK_DIALOG then "(Your should answer on the model's question)\n" else "" - response(s"$prompt ${resp.getBody}") + response(s"$prompt${resp.getBody}") catch case e: NCRejection => response(s"Request rejected: ${e.getMessage}") case e: Throwable => - logger.error("Unexpected error.", e) + System.err.println("Unexpected error.") + e.printStackTrace() response(s"Unexpected error: ${e.getMessage}") ) @@ -84,10 +83,10 @@ object OrderModelRest extends App with LazyLogging: applStarted = false srv.stop(0) srv.synchronized { srv.notifyAll() } - logger.info("Server stopped.") + println("Server stopped.") ) - logger.info(s"Server started: http://$HOST:$PORT/ask") + println(s"Server started: $URI") while (applStarted) srv.synchronized {