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 662dcdf WIP.
662dcdf is described below
commit 662dcdf2100fb0be0b9cc3cdd8735a8c11146f2b
Author: Sergey Kamov <[email protected]>
AuthorDate: Fri Feb 18 11:25:40 2022 +0300
WIP.
---
.../scala/org/apache/nlpcraft/NCModelClient.java | 3 +-
.../conversation/NCConversationManager.scala | 73 ++++++++--------
.../internal/dialogflow/NCDialogFlowManager.scala | 98 +++++++++++-----------
.../nlpcraft/internal/impl/NCModelClientImpl.scala | 14 ++--
.../internal/impl/NCModelPipelineManager.scala | 22 +----
.../internal/intent/matcher/NCIntentsManager.scala | 4 +-
.../internal/impl/NCModelClientImplSpec.scala | 6 +-
7 files changed, 100 insertions(+), 120 deletions(-)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java
index fee87cf..9f465c2 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/NCModelClient.java
@@ -25,7 +25,7 @@ import java.util.concurrent.*;
/**
*
*/
-public class NCModelClient {
+public class NCModelClient implements AutoCloseable {
private final NCModelClientImpl impl;
/**
@@ -81,6 +81,7 @@ public class NCModelClient {
/**
*
*/
+ @Override
public void close() {
impl.close();
}
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 cc6ba84..77574da 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
@@ -32,33 +32,24 @@ class NCConversationManager(cfg: NCModelConfig) extends
LazyLogging:
private final val convs: mutable.Map[String, Value] =
mutable.HashMap.empty[String, Value]
@volatile private var gc: Thread = _
- /**
- *
- * @return
- */
- def start(): Unit =
- gc = NCUtils.mkThread("conv-mgr-gc", cfg.getId) { t =>
- while (!t.isInterrupted)
- try
- convs.synchronized {
- val sleepTime = clearForTimeout() - NCUtils.now()
- if sleepTime > 0 then
- logger.trace(s"${t.getName} waits for $sleepTime
ms.")
- convs.wait(sleepTime)
- }
- catch
- case _: InterruptedException => // No-op.
- case e: Throwable => logger.error(s"Unexpected error for
thread: ${t.getName}", e)
- }
- gc.start()
/**
+ * Gets conversation for given user ID.
*
+ * @param usrId User ID.
+ * @return New or existing conversation.
*/
- def close(): Unit =
- NCUtils.stopThread(gc)
- gc = null
- convs.clear()
+ def getConversation(usrId: String): NCConversationHolder =
+ convs.synchronized {
+ val v = convs.getOrElseUpdate(
+ usrId,
+ Value(NCConversationHolder(usrId, cfg.getId,
cfg.getConversationTimeout, cfg.getConversationDepth))
+ )
+
+ v.tstamp = NCUtils.nowUtcMs()
+ convs.notifyAll()
+ v.conv
+ }
/**
* Gets next clearing time.
@@ -84,19 +75,29 @@ class NCConversationManager(cfg: NCModelConfig) extends
LazyLogging:
else Long.MaxValue
/**
- * Gets conversation for given user ID.
*
- * @param usrId User ID.
- * @return New or existing conversation.
+ * @return
*/
- def getConversation(usrId: String): NCConversationHolder =
- convs.synchronized {
- val v = convs.getOrElseUpdate(
- usrId,
- Value(NCConversationHolder(usrId, cfg.getId,
cfg.getConversationTimeout, cfg.getConversationDepth))
- )
-
- v.tstamp = NCUtils.nowUtcMs()
- convs.notifyAll()
- v.conv
+ def start(): Unit =
+ gc = NCUtils.mkThread("conv-mgr-gc", cfg.getId) { t =>
+ while (!t.isInterrupted)
+ try
+ convs.synchronized {
+ val sleepTime = clearForTimeout() - NCUtils.now()
+ if sleepTime > 0 then
+ logger.trace(s"${t.getName} waits for $sleepTime
ms.")
+ convs.wait(sleepTime)
+ }
+ catch
+ case _: InterruptedException => // No-op.
+ case e: Throwable => logger.error(s"Unexpected error for
thread: ${t.getName}", e)
}
+ gc.start()
+
+ /**
+ *
+ */
+ def close(): Unit =
+ NCUtils.stopThread(gc)
+ gc = null
+ convs.clear()
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/dialogflow/NCDialogFlowManager.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/dialogflow/NCDialogFlowManager.scala
index 7181c17..1026e3d 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/dialogflow/NCDialogFlowManager.scala
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/dialogflow/NCDialogFlowManager.scala
@@ -39,6 +39,31 @@ class NCDialogFlowManager(cfg: NCModelConfig) extends
LazyLogging:
@volatile private var gc: Thread = _
/**
+ * Gets next clearing time.
+ */
+ private def clearForTimeout(): Long =
+ require(Thread.holdsLock(flow))
+
+ val timeout = cfg.getConversationTimeout
+ val bound = NCUtils.now() - timeout
+ var next = Long.MaxValue
+
+ val delKeys = mutable.ArrayBuffer.empty[String]
+
+ for ((usrId, values) <- flow)
+ values --= values.filter(_.getRequest.getReceiveTimestamp < bound)
+
+ if values.nonEmpty then
+ val candidate =
values.map(_.getRequest.getReceiveTimestamp).min + timeout
+ if next > candidate then next = candidate
+ else
+ delKeys += usrId
+
+ if delKeys.nonEmpty then flow --= delKeys
+
+ next
+
+ /**
*
* @return
*/
@@ -60,20 +85,20 @@ class NCDialogFlowManager(cfg: NCModelConfig) extends
LazyLogging:
gc.start()
/**
- *
- */
+ *
+ */
def close(): Unit =
NCUtils.stopThread(gc)
gc = null
flow.clear()
/**
- * Adds matched (winning) intent to the dialog flow.
- *
- * @param intentMatch
- * @param res Intent callback result.
- * @param ctx Original query context.
- */
+ * Adds matched (winning) intent to the dialog flow.
+ *
+ * @param intentMatch
+ * @param res Intent callback result.
+ * @param ctx Original query context.
+ */
def addMatchedIntent(intentMatch: NCIntentMatch, res: NCResult, ctx:
NCContext): Unit =
val item: NCDialogFlowItem = new NCDialogFlowItem:
override val getIntentMatch: NCIntentMatch = intentMatch
@@ -97,10 +122,10 @@ class NCDialogFlowManager(cfg: NCModelConfig) extends
LazyLogging:
case None => Seq.empty
/**
- * Prints out ASCII table for current dialog flow.
- *
- * @param usrId User ID.
- */
+ * Prints out ASCII table for current dialog flow.
+ *
+ * @param usrId User ID.
+ */
def ack(usrId: String): Unit =
val tbl = NCAsciiTable(
"#",
@@ -123,35 +148,10 @@ class NCDialogFlowManager(cfg: NCModelConfig) extends
LazyLogging:
logger.info(s"""Current dialog flow (oldest first) for
[mdlId=${cfg.getId}, usrId=$usrId]\n${tbl.toString()}""")
/**
- * Gets next clearing time.
- */
- private def clearForTimeout(): Long =
- require(Thread.holdsLock(flow))
-
- val timeout = cfg.getConversationTimeout
- val bound = NCUtils.now() - timeout
- var next = Long.MaxValue
-
- val delKeys = mutable.ArrayBuffer.empty[String]
-
- for ((usrId, values) <- flow)
- values --= values.filter(_.getRequest.getReceiveTimestamp < bound)
-
- if values.nonEmpty then
- val candidate =
values.map(_.getRequest.getReceiveTimestamp).min + timeout
- if next > candidate then next = candidate
- else
- delKeys += usrId
-
- if delKeys.nonEmpty then flow --= delKeys
-
- next
-
- /**
- * Clears dialog history for given user ID.
- *
- * @param usrId User ID.
- */
+ * Clears dialog history for given user ID.
+ *
+ * @param usrId User ID.
+ */
def clear(usrId: String): Unit =
flow.synchronized {
flow -= usrId
@@ -159,15 +159,15 @@ class NCDialogFlowManager(cfg: NCModelConfig) extends
LazyLogging:
}
/**
- * Clears dialog history for given user ID and predicate.
- *
- * @param usrId User ID.
- * @param mdlId Model ID.
- * @param pred Intent ID predicate.
- * @param parent Parent span, if any.
- */
+ * Clears dialog history for given user ID and predicate.
+ *
+ * @param usrId User ID.
+ * @param mdlId Model ID.
+ * @param pred Intent ID predicate.
+ * @param parent Parent span, if any.
+ */
def clearForPredicate(usrId: String, pred: String => Boolean): Unit =
flow.synchronized {
flow(usrId) = flow(usrId).filterNot(v =>
pred(v.getIntentMatch.getIntentId))
flow.notifyAll()
- }
\ No newline at end of file
+ }
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 541e8e0..2666a8b 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
@@ -55,12 +55,11 @@ import scala.jdk.CollectionConverters.*
class NCModelClientImpl(mdl: NCModel) extends LazyLogging:
verify()
- private val mdlIntents = NCModelScanner.scan(mdl)
-
+ private val intents = NCModelScanner.scan(mdl)
private val pipelineMgr = new NCModelPipelineManager(mdl.getConfig,
mdl.getPipeline)
private val convMgr = NCConversationManager(mdl.getConfig)
private val dialogMgr = NCDialogFlowManager(mdl.getConfig)
- private val intentsMgr = NCIntentsManager(dialogMgr, mdlIntents.map(p =>
p.intent -> p.function).toMap)
+ private val intentsMgr = NCIntentsManager(dialogMgr, intents.map(p =>
p.intent -> p.function).toMap)
/**
*
@@ -78,6 +77,7 @@ class NCModelClientImpl(mdl: NCModel) extends LazyLogging:
Objects.requireNonNull(cfg.getVersion, "Model version cannot be null.")
Objects.requireNonNull(pipeline.getTokenParser, "Token parser cannot
be null.")
Objects.requireNonNull(pipeline.getEntityParsers, "List of entity
parsers in the pipeline cannot be null.")
+
if pipeline.getEntityParsers.isEmpty then E(s"At least one entity
parser must be specified in the pipeline.")
/**
@@ -85,7 +85,7 @@ class NCModelClientImpl(mdl: NCModel) extends LazyLogging:
* @param data
* @return
*/
- private def matchVariants(data: NCPipelineVariants): NCResult =
+ private def ask0(data: NCPipelineVariants): NCResult =
val userId = data.request.getUserId
val convHldr = convMgr.getConversation(userId)
val allEnts = data.variants.flatMap(_.getEntities.asScala)
@@ -121,9 +121,7 @@ class NCModelClientImpl(mdl: NCModel) extends LazyLogging:
val check = () => if fut.isCancelled then
E(s"Asynchronous ask is interrupted [txt=$txt, usrId=$usrId]")
- fut.completeAsync(() => matchVariants(pipelineMgr.prepare(txt, data,
usrId, Option(check))))
-
-
+ fut.completeAsync(() => ask0(pipelineMgr.prepare(txt, data, usrId,
Option(check))))
/**
*
@@ -133,7 +131,7 @@ class NCModelClientImpl(mdl: NCModel) extends LazyLogging:
* @return
*/
def askSync(txt: String, data: JMap[String, AnyRef], usrId: String):
NCResult =
- matchVariants(pipelineMgr.prepare(txt, data, usrId))
+ ask0(pipelineMgr.prepare(txt, data, usrId))
/**
*
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala
index d56c04e..d2758c9 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala
@@ -59,31 +59,11 @@ class NCModelPipelineManager(cfg: NCModelConfig, pipeline:
NCModelPipeline) exte
private val entVals = nvl(pipeline.getEntityValidators)
private val varFilterOpt = pipeline.getVariantFilter.toScala
- private var allSrvs: Seq[NCLifecycle] =
+ private val allSrvs: Seq[NCLifecycle] =
tokEnrichers ++ entEnrichers ++ entParsers ++ tokVals ++ entVals ++
varFilterOpt.toSeq
processServices(_.onStart(cfg), "started")
- /**
- *
- * @param cfg
- * @param pipeline
- */
- private def init(): Unit =
- val buf = mutable.ArrayBuffer.empty[NCLifecycle] ++
pipeline.getEntityParsers.asScala
-
- def add[T <: NCLifecycle](list: JList[T]): Unit = if list != null then
buf ++= list.asScala
-
- add(pipeline.getTokenEnrichers)
- add(pipeline.getTokenValidators)
- add(pipeline.getEntityEnrichers)
- add(pipeline.getEntityParsers)
- add(pipeline.getEntityValidators)
- if pipeline.getVariantFilter.isPresent then
add(JColls.singletonList(pipeline.getVariantFilter.get()))
-
- allSrvs = buf.toSeq
-
- processServices(_.onStart(cfg), "started")
/**
*
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/matcher/NCIntentsManager.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/matcher/NCIntentsManager.scala
index 37525e5..6f4bd88 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/matcher/NCIntentsManager.scala
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/intent/matcher/NCIntentsManager.scala
@@ -278,7 +278,7 @@ class NCIntentsManager(dialog: NCDialogFlowManager,
intents: Map[NCIDLIntent, NC
var entIdx = 0
for (e <- grp.usedEntities)
val conv = if e.conv then "(conv) " else ""
- ents += s" #$entIdx: $conv${e.entity}"
+ ents += s" #$entIdx:
$conv${e.entity.getId}(${e.entity.mkText()})"
entIdx += 1
else
ents += " <empty>"
@@ -587,11 +587,9 @@ class NCIntentsManager(dialog: NCDialogFlowManager,
intents: Map[NCIDLIntent, NC
private var stopped: Boolean = false
def hasNext: Boolean = !stopped
-
def finish(data: Option[NCResult]): Unit =
Loop.data = Option(data)
Loop.stopped = true
-
def result: Option[NCResult] = data.getOrElse(throw new
NCRejection("No matching intent found - all intents were skipped."))
for (intentRes <- intentResults.filter(_ != null) if Loop.hasNext)
diff --git
a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientImplSpec.scala
b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientImplSpec.scala
index 9d09503..fee87e9 100644
---
a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientImplSpec.scala
+++
b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/impl/NCModelClientImplSpec.scala
@@ -56,8 +56,10 @@ class NCModelClientImplSpec:
val res = client.askSync("Lights on at second floor kitchen", null,
"userId")
- println(res.getIntentId)
- println(res.getBody)
+ println(s"Intent: ${res.getIntentId}")
+ println(s"Body: ${res.getBody}")
+
+ client.close()