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