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

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


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

commit c9236f6f315bcde595b117d00b4cb084a9aa0643
Author: Sergey Kamov <[email protected]>
AuthorDate: Fri Feb 18 23:09:26 2022 +0300

    WIP.
---
 .../scala/org/apache/nlpcraft/NCModelClient.java   | 35 ++++++---
 .../scala/org/apache/nlpcraft/NCPropertyMap.java   |  5 ++
 .../org/apache/nlpcraft/NCPropertyMapAdapter.java  | 12 ++-
 .../conversation/NCConversationManager.scala       |  6 +-
 .../nlpcraft/internal/impl/NCModelClientImpl.scala | 85 ++++++++++++++++------
 .../nlpcraft/internal/impl/NCModelClientSpec.scala |  9 ++-
 .../internal/impl/NCSlowPipelineSpec.scala         | 82 ---------------------
 7 files changed, 109 insertions(+), 125 deletions(-)

diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java
index 9f465c2..54f023b 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java
@@ -20,7 +20,7 @@ package org.apache.nlpcraft;
 import org.apache.nlpcraft.internal.impl.NCModelClientImpl;
 
 import java.util.Map;
-import java.util.concurrent.*;
+import java.util.function.Predicate;
 
 /**
  *
@@ -44,29 +44,26 @@ public class NCModelClient implements AutoCloseable {
      * @return
      * @throws NCException
      */
-    public CompletableFuture<NCResult> ask(String txt, Map<String, Object> 
data, String usrId) {
+    public NCResult ask(String txt, Map<String, Object> data, String usrId) {
         return impl.ask(txt, data, usrId);
     }
 
     /**
      *
-     * @param txt
-     * @param data
      * @param usrId
-     * @return
      * @throws NCException
      */
-    public NCResult askSync(String txt, Map<String, Object> data, String 
usrId) {
-        return impl.askSync(txt, data, usrId);
+    public void clearStm(String usrId) {
+        impl.clearStm(usrId);
     }
 
     /**
      *
      * @param usrId
-     * @throws NCException
+     * @param filter
      */
-    public void clearConversation(String usrId) {
-        impl.clearConversation(usrId);
+    public void clearStm(String usrId, Predicate<NCEntity> filter) {
+        impl.clearStm(usrId, filter);
     }
 
     /**
@@ -79,10 +76,26 @@ public class NCModelClient implements AutoCloseable {
     }
 
     /**
-     * 
+     *
+     * @param usrId
+     * @param filter
+     */
+    public void clearDialog(String usrId, Predicate<NCDialogFlowItem> filter) {
+        impl.clearDialog(usrId, filter);
+    }
+
+    /**
+     *
      */
     @Override
     public void close() {
         impl.close();
     }
+
+    /**
+     *
+     */
+    public void validateSamples() {
+        impl.validateSamples();
+    }
 }
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMap.java 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMap.java
index 2cb97dc..25a29f1 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMap.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMap.java
@@ -82,4 +82,9 @@ public interface NCPropertyMap {
      * @return
      */
     Set<String> keysSet();
+
+    /**
+     *
+     */
+    void clear();
 }
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.java 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.java
index c2ca3d1..86bb3d0 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCPropertyMapAdapter.java
@@ -17,13 +17,16 @@
 
 package org.apache.nlpcraft;
 
-import java.util.*;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  *
  */
 public class NCPropertyMapAdapter implements NCPropertyMap {
-    private final Map<String, Object> map = new HashMap<>();
+    private final Map<String, Object> map = new ConcurrentHashMap<>();
 
     @Override
     public <T> T get(String key) {
@@ -64,4 +67,9 @@ public class NCPropertyMapAdapter implements NCPropertyMap {
     public Set<String> keysSet() {
         return map.keySet();
     }
+
+    @Override
+    public void clear() {
+        map.clear();
+    }
 }
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala
 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala
index 1b1d052..bc7c557 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala
@@ -61,13 +61,9 @@ class NCConversationManager(cfg: NCModelConfig) extends 
LazyLogging:
 
         for ((key, value) <- convs)
             if value.tstamp < now - cfg.getConversationTimeout then
-                val data = value.conv.getUserData
-
-                data.synchronized { 
data.keysSet().asScala.foreach(data.remove) }
-
+                value.conv.getUserData.clear()
                 delKeys += key
 
-
         convs --= delKeys
 
         if convs.nonEmpty then convs.values.map(v => v.tstamp + 
v.conv.timeoutMs).min
diff --git 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelClientImpl.scala
 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelClientImpl.scala
index 51fa8af..a4e6d62 100644
--- 
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelClientImpl.scala
+++ 
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelClientImpl.scala
@@ -20,6 +20,7 @@ package org.apache.nlpcraft.internal.impl
 import com.typesafe.scalalogging.LazyLogging
 import org.apache.nlpcraft.*
 import org.apache.nlpcraft.internal.*
+import org.apache.nlpcraft.internal.ascii.NCAsciiTable
 import org.apache.nlpcraft.internal.conversation.*
 import org.apache.nlpcraft.internal.dialogflow.NCDialogFlowManager
 import org.apache.nlpcraft.internal.impl.*
@@ -78,15 +79,19 @@ class NCModelClientImpl(mdl: NCModel) extends LazyLogging:
         dlgMgr.start()
         plMgr.start()
 
-    /**
-      *
+
+     /*
+      * @param txt
       * @param data
+      * @param usrId
       * @return
       */
-    private def ask0(data: NCPipelineData): NCResult =
-        val userId = data.request.getUserId
+    def ask(txt: String, data: JMap[String, AnyRef], usrId: String): NCResult =
+        val plData = plMgr.prepare(txt, data, usrId)
+
+        val userId = plData.request.getUserId
         val convHldr = convMgr.getConversation(userId)
-        val allEnts = data.variants.flatMap(_.getEntities.asScala)
+        val allEnts = plData.variants.flatMap(_.getEntities.asScala)
 
         val conv: NCConversation =
             new NCConversation:
@@ -100,46 +105,82 @@ class NCModelClientImpl(mdl: NCModel) extends LazyLogging:
             new NCContext:
                 override def isOwnerOf(ent: NCEntity): Boolean = 
allEnts.contains(ent)
                 override val getModelConfig: NCModelConfig = mdl.getConfig
-                override val getRequest: NCRequest = data.request
+                override val getRequest: NCRequest = plData.request
                 override val getConversation: NCConversation = conv
-                override val getVariants: util.Collection[NCVariant] = 
data.variants.asJava
-                override val getTokens: JList[NCToken] = data.tokens
+                override val getVariants: util.Collection[NCVariant] = 
plData.variants.asJava
+                override val getTokens: JList[NCToken] = plData.tokens
 
         intentsMgr.solve(NCIntentSolverInput(ctx, mdl))
 
+
     /**
       *
-      * @param txt
-      * @param data
       * @param usrId
-      * @return
       */
-    def ask(txt: String, data: JMap[String, AnyRef], usrId: String): 
CompletableFuture[NCResult] =
-        val fut = new CompletableFuture[NCResult]
-        val check = () => if fut.isCancelled then E(s"Asynchronous ask is 
interrupted [txt=$txt, usrId=$usrId]")
-
-        fut.completeAsync(() => ask0(plMgr.prepare(txt, data, usrId, 
Option(check))))
+    def clearStm(usrId: String): Unit = convMgr.getConversation(usrId).clear(_ 
=> true)
 
     /**
       *
-      * @param txt
-      * @param data
       * @param usrId
-      * @return
+      * @param filter
       */
-    def askSync(txt: String, data: JMap[String, AnyRef], usrId: String): 
NCResult = ask0(plMgr.prepare(txt, data, usrId))
+    def clearStm(usrId: String, filter: Predicate[NCEntity]): Unit = 
convMgr.getConversation(usrId).clear(filter)
 
     /**
       *
       * @param usrId
       */
-    def clearConversation(usrId: String): Unit = 
convMgr.getConversation(usrId).clear(_ => true)
+    def clearDialog(usrId: String): Unit = dlgMgr.clear(usrId)
 
     /**
       *
       * @param usrId
       */
-    def clearDialog(usrId: String): Unit = dlgMgr.clear(usrId)
+    def clearDialog(usrId: String, filter: Predicate[NCDialogFlowItem]): Unit 
= dlgMgr.clear(usrId, (i: NCDialogFlowItem) => filter.test(i))
+
+    /**
+      *
+      */
+    def validateSamples(): Unit =
+        case class Result(intentId: String, text: String, pass: Boolean, 
error: Option[String], time: Long)
+
+        val userId = UUID.randomUUID().toString
+        val results = mutable.ArrayBuffer.empty[Result]
+
+        def now: Long = System.currentTimeMillis()
+
+        for (i <- intents; samples <- i.samples)
+            for (sample <- samples)
+                val t = now
+
+                try
+                    ask(sample, null, userId)
+
+                    results += Result(i.intent.id, sample, true, None, now - t)
+                catch
+                    case e: Throwable =>
+                        results += Result(i.intent.id, sample, true, 
Option(e.getMessage), now - t)
+
+            clearDialog(userId)
+            clearStm(userId)
+
+        val tbl = NCAsciiTable()
+
+        tbl #= ("Intent ID", "+/-", "Text", "Error", "ms.")
+
+        for (res <- results)
+            tbl += (
+                res.intentId,
+                if res.pass then "OK" else "FAIL",
+                res.text,
+                res.error.getOrElse(""),
+                res.time
+            )
+
+        val passCnt = results.count(_.pass)
+        val failCnt = results.count(!_.pass)
+
+        tbl.info(logger, Option(s"Model auto-validation results: OK $passCnt, 
FAIL $failCnt:"))
 
     /**
       *
diff --git 
a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientSpec.scala
 
b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientSpec.scala
index a1e0f78..9563947 100644
--- 
a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientSpec.scala
+++ 
b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientSpec.scala
@@ -33,10 +33,11 @@ class NCModelClientSpec:
       */
     @Test
     def test(): Unit =
-        val mdl =
+        val mdl: NCTestModelAdapter =
             new NCTestModelAdapter():
                 // TODO: doesn't work.
-                //@NCIntent("intent=ls term(act)={has(ent_groups, 'act')} 
term(loc)={# == 'ls:loc'}*")
+                //@NCIntent("intent=ls term(act)={has(ent_groups, 'act')} 
term(loc)={# == 'ls:loc'}*") @NCIntent("intent=locInt term(single)~{# == 'id1'} 
term(list)~{# == 'id2'}[0,10] term(opt)~{# == 'id3'}?")
+                @NCIntentSample(Array("Lights on at second floor kitchen", 
"Invalid sample"))
                 @NCIntent("intent=ls term(act)={# == 'ls:on'} term(loc)={# == 
'ls:loc'}*")
                 def onMatch(@NCIntentTerm("act") act: NCEntity, 
@NCIntentTerm("loc") locs: List[NCEntity]): NCResult =
                     val ncRes = new NCResult()
@@ -54,8 +55,10 @@ class NCModelClientSpec:
         )
 
         Using.resource(new NCModelClient(mdl)) { client =>
-            val res = client.askSync("Lights on at second floor kitchen", 
null, "userId")
+            val res = client.ask("Lights on at second floor kitchen", null, 
"userId")
 
             println(s"Intent: ${res.getIntentId}")
             println(s"Body: ${res.getBody}")
+
+            client.validateSamples()
         }
\ No newline at end of file
diff --git 
a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCSlowPipelineSpec.scala
 
b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCSlowPipelineSpec.scala
deleted file mode 100644
index a03e918..0000000
--- 
a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCSlowPipelineSpec.scala
+++ /dev/null
@@ -1,82 +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
- *
- *      https://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.internal.impl
-
-import org.apache.nlpcraft.*
-import org.apache.nlpcraft.nlp.util.NCTestModelAdapter
-import org.apache.nlpcraft.nlp.util.opennlp.*
-import org.junit.jupiter.api.*
-
-import java.util.List as JList
-import java.util.concurrent.*
-import scala.jdk.CollectionConverters.*
-import scala.util.Using
-
-/**
-  *
-  */
-class NCSlowPipelineSpec:
-    /**
-      *
-      * @param delayMs
-      * @param iterCnt
-      * @return
-      */
-    private def mkSlowModel(delayMs: Long, iterCnt: Int): NCModel =
-        val pipeline = EN_PIPELINE.clone()
-
-        pipeline.getEntityParsers.clear()
-
-        def mkSlowParser(i: Int) =
-            new NCEntityParser:
-                override def parse(req: NCRequest, cfg: NCModelConfig, toks: 
JList[NCToken]): JList[NCEntity] =
-                    println(s"Parser called: $i")
-                    Thread.sleep(delayMs)
-                    java.util.Collections.emptyList()
-
-        (0 until iterCnt).foreach(i => 
pipeline.getEntityParsers.add(mkSlowParser(i)))
-
-        new NCTestModelAdapter:
-            override val getPipeline: NCModelPipeline = pipeline
-    /**
-      *
-      */
-    @Test
-    def testCancel(): Unit =
-        Using.resource(new NCModelClient(mkSlowModel(1, 10000))) { client =>
-            val fut = client.ask("any", null, "userId")
-
-            Thread.sleep(20)
-            require(fut.cancel(true))
-            Thread.sleep(20)
-
-            Assertions.assertThrows(classOf[CancellationException], () => 
fut.get)
-        }
-    /**
-      *
-      */
-    @Test
-    def testTimeout(): Unit =
-        Using.resource(new NCModelClient(mkSlowModel(1, 10000))) { client =>
-            val fut = client.ask("any", null, "userId")
-
-            Thread.sleep(20)
-
-            try Assertions.assertThrows(classOf[TimeoutException], () => 
fut.get(1, TimeUnit.MILLISECONDS))
-            finally fut.cancel(true)
-        }

Reply via email to