You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nlpcraft.apache.org by ar...@apache.org on 2021/03/04 06:02:32 UTC
[incubator-nlpcraft] branch NLPCRAFT-206 updated: WIP (does NOT
compile).
This is an automated email from the ASF dual-hosted git repository.
aradzinski pushed a commit to branch NLPCRAFT-206
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
The following commit(s) were added to refs/heads/NLPCRAFT-206 by this push:
new e00d7ff WIP (does NOT compile).
e00d7ff is described below
commit e00d7fff40914acf9a6cdbd2220c5378fb29cc9a
Author: Aaron Radzinzski <ar...@datalingvo.com>
AuthorDate: Wed Mar 3 22:02:22 2021 -0800
WIP (does NOT compile).
---
.../apache/nlpcraft/model/NCDialogFlowItem.java | 26 +-
.../scala/org/apache/nlpcraft/model/NCRequest.java | 2 +-
.../impl/{ver2 => }/NCIntentDslBaselCompiler.scala | 9 +-
.../model/intent/impl/NCIntentDslCompiler.scala | 652 ++++++++++++---------
.../impl/{ver2 => }/NCIntentDslFragmentCache.scala | 4 +-
.../model/intent/impl/NCIntentSolverEngine.scala | 26 +-
.../intent/impl/ver2/NCIntentDslCompiler.scala | 485 ---------------
.../intent/utils/{ver2 => }/NCDslFragment.scala | 2 +-
.../nlpcraft/model/intent/utils/NCDslIntent.scala | 65 +-
.../nlpcraft/model/intent/utils/NCDslTerm.java | 131 -----
.../model/intent/utils/{ver2 => }/NCDslTerm.scala | 2 +-
.../intent/utils/{ver2 => }/NCDslTermContext.scala | 2 +-
.../intent/utils/{ver2 => }/NCDslTermRetVal.scala | 2 +-
.../model/intent/utils/ver2/NCDslIntent.scala | 55 --
.../mgrs/dialogflow/NCDialogFlowManager.scala | 18 +-
.../probe/mgrs/nlp/NCProbeEnrichmentManager.scala | 2 +-
.../model/intent/dsl/NCIntentDslCompilerSpec.scala | 3 +-
17 files changed, 453 insertions(+), 1033 deletions(-)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java
index a32ba76..a08bbf3 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCDialogFlowItem.java
@@ -21,8 +21,8 @@ import java.util.*;
/**
* An item of the dialog flow. Dialog flow is a chronologically ordered list of dialog flow
- * items. Each item represents a snapshot of winning intent's match data. An instance of this interface
- * is passed into user-defined dialog flow match method.
+ * items. Each item represents a snapshot of winning intent's match and its associated data. An instance
+ * of this interface is passed into a custom user-defined dialog flow match method.
* <p>
* Read full documentation in <a target=_ href="https://nlpcraft.apache.org/intent-matching.html">Intent Matching</a> section and review
* <a target=_ href="https://github.com/apache/incubator-nlpcraft/tree/master/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/">examples</a>.
@@ -78,12 +78,12 @@ public interface NCDialogFlowItem {
List<NCToken> getTermTokens(String termId);
/**
- * Gets sentence parsing variant that produced the matching for this intent. Returned variant is one of the
+ * Gets sentence parsing variant that produced the matching for the winning intent. Returned variant is one of the
* variants provided by {@link NCContext#getVariants()} methods. Note that tokens returned by this method are
* a superset of the tokens returned by {@link #getIntentTokens()} method, i.e. not all tokens
* from this variant may have been used in matching of the winning intent.
*
- * @return Sentence parsing variant that produced the matching for this intent.
+ * @return Sentence parsing variant that produced the matching for the winning intent.
* @see #getIntentTokens()
*/
NCVariant getVariant();
@@ -92,12 +92,10 @@ public interface NCDialogFlowItem {
* Indicates whether or not the intent match was ambiguous (not exact).
* <p>
* An exact match means that for the intent to match it has to use all non-free word tokens
- * in the user input, i.e. only free word tokens can be left after the match. An ambiguous match
+ * in the user input, i.e. only free word tokens can be left unused after the match. An ambiguous match
* doesn't have this restriction. Note that an ambiguous match should be used with a great care.
* An ambiguous match completely ignores extra found user or system tokens (which are not part
* of the intent template) which could have altered the matching outcome had they been considered.
- * <p>
- * Intent callbacks that check this property should always provide custom rejection message.
*
* @return {@code True} if the intent match was exact, {@code false} otherwise.
*/
@@ -120,7 +118,7 @@ public interface NCDialogFlowItem {
/**
* Gets globally unique server ID of the input request.
* <p>
- * Server request is defined as a processing of a one user input request (a session).
+ * Server request is defined as a processing of a one user input request.
* Note that the model can be accessed multiple times during processing of a single user request
* and therefore multiple instances of this interface can return the same server
* request ID. In fact, users of this interfaces can use this fact by using this ID,
@@ -138,29 +136,29 @@ public interface NCDialogFlowItem {
String getNormalizedText();
/**
- * Gets UTC/GMT timestamp in ms when user input was received.
+ * Gets UTC/GMT timestamp in milliseconds when user input was received.
*
- * @return UTC/GMT timestamp in ms when user input was received.
+ * @return UTC/GMT timestamp in milliseconds when user input was received.
*/
long getReceiveTimestamp();
/**
- * Gets optional address of the remote client.
+ * Gets optional address of the remote client that made the initial REST request.
*
* @return Optional address of the remote client.
*/
Optional<String> getRemoteAddress();
/**
- * Gets string representation of the user client agent that made the call with
- * this request.
+ * Gets string representation of the user client agent that made the initial REST
+ * request .
*
* @return User agent string from user client (web browser, REST client, etc.).
*/
Optional<String> getClientAgent();
/**
- * Gets optional JSON data passed in with the user request.
+ * Gets optional JSON data passed in with the initial REST request.
*
* @return Optional JSON data.
*/
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java
index ebca5f2..74d16ee 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/NCRequest.java
@@ -42,7 +42,7 @@ public interface NCRequest {
/**
* Gets globally unique server ID of the current request.
* <p>
- * Server request is defined as a processing of a one user input request (a session).
+ * Server request is defined as a processing of a one user input request.
* Note that the model can be accessed multiple times during processing of a single user request
* and therefore multiple instances of this interface can return the same server
* request ID. In fact, users of this interfaces can use this fact by using this ID,
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslBaselCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslBaselCompiler.scala
similarity index 99%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslBaselCompiler.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslBaselCompiler.scala
index 794ad1e..16db816 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslBaselCompiler.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslBaselCompiler.scala
@@ -15,14 +15,15 @@
* limitations under the License.
*/
-package org.apache.nlpcraft.model.intent.impl.ver2
+package org.apache.nlpcraft.model.intent.impl
-import org.antlr.v4.runtime.{ParserRuleContext ⇒ PRC}
import org.antlr.v4.runtime.tree.{TerminalNode ⇒ TN}
+import org.antlr.v4.runtime.{ParserRuleContext ⇒ PRC}
import org.apache.commons.lang3.StringUtils
-import org.apache.nlpcraft.model.NCToken
-import org.apache.nlpcraft.model.intent.utils.ver2.{NCDslTermContext, NCDslTermRetVal}
import org.apache.nlpcraft.common._
+import org.apache.nlpcraft.model.NCToken
+import org.apache.nlpcraft.model.intent.utils.{NCDslTermContext, NCDslTermRetVal}
+import org.apache.nlpcraft.model.intent.utils.ver2.NCDslTermRetVal
import java.lang.{Double ⇒ JDouble, Long ⇒ JLong}
import java.time.LocalDate
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala
index 47d1c76..9aae4c8 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslCompiler.scala
@@ -19,68 +19,82 @@ package org.apache.nlpcraft.model.intent.impl
import com.typesafe.scalalogging.LazyLogging
import org.antlr.v4.runtime._
-import org.antlr.v4.runtime.tree._
-import org.apache.nlpcraft.model.NCToken
-import org.apache.nlpcraft.model.intent.impl.antlr4.{NCIntentDslBaseListener, NCIntentDslLexer, NCIntentDslParser}
-import org.apache.nlpcraft.model.intent.utils.{NCDslIntent, NCDslTerm}
+import org.antlr.v4.runtime.tree.ParseTreeWalker
import org.apache.nlpcraft.common._
+import org.apache.nlpcraft.model._
+import org.apache.nlpcraft.model.intent.impl.antlr4.{NCIntentDslParser ⇒ IDP, _}
+import org.apache.nlpcraft.model.intent.impl.{NCIntentDslFragmentCache ⇒ FragCache}
+import org.apache.nlpcraft.model.intent.utils._
+import java.nio.file.Path
+import java.util.Optional
+import java.util.regex.{Pattern, PatternSyntaxException}
import scala.collection.JavaConverters._
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
-/**
- * Intent DSL compiler.
- */
object NCIntentDslCompiler extends LazyLogging {
// Compiler cache.
- private val cache = new java.util.concurrent.ConcurrentHashMap[String, NCDslIntent]().asScala
-
- private var mdlId: String = _
-
+ private val cache = new mutable.HashMap[String, Set[NCDslIntent]]
+
/**
- *
- */
- class FiniteStateMachine extends NCIntentDslBaseListener {
+ *
+ * @param dsl
+ * @param mdlId
+ */
+ class FiniteStateMachine(dsl: String, mdlId: String) extends NCIntentDslBaseListener with NCIntentDslBaselCompiler {
+ // Accumulator for parsed intents.
+ private val intents = ArrayBuffer.empty[NCDslIntent]
+
+ // Fragment components.
+ private var fragId: String = _
+ private var fragMeta: Map[String, Any] = _
+
// Intent components.
+ private var intentId: String = _
private var ordered: Boolean = false
- private var id: String = _
- private val terms = ArrayBuffer.empty[NCDslTerm] // Accumulator for parsed terms.
private var flowRegex: Option[String] = None
+ private var intentMeta: Map[String, Any] = _
+
+ // Accumulator for parsed terms.
+ private val terms = ArrayBuffer.empty[NCDslTerm]
// Currently term.
private var termId: String = _
private var termConv: Boolean = _
private var min = 1
private var max = 1
-
- private val predStack = new mutable.ArrayStack[NCToken ⇒ Boolean] // Stack of predicates.
- private val lvalParts = ArrayBuffer.empty[String] // lval parts collector.
- private val rvalList = ArrayBuffer.empty[String] // rval list collector.
- private var rval: String = _
-
- /**
- *
- * @return
- */
- def getBuiltIntent: NCDslIntent = {
- require(id != null)
- require(terms.nonEmpty)
-
- NCDslIntent(id, ordered, flowRegex, terms.toArray)
- }
-
+
+ // Current method reference.
+ private var refClsName: Option[String] = None
+ private var refMtdName: Option[String] = None
+
+ // Current term's code, i.e. list of instructions.
+ private var termInstrs = mutable.Buffer.empty[Instr]
+
+ /*
+ * Shared/common implementation.
+ */
+ override def exitUnaryExpr(ctx: IDP.UnaryExprContext): Unit = termInstrs += parseUnaryExpr(ctx.MINUS(), ctx.NOT())(ctx)
+ override def exitMultExpr(ctx: IDP.MultExprContext): Unit = termInstrs += parseMultExpr(ctx.MULT(), ctx.MOD(), ctx.DIV())(ctx)
+ override def exitPlusExpr(ctx: IDP.PlusExprContext): Unit = termInstrs += parsePlusExpr(ctx.PLUS(), ctx.MINUS())(ctx)
+ override def exitCompExpr(ctx: IDP.CompExprContext): Unit = termInstrs += parseCompExpr(ctx.LT(), ctx.GT(), ctx.LTEQ(), ctx.GTEQ())(ctx)
+ override def exitLogExpr(ctx: IDP.LogExprContext): Unit = termInstrs += parseLogExpr(ctx.AND, ctx.OR())(ctx)
+ override def exitEqExpr(ctx: IDP.EqExprContext): Unit = termInstrs += parseEqExpr(ctx.EQ, ctx.NEQ())(ctx)
+ override def exitCallExpr(ctx: IDP.CallExprContext): Unit = termInstrs += parseCallExpr(ctx.FUN_NAME())(ctx)
+ override def exitAtom(ctx: IDP.AtomContext): Unit = termInstrs += parseAtom(ctx.getText)(ctx)
+
/**
- *
- * @param min
- * @param max
- */
+ *
+ * @param min
+ * @param max
+ */
private def setMinMax(min: Int, max: Int): Unit = {
this.min = min
this.max = max
}
-
- override def exitMinMaxShortcut(ctx: NCIntentDslParser.MinMaxShortcutContext): Unit = {
+
+ override def exitMinMaxShortcut(ctx: IDP.MinMaxShortcutContext): Unit = {
if (ctx.PLUS() != null)
setMinMax(1, Integer.MAX_VALUE)
else if (ctx.MULT() != null)
@@ -91,22 +105,10 @@ object NCIntentDslCompiler extends LazyLogging {
assert(false)
}
-// override def exitLvalPart(ctx: NCIntentDslParser.LvalPartContext): Unit = {
-// lvalParts += ctx.ID().getText.trim()
-// }
-
- override def exitTermId(ctx: NCIntentDslParser.TermIdContext): Unit = {
- termId = ctx.id().getText.trim
- }
-
- override def exitTermEq(ctx: NCIntentDslParser.TermEqContext): Unit = {
- termConv = ctx.TILDA() != null
- }
-
- override def exitMinMaxRange(ctx: NCIntentDslParser.MinMaxRangeContext): Unit = {
+ override def exitMinMaxRange(ctx: IDP.MinMaxRangeContext): Unit = {
val minStr = ctx.getChild(1).getText.trim
val maxStr = ctx.getChild(3).getText.trim
-
+
try
setMinMax(java.lang.Integer.parseInt(minStr), java.lang.Integer.parseInt(maxStr))
catch {
@@ -115,261 +117,369 @@ object NCIntentDslCompiler extends LazyLogging {
}
}
- override def exitFlowDecl(ctx: NCIntentDslParser.FlowDeclContext): Unit = {
- val qRegex = ctx.qstring().getText.trim
-
- if (qRegex != null && qRegex.length > 2) {
- val regex = qRegex.substring(1, qRegex.length - 1).strip // Remove single quotes.
+ override def exitMtdRef(ctx: IDP.MtdRefContext): Unit = {
+ if (ctx.javaFqn() != null)
+ refClsName = Some(ctx.javaFqn().getText)
- flowRegex = if (regex.nonEmpty) Some(regex) else None
- }
+ refMtdName = Some(ctx.id().getText)
}
- override def exitIntentId(ctx: NCIntentDslParser.IntentIdContext): Unit = {
- id = ctx.id().getText.trim
+ override def exitTermId(ctx: IDP.TermIdContext): Unit = {
+ termId = ctx.id().getText
+
+ if (terms.exists(t ⇒ t.id != null && t.id == termId))
+ throw newSyntaxError(s"Duplicate term ID: $termId")(ctx.id())
}
- override def exitOrderedDecl(ctx: NCIntentDslParser.OrderedDeclContext): Unit = {
- ordered = ctx.BOOL().getText.strip == "true"
+ override def exitIntentId(ctx: IDP.IntentIdContext): Unit = {
+ intentId = ctx.id().getText
+
+ if (intents.exists(i ⇒ i.id != null && i.id == intentId))
+ throw newSyntaxError(s"Duplicate intent ID: $intentId")(ctx.id())
}
- override def exitTerm(ctx: NCIntentDslParser.TermContext): Unit = {
- require(predStack.size == 1)
-
- val p = predStack.pop
-
- terms += new NCDslTerm(
+ override def exitFragId(ctx: IDP.FragIdContext): Unit = {
+ fragId = ctx.id().getText
+
+ if (FragCache.get(mdlId, fragId).isDefined)
+ throw newSyntaxError(s"Duplicate fragment ID: $fragId")(ctx.id())
+ }
+
+ override def exitTermEq(ctx: IDP.TermEqContext): Unit = termConv = ctx.TILDA() != null
+ override def exitFragMeta(ctx: IDP.FragMetaContext): Unit = fragMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
+ override def exitMetaDecl(ctx: IDP.MetaDeclContext): Unit = intentMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
+ override def exitOrderedDecl(ctx: IDP.OrderedDeclContext): Unit = ordered = ctx.BOOL().getText == "true"
+
+ override def exitFragRef(ctx: IDP.FragRefContext): Unit = {
+ val id = ctx.id().getText
+
+ FragCache.get(mdlId, id) match {
+ case Some(frag) ⇒
+ val meta = if (fragMeta == null) Map.empty[String, Any] else fragMeta
+
+ for (fragTerm ← frag.terms)
+ if (terms.exists(t ⇒ t.id != null && t.id == fragTerm.id))
+ throw newSyntaxError(s"Duplicate term ID '${fragTerm.id}' in fragment '$id'.")(ctx.id())
+ else
+ terms += fragTerm.cloneWithMeta(meta)
+
+ case None ⇒ throw newSyntaxError(s"Unknown intent fragment ID: $id")(ctx.id())
+ }
+
+ fragMeta = null
+ }
+
+ override def exitFlowDecl(ctx: IDP.FlowDeclContext): Unit = {
+ implicit val evidence: ParserRuleContext = ctx
+
+ if (ctx.qstring() != null) {
+ val regex = ctx.qstring().getText
+
+ if (regex != null && regex.length > 2)
+ flowRegex = if (regex.nonEmpty) Some(regex) else None
+
+ if (flowRegex.isDefined) // Pre-check.
+ try
+ Pattern.compile(flowRegex.get)
+ catch {
+ case e: PatternSyntaxException ⇒
+ newSyntaxError(s"${e.getDescription} in intent flow regex '${e.getPattern}' near index ${e.getIndex}.")(ctx.qstring())
+ }
+ }
+ }
+
+ override def exitTerm(ctx: IDP.TermContext): Unit = {
+ implicit val c: ParserRuleContext = ctx
+
+ if (min < 0 || min > max)
+ throw newSyntaxError(s"Invalid intent term min quantifiers: $min (must be min >= 0 && min <= max).")(ctx.minMax())
+ if (max < 1)
+ throw newSyntaxError(s"Invalid intent term max quantifiers: $max (must be max >= 1).")(ctx.minMax())
+
+ val pred =
+ if (refMtdName != null) { // User-code defined term.
+ // Closure copies.
+ val clsName = refClsName.orNull
+ val mtdName = refMtdName.orNull
+
+ (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
+ val javaCtx: NCTokenPredicateContext = new NCTokenPredicateContext {
+ override lazy val getRequest: NCRequest = termCtx.req
+ override lazy val getToken: NCToken = tok
+ override lazy val getIntentMeta: Optional[NCMetadata] =
+ if (termCtx.intentMeta != null)
+ Optional.of(NCMetadata.apply(termCtx.intentMeta.asJava))
+ else
+ Optional.empty()
+ }
+
+ val mdl = tok.getModel
+ val mdlCls = if (clsName == null) mdl.meta[String](MDL_META_MODEL_CLASS_KEY) else clsName
+
+ try {
+ val obj = if (clsName == null) mdl else U.mkObject(clsName)
+ val mtd = Thread.currentThread().getContextClassLoader.loadClass(mdlCls)
+ .getMethod(mtdName, classOf[NCTokenPredicateContext])
+
+ var flag = mtd.canAccess(mdl)
+
+ val res = try {
+ if (!flag) {
+ mtd.setAccessible(true)
+
+ flag = true
+ }
+ else
+ flag = false
+
+ mtd.invoke(obj, javaCtx).asInstanceOf[NCTokenPredicateResult]
+ }
+ finally {
+ if (flag)
+ try
+ mtd.setAccessible(false)
+ catch {
+ case e: SecurityException ⇒
+ throw new NCE(s"Access or security error in custom intent term: $mdlCls.$mtdName", e)
+ }
+ }
+
+ (res.getResult, res.wasTokenUsed())
+ }
+ catch {
+ case e: Exception ⇒
+ throw newRuntimeError(s"Failed to invoke custom intent term: $mdlCls.$mtdName", e)
+ }
+ }
+ }
+ else { // DSL-defined term.
+ val instrs = mutable.Buffer.empty[Instr]
+
+ instrs ++= termInstrs
+
+ (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
+ val stack = new mutable.ArrayStack[NCDslTermRetVal]()
+
+ // Execute all instructions.
+ instrs.foreach(_(tok, stack, termCtx))
+
+ // Pop final result from stack.
+ val x = stack.pop()
+
+ if (!isBoolean(x.retVal))
+ throw newRuntimeError(s"Intent term does not return boolean value: ${ctx.getText}")
+
+ (asBool(x.retVal), x.usedTok)
+ }
+
+ }
+
+ // Add term.
+ terms += NCDslTerm(
termId,
- new java.util.function.Function[NCToken, java.lang.Boolean]() {
- override def apply(tok: NCToken): java.lang.Boolean = p.apply(tok)
- override def toString: String = p.toString().strip //ctx.item().getText
- },
+ pred,
min,
max,
- termConv)
-
- // Reset.
- termId = null
+ termConv
+ )
+
+ // Reset term vars.
setMinMax(1, 1)
+ termId = null
+ termInstrs.clear()
+ refClsName = None
+ refMtdName = None
}
-
-// override def exitRvalSingle(ctx: NCIntentDslParser.RvalSingleContext): Unit = {
-// rval = ctx.getText.trim()
-// }
-
-// override def exitRvalList(ctx: NCIntentDslParser.RvalListContext): Unit = {
-// rvalList += rval
-// }
-
-// override def exitItem(ctx: NCIntentDslParser.ItemContext): Unit = {
-// if (ctx.EXCL() != null) {
-// val p = predStack.pop
-//
-// predStack.push(new Function[NCToken, Boolean] {
-// override def apply(tok: NCToken): Boolean = !p.apply(tok)
-// override def toString: String = s"!$p"
-// })
-// }
-// else if (ctx.AND() != null) {
-// // Note that stack is LIFO so order is flipped.
-// val p2 = predStack.pop
-// val p1 = predStack.pop
-//
-// predStack.push(new Function[NCToken, Boolean] {
-// override def apply(tok: NCToken): Boolean = {
-// // To bypass any possible compiler optimizations.
-// if (!p1.apply(tok))
-// false
-// else if (!p2.apply(tok))
-// false
-// else
-// true
-// }
-// override def toString: String = s"$p1 && $p2"
-// })
-// }
-// else if (ctx.OR() != null) {
-// // Note that stack is LIFO so order is flipped.
-// val p2 = predStack.pop
-// val p1 = predStack.pop
-//
-// predStack.push(new Function[NCToken, Boolean] {
-// override def apply(tok: NCToken): Boolean = {
-// // To bypass any possible compiler optimizations.
-// if (p1.apply(tok))
-// true
-// else if (p2.apply(tok))
-// true
-// else
-// false
-// }
-// override def toString: String = s"$p1 || $p2"
-// })
-// }
-// else if (ctx.RPAREN() != null && ctx.LPAREN() != null) {
-// val p = predStack.pop
-//
-// predStack.push(new Function[NCToken, Boolean] {
-// override def apply(tok: NCToken): Boolean = p.apply(tok)
-// override def toString: String = s"($p)"
-// })
-// }
-//
-// // In all other cases the current predicate is already on the top of the stack.
-// }
-
+
+ override def exitFrag(ctx: IDP.FragContext): Unit = {
+ FragCache.add(mdlId, NCDslFragment(fragId, terms.toList))
+
+ terms.clear()
+ }
+
+ override def exitIntent(ctx: IDP.IntentContext): Unit = {
+ intents += NCDslIntent(
+ dsl,
+ intentId,
+ ordered,
+ if (intentMeta == null) Map.empty else intentMeta,
+ flowRegex,
+ refClsName,
+ refMtdName,
+ terms.toList
+ )
+
+ refClsName = None
+ refMtdName = None
+ intentMeta = null
+ terms.clear()
+ }
+
/**
*
- * @param rv
* @return
*/
- private def mkRvalObject(rv: String): Any = {
- if (rv == "null") null // Try 'null'.
- else if (rv == "true") true // Try 'boolean'.
- else if (rv == "false") false // Try 'boolean'.
- // Only numeric values below...
- else {
- // Strip '_' from numeric values.
- val rvalNum = rv.replaceAll("_", "")
-
- try
- java.lang.Integer.parseInt(rvalNum) // Try 'int'.
- catch {
- case _: NumberFormatException ⇒
- try
- java.lang.Long.parseLong(rvalNum) // Try 'long'.
- catch {
- case _: NumberFormatException ⇒
- try
- java.lang.Double.parseDouble(rvalNum) // Try 'double'.
- catch {
- case _: NumberFormatException ⇒ rv // String by default.
- }
- }
- }
- }
- }
-
-// override def exitPredicate(ctx: NCIntentDslParser.PredicateContext): Unit = {
-// var lval: String = null
-// var lvalFunc: String = null
-// var op: String = null
-//
-// def getLvalNode(tree: ParseTree): String =
-// tree.getChild(if (tree.getChildCount == 1) 0 else 1).getText.trim
-//
-// if (ctx.children.size() == 3) {
-// lval = getLvalNode(ctx.getChild(0))
-// op = ctx.getChild(1).getText.trim
-// }
-// else {
-// lvalFunc = ctx.getChild(0).getText.trim
-// lval = getLvalNode(ctx.getChild(2))
-// op = ctx.getChild(4).getText.trim
-// }
-//
-// val pred = new NCDslTokenPredicate(
-// lvalParts.asJava,
-// lvalFunc,
-// lval,
-// op,
-// if (rvalList.isEmpty) mkRvalObject(rval) else rvalList.map(mkRvalObject).asJava
-// )
-//
-// predStack.push(new Function[NCToken, Boolean] {
-// override def apply(tok: NCToken): Boolean = pred.apply(tok)
-// override def toString: String = pred.toString
-// })
-//
-// // Reset.
-// lvalParts.clear()
-// rvalList.clear()
-// rval = null
-// }
+ def getBuiltIntents: Set[NCDslIntent] = intents.toSet
+
+ override def syntaxError(errMsg: String, srcName: String, line: Int, pos: Int): NCE =
+ throw new NCE(mkSyntaxError(errMsg, srcName, line, pos, dsl, mdlId))
+ override def runtimeError(errMsg: String, srcName: String, line: Int, pos: Int, cause: Exception = null): NCE =
+ throw new NCE(mkRuntimeError(errMsg, srcName, line, pos, dsl, mdlId), cause)
}
-
+
+ /**
+ *
+ * @param msg
+ * @param line
+ * @param charPos
+ * @param dsl Original DSL text (input).
+ * @param mdlId
+ * @return
+ */
+ private def mkSyntaxError(
+ msg: String,
+ srcName: String,
+ line: Int, // 1, 2, ...
+ charPos: Int, // 0, 1, 2, ...
+ dsl: String,
+ mdlId: String): String = mkError("syntax", msg, srcName, line, charPos, dsl, mdlId)
+
/**
- * Custom error handler.
+ *
+ * @param msg
+ * @param dsl
+ * @param mdlId
+ * @param srcName
+ * @param line
+ * @param charPos
+ * @return
*/
- class CompilerErrorListener(dsl: String) extends BaseErrorListener {
- /**
- *
- * @param len
- * @param pos
- * @return
- */
- private def makeCharPosPointer(len: Int, pos: Int): String = {
- val s = (for (_ ← 1 to len) yield '-').mkString("")
-
- s.substring(0, pos - 1) + '^' + s.substring(pos)
- }
+ private def mkRuntimeError(
+ msg: String,
+ srcName: String,
+ line: Int, // 1, 2, ...
+ charPos: Int, // 0, 1, 2, ...
+ dsl: String,
+ mdlId: String): String = mkError("runtime", msg, srcName, line, charPos, dsl, mdlId)
+
+ private def mkError(
+ kind: String,
+ msg: String,
+ srcName: String,
+ line: Int,
+ charPos: Int,
+ dsl: String,
+ mdlId: String): String = {
+ val dslLine = dsl.split("\n")(line - 1)
+ val dash = "-" * dslLine.length
+ val pos = Math.max(0, charPos)
+ val posPtr = dash.substring(0, pos) + r("^") + y(dash.substring(pos + 1))
+ val dslPtr = dslLine.substring(0, pos) + r(dslLine.charAt(pos)) + y(dslLine.substring(pos + 1))
+ val aMsg = U.decapitalize(msg) match {
+ case s: String if s.last == '.' ⇒ s
+ case s: String ⇒ s + '.'
+ }
+ s"Intent DSL $kind error in '$srcName' at line $line:${charPos + 1} - $aMsg\n" +
+ s" |-- ${c("Model:")} $mdlId\n" +
+ s" |-- ${c("Line:")} $dslPtr\n" +
+ s" +-- ${c("Position:")} $posPtr"
+ }
+
+ /**
+ * Custom error handler.
+ *
+ * @param dsl
+ * @param mdlId
+ */
+ class CompilerErrorListener(dsl: String, mdlId: String) extends BaseErrorListener {
/**
- *
- * @param recognizer
- * @param offendingSymbol
- * @param line
- * @param charPos
- * @param msg
- * @param e
- */
+ *
+ * @param recog
+ * @param badSymbol
+ * @param line
+ * @param charPos
+ * @param msg
+ * @param e
+ */
override def syntaxError(
- recognizer: Recognizer[_, _],
- offendingSymbol: scala.Any,
- line: Int,
- charPos: Int,
+ recog: Recognizer[_, _],
+ badSymbol: scala.Any,
+ line: Int, // 1, 2, ...
+ charPos: Int, // 1, 2, ...
msg: String,
- e: RecognitionException): Unit = {
-
- val errMsg = s"Intent DSL syntax error at line $line:$charPos - $msg\n" +
- s" |-- ${c("Model:")} $mdlId\n" +
- s" |-- ${c("Intent:")} $dsl\n" +
- s" +-- ${c("Error:")} ${makeCharPosPointer(dsl.length, charPos)}"
-
- throw new NCE(errMsg)
- }
+ e: RecognitionException): Unit =
+ throw new NCE(mkSyntaxError(msg, recog.getInputStream.getSourceName, line, charPos - 1, dsl, mdlId))
}
-
+
/**
*
- * @param dsl Intent DSL to parse.
- * @param mdlId ID of the model the intent belongs to.
+ * @param dsl
+ * @param mdlId
+ * @param srcName
* @return
*/
- def compile(dsl: String, mdlId: String): NCDslIntent = {
+ private def antlr4(
+ dsl: String,
+ mdlId: String,
+ srcName: String
+ ): Set[NCDslIntent] = {
require(dsl != null)
-
- this.mdlId = mdlId
-
- val intent: NCDslIntent = cache.getOrElseUpdate(dsl, {
+ require(mdlId != null)
+ require(srcName != null)
+
+ val aDsl = dsl.strip()
+
+ val intents: Set[NCDslIntent] = cache.getOrElseUpdate(aDsl, {
// ANTLR4 armature.
- val lexer = new NCIntentDslLexer(CharStreams.fromString(dsl))
+ val lexer = new NCIntentDslLexer(CharStreams.fromString(aDsl, srcName))
val tokens = new CommonTokenStream(lexer)
- val parser = new NCIntentDslParser(tokens)
-
+ val parser = new IDP(tokens)
+
// Set custom error handlers.
lexer.removeErrorListeners()
parser.removeErrorListeners()
- lexer.addErrorListener(new CompilerErrorListener(dsl))
- parser.addErrorListener(new CompilerErrorListener(dsl))
-
+ lexer.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
+ parser.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
+
// State automata.
- val fsm = new FiniteStateMachine
-
+ val fsm = new FiniteStateMachine(aDsl, mdlId)
+
// Parse the input DSL and walk built AST.
- (new ParseTreeWalker).walk(fsm, parser.intent())
-
+ (new ParseTreeWalker).walk(fsm, parser.dsl())
+
// Return the built intent.
- val newIntent = fsm.getBuiltIntent
-
- // Log for visual verification.
- logger.debug(s"Intent compiler:")
- logger.debug(s" |-- IN $dsl")
- logger.debug(s" |-- OUT ${newIntent.toDslString}")
-
- newIntent
+ fsm.getBuiltIntents
})
-
- intent
+
+ intents
}
+
+ /**
+ * Compiles inline (supplied) fragments and/or intents from given file. Note that fragments are
+ * accumulated in a static map keyed by model ID. Only intents are returned, if any.
+ *
+ * @param filePath *.nc DSL file to compile.
+ * @param mdlId ID of the model *.nc file belongs to.
+ * @return
+ */
+ @throws[NCE]
+ def compilePath(
+ filePath: Path,
+ mdlId: String
+ ): Set[NCDslIntent] = antlr4(U.readFile(filePath.toFile).mkString("\n"), mdlId, filePath.getFileName.toString)
+
+ /**
+ * Compiles inline (supplied) fragments and/or intents. Note that fragments are accumulated in a static
+ * map keyed by model ID. Only intents are returned, if any.
+ *
+ * @param dsl DSL to compile.
+ * @param mdlId ID of the model DSL belongs to.
+ * @return
+ */
+ @throws[NCE]
+ def compile(
+ dsl: String,
+ mdlId: String
+ ): Set[NCDslIntent] = antlr4(dsl, mdlId, "<inline>")
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslFragmentCache.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslFragmentCache.scala
similarity index 94%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslFragmentCache.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslFragmentCache.scala
index b079321..601a817 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslFragmentCache.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentDslFragmentCache.scala
@@ -15,9 +15,9 @@
* limitations under the License.
*/
-package org.apache.nlpcraft.model.intent.impl.ver2
+package org.apache.nlpcraft.model.intent.impl
-import org.apache.nlpcraft.model.intent.utils.ver2.NCDslFragment
+import org.apache.nlpcraft.model.intent.utils.NCDslFragment
import scala.collection.concurrent.TrieMap
import scala.collection.mutable
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala
index 7452555..8c44d00 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/NCIntentSolverEngine.scala
@@ -219,7 +219,7 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
// Isolated conversation tokens.
val convToks =
- if (intent.terms.exists(_.isConversational))
+ if (intent.terms.exists(_.conv))
Seq.empty[UsedToken] ++
// We shouldn't mix tokens with same group from conversation
// history and processed sentence.
@@ -461,7 +461,7 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
varIdx: Int
): Option[IntentMatch] = {
val intentId = intent.id
- val hist = NCDialogFlowManager.getDialogFlow(ctx.getRequest.getUser.getId, ctx.getModel.getId)
+ val flow = NCDialogFlowManager.getDialogFlow(ctx.getRequest.getUser.getId, ctx.getModel.getId)
val varStr = s"(variant #${varIdx + 1})"
val flowRegex = intent.flowRegex
@@ -470,6 +470,12 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
logger.info(s" |-- ${c("Dialog flow:")} ${hist.mkString(" ")}")
logger.info(s" +-- ${c("Match regex:")} ${flowRegex.get.toString}")
}
+
+ if (intent.)
+
+
+
+
// Check dialog flow first.
if (intent.flowRegex.isDefined && !flowRegex.get.matcher(hist.mkString(" ")).find(0)) {
@@ -594,10 +600,10 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
senToks: Seq[UsedToken],
convToks: Seq[UsedToken]
): Option[TermMatch] =
- solvePredicate(term.getPredicate, term.getMin, term.getMax, senToks, convToks) match {
+ solvePredicate(term.pred, term.min, term.max, senToks, convToks) match {
case Some((usedToks, predWeight)) ⇒ Some(
TermMatch(
- term.getId,
+ term.id,
usedToks,
if (usedToks.nonEmpty) {
// If term match is non-empty we add the following weights:
@@ -605,19 +611,19 @@ object NCIntentSolverEngine extends LazyLogging with NCOpenCensusTrace {
// - delta between specified max and normalized max (how close the actual quantity was to the specified one).
// - normalized max
predWeight
- .append(term.getMin)
- .append(-(term.getMax - usedToks.size))
+ .append(term.min)
+ .append(-(term.max - usedToks.size))
// Normalize max quantifier in case of unbound max.
- .append(if (term.getMax == Integer.MAX_VALUE) usedToks.size else term.getMax)
+ .append(if (term.max == Integer.MAX_VALUE) usedToks.size else term.max)
} else {
// Term is optional (found but empty).
- require(term.getMin == 0)
+ require(term.min == 0)
predWeight
.append(0)
- .append(-term.getMax)
+ .append(-term.max)
// Normalize max quantifier in case of unbound max.
- .append(if (term.getMax == Integer.MAX_VALUE) 0 else term.getMax)
+ .append(if (term.max == Integer.MAX_VALUE) 0 else term.max)
}
)
)
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslCompiler.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslCompiler.scala
deleted file mode 100644
index 3cdd22d..0000000
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/impl/ver2/NCIntentDslCompiler.scala
+++ /dev/null
@@ -1,485 +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.model.intent.impl.ver2
-
-import com.typesafe.scalalogging.LazyLogging
-import org.antlr.v4.runtime._
-import org.antlr.v4.runtime.tree.ParseTreeWalker
-import org.apache.nlpcraft.common._
-import org.apache.nlpcraft.model.intent.impl.antlr4.{NCIntentDslParser ⇒ IDP, _}
-import org.apache.nlpcraft.model.intent.utils.ver2._
-import org.apache.nlpcraft.model._
-import org.apache.nlpcraft.model.intent.impl.ver2.{NCIntentDslFragmentCache ⇒ FragCache}
-
-import java.nio.file.Path
-import java.util.Optional
-import java.util.regex.{Pattern, PatternSyntaxException}
-import scala.collection.mutable
-import scala.collection.mutable.ArrayBuffer
-import scala.collection.JavaConverters._
-
-object NCIntentDslCompiler extends LazyLogging {
- // Compiler cache.
- private val cache = new mutable.HashMap[String, Set[NCDslIntent]]
-
- /**
- *
- * @param dsl
- * @param mdlId
- */
- class FiniteStateMachine(dsl: String, mdlId: String) extends NCIntentDslBaseListener with NCIntentDslBaselCompiler {
- // Accumulator for parsed intents.
- private val intents = ArrayBuffer.empty[NCDslIntent]
-
- // Fragment components.
- private var fragId: String = _
- private var fragMeta: Map[String, Any] = _
-
- // Intent components.
- private var intentId: String = _
- private var ordered: Boolean = false
- private var flowRegex: Option[String] = None
- private var intentMeta: Map[String, Any] = _
-
- // Accumulator for parsed terms.
- private val terms = ArrayBuffer.empty[NCDslTerm]
-
- // Currently term.
- private var termId: String = _
- private var termConv: Boolean = _
- private var min = 1
- private var max = 1
-
- // Current method reference.
- private var refClsName: Option[String] = None
- private var refMtdName: Option[String] = None
-
- // Current term's code, i.e. list of instructions.
- private var termInstrs = mutable.Buffer.empty[Instr]
-
- /*
- * Shared/common implementation.
- */
- override def exitUnaryExpr(ctx: IDP.UnaryExprContext): Unit = termInstrs += parseUnaryExpr(ctx.MINUS(), ctx.NOT())(ctx)
- override def exitMultExpr(ctx: IDP.MultExprContext): Unit = termInstrs += parseMultExpr(ctx.MULT(), ctx.MOD(), ctx.DIV())(ctx)
- override def exitPlusExpr(ctx: IDP.PlusExprContext): Unit = termInstrs += parsePlusExpr(ctx.PLUS(), ctx.MINUS())(ctx)
- override def exitCompExpr(ctx: IDP.CompExprContext): Unit = termInstrs += parseCompExpr(ctx.LT(), ctx.GT(), ctx.LTEQ(), ctx.GTEQ())(ctx)
- override def exitLogExpr(ctx: IDP.LogExprContext): Unit = termInstrs += parseLogExpr(ctx.AND, ctx.OR())(ctx)
- override def exitEqExpr(ctx: IDP.EqExprContext): Unit = termInstrs += parseEqExpr(ctx.EQ, ctx.NEQ())(ctx)
- override def exitCallExpr(ctx: IDP.CallExprContext): Unit = termInstrs += parseCallExpr(ctx.FUN_NAME())(ctx)
- override def exitAtom(ctx: IDP.AtomContext): Unit = termInstrs += parseAtom(ctx.getText)(ctx)
-
- /**
- *
- * @param min
- * @param max
- */
- private def setMinMax(min: Int, max: Int): Unit = {
- this.min = min
- this.max = max
- }
-
- override def exitMinMaxShortcut(ctx: IDP.MinMaxShortcutContext): Unit = {
- if (ctx.PLUS() != null)
- setMinMax(1, Integer.MAX_VALUE)
- else if (ctx.MULT() != null)
- setMinMax(0, Integer.MAX_VALUE)
- else if (ctx.QUESTION() != null)
- setMinMax(0, 1)
- else
- assert(false)
- }
-
- override def exitMinMaxRange(ctx: IDP.MinMaxRangeContext): Unit = {
- val minStr = ctx.getChild(1).getText.trim
- val maxStr = ctx.getChild(3).getText.trim
-
- try
- setMinMax(java.lang.Integer.parseInt(minStr), java.lang.Integer.parseInt(maxStr))
- catch {
- // Errors should be caught during compilation phase.
- case _: NumberFormatException ⇒ assert(false)
- }
- }
-
- override def exitMtdRef(ctx: IDP.MtdRefContext): Unit = {
- if (ctx.javaFqn() != null)
- refClsName = Some(ctx.javaFqn().getText)
-
- refMtdName = Some(ctx.id().getText)
- }
-
- override def exitTermId(ctx: IDP.TermIdContext): Unit = {
- termId = ctx.id().getText
-
- if (terms.exists(t ⇒ t.id != null && t.id == termId))
- throw newSyntaxError(s"Duplicate term ID: $termId")(ctx.id())
- }
-
- override def exitIntentId(ctx: IDP.IntentIdContext): Unit = {
- intentId = ctx.id().getText
-
- if (intents.exists(i ⇒ i.id != null && i.id == intentId))
- throw newSyntaxError(s"Duplicate intent ID: $intentId")(ctx.id())
- }
-
- override def exitFragId(ctx: IDP.FragIdContext): Unit = {
- fragId = ctx.id().getText
-
- if (FragCache.get(mdlId, fragId).isDefined)
- throw newSyntaxError(s"Duplicate fragment ID: $fragId")(ctx.id())
- }
-
- override def exitTermEq(ctx: IDP.TermEqContext): Unit = termConv = ctx.TILDA() != null
- override def exitFragMeta(ctx: IDP.FragMetaContext): Unit = fragMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
- override def exitMetaDecl(ctx: IDP.MetaDeclContext): Unit = intentMeta = U.jsonToScalaMap(ctx.jsonObj().getText)
- override def exitOrderedDecl(ctx: IDP.OrderedDeclContext): Unit = ordered = ctx.BOOL().getText == "true"
-
- override def exitFragRef(ctx: IDP.FragRefContext): Unit = {
- val id = ctx.id().getText
-
- FragCache.get(mdlId, id) match {
- case Some(frag) ⇒
- val meta = if (fragMeta == null) Map.empty[String, Any] else fragMeta
-
- for (fragTerm ← frag.terms)
- if (terms.exists(t ⇒ t.id != null && t.id == fragTerm.id))
- throw newSyntaxError(s"Duplicate term ID '${fragTerm.id}' in fragment '$id'.")(ctx.id())
- else
- terms += fragTerm.cloneWithMeta(meta)
-
- case None ⇒ throw newSyntaxError(s"Unknown intent fragment ID: $id")(ctx.id())
- }
-
- fragMeta = null
- }
-
- override def exitFlowDecl(ctx: IDP.FlowDeclContext): Unit = {
- implicit val evidence: ParserRuleContext = ctx
-
- if (ctx.qstring() != null) {
- val regex = ctx.qstring().getText
-
- if (regex != null && regex.length > 2)
- flowRegex = if (regex.nonEmpty) Some(regex) else None
-
- if (flowRegex.isDefined) // Pre-check.
- try
- Pattern.compile(flowRegex.get)
- catch {
- case e: PatternSyntaxException ⇒
- newSyntaxError(s"${e.getDescription} in intent flow regex '${e.getPattern}' near index ${e.getIndex}.")(ctx.qstring())
- }
- }
- }
-
- override def exitTerm(ctx: IDP.TermContext): Unit = {
- implicit val c: ParserRuleContext = ctx
-
- if (min < 0 || min > max)
- throw newSyntaxError(s"Invalid intent term min quantifiers: $min (must be min >= 0 && min <= max).")(ctx.minMax())
- if (max < 1)
- throw newSyntaxError(s"Invalid intent term max quantifiers: $max (must be max >= 1).")(ctx.minMax())
-
- val pred =
- if (refMtdName != null) { // User-code defined term.
- // Closure copies.
- val clsName = refClsName.orNull
- val mtdName = refMtdName.orNull
-
- (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
- val javaCtx: NCTokenPredicateContext = new NCTokenPredicateContext {
- override lazy val getRequest: NCRequest = termCtx.req
- override lazy val getToken: NCToken = tok
- override lazy val getIntentMeta: Optional[NCMetadata] =
- if (termCtx.intentMeta != null)
- Optional.of(NCMetadata.apply(termCtx.intentMeta.asJava))
- else
- Optional.empty()
- }
-
- val mdl = tok.getModel
- val mdlCls = if (clsName == null) mdl.meta[String](MDL_META_MODEL_CLASS_KEY) else clsName
-
- try {
- val obj = if (clsName == null) mdl else U.mkObject(clsName)
- val mtd = Thread.currentThread().getContextClassLoader.loadClass(mdlCls)
- .getMethod(mtdName, classOf[NCTokenPredicateContext])
-
- var flag = mtd.canAccess(mdl)
-
- val res = try {
- if (!flag) {
- mtd.setAccessible(true)
-
- flag = true
- }
- else
- flag = false
-
- mtd.invoke(obj, javaCtx).asInstanceOf[NCTokenPredicateResult]
- }
- finally {
- if (flag)
- try
- mtd.setAccessible(false)
- catch {
- case e: SecurityException ⇒
- throw new NCE(s"Access or security error in custom intent term: $mdlCls.$mtdName", e)
- }
- }
-
- (res.getResult, res.wasTokenUsed())
- }
- catch {
- case e: Exception ⇒
- throw newRuntimeError(s"Failed to invoke custom intent term: $mdlCls.$mtdName", e)
- }
- }
- }
- else { // DSL-defined term.
- val instrs = mutable.Buffer.empty[Instr]
-
- instrs ++= termInstrs
-
- (tok: NCToken, termCtx: NCDslTermContext) ⇒ {
- val stack = new mutable.ArrayStack[NCDslTermRetVal]()
-
- // Execute all instructions.
- instrs.foreach(_(tok, stack, termCtx))
-
- // Pop final result from stack.
- val x = stack.pop()
-
- if (!isBoolean(x.retVal))
- throw newRuntimeError(s"Intent term does not return boolean value: ${ctx.getText}")
-
- (asBool(x.retVal), x.usedTok)
- }
-
- }
-
- // Add term.
- terms += NCDslTerm(
- termId,
- pred,
- min,
- max,
- termConv
- )
-
- // Reset term vars.
- setMinMax(1, 1)
- termId = null
- termInstrs.clear()
- refClsName = None
- refMtdName = None
- }
-
- override def exitFrag(ctx: IDP.FragContext): Unit = {
- FragCache.add(mdlId, NCDslFragment(fragId, terms.toList))
-
- terms.clear()
- }
-
- override def exitIntent(ctx: IDP.IntentContext): Unit = {
- intents += NCDslIntent(
- dsl,
- intentId,
- ordered,
- if (intentMeta == null) Map.empty else intentMeta,
- flowRegex,
- refClsName,
- refMtdName,
- terms.toList
- )
-
- refClsName = None
- refMtdName = None
- intentMeta = null
- terms.clear()
- }
-
- /**
- *
- * @return
- */
- def getBuiltIntents: Set[NCDslIntent] = intents.toSet
-
- override def syntaxError(errMsg: String, srcName: String, line: Int, pos: Int): NCE =
- throw new NCE(mkSyntaxError(errMsg, srcName, line, pos, dsl, mdlId))
- override def runtimeError(errMsg: String, srcName: String, line: Int, pos: Int, cause: Exception = null): NCE =
- throw new NCE(mkRuntimeError(errMsg, srcName, line, pos, dsl, mdlId), cause)
- }
-
- /**
- *
- * @param msg
- * @param line
- * @param charPos
- * @param dsl Original DSL text (input).
- * @param mdlId
- * @return
- */
- private def mkSyntaxError(
- msg: String,
- srcName: String,
- line: Int, // 1, 2, ...
- charPos: Int, // 0, 1, 2, ...
- dsl: String,
- mdlId: String): String = mkError("syntax", msg, srcName, line, charPos, dsl, mdlId)
-
- /**
- *
- * @param msg
- * @param dsl
- * @param mdlId
- * @param srcName
- * @param line
- * @param charPos
- * @return
- */
- private def mkRuntimeError(
- msg: String,
- srcName: String,
- line: Int, // 1, 2, ...
- charPos: Int, // 0, 1, 2, ...
- dsl: String,
- mdlId: String): String = mkError("runtime", msg, srcName, line, charPos, dsl, mdlId)
-
- private def mkError(
- kind: String,
- msg: String,
- srcName: String,
- line: Int,
- charPos: Int,
- dsl: String,
- mdlId: String): String = {
- val dslLine = dsl.split("\n")(line - 1)
- val dash = "-" * dslLine.length
- val pos = Math.max(0, charPos)
- val posPtr = dash.substring(0, pos) + r("^") + y(dash.substring(pos + 1))
- val dslPtr = dslLine.substring(0, pos) + r(dslLine.charAt(pos)) + y(dslLine.substring(pos + 1))
- val aMsg = U.decapitalize(msg) match {
- case s: String if s.last == '.' ⇒ s
- case s: String ⇒ s + '.'
- }
-
- s"Intent DSL $kind error in '$srcName' at line $line:${charPos + 1} - $aMsg\n" +
- s" |-- ${c("Model:")} $mdlId\n" +
- s" |-- ${c("Line:")} $dslPtr\n" +
- s" +-- ${c("Position:")} $posPtr"
- }
-
- /**
- * Custom error handler.
- *
- * @param dsl
- * @param mdlId
- */
- class CompilerErrorListener(dsl: String, mdlId: String) extends BaseErrorListener {
- /**
- *
- * @param recog
- * @param badSymbol
- * @param line
- * @param charPos
- * @param msg
- * @param e
- */
- override def syntaxError(
- recog: Recognizer[_, _],
- badSymbol: scala.Any,
- line: Int, // 1, 2, ...
- charPos: Int, // 1, 2, ...
- msg: String,
- e: RecognitionException): Unit =
- throw new NCE(mkSyntaxError(msg, recog.getInputStream.getSourceName, line, charPos - 1, dsl, mdlId))
- }
-
- /**
- *
- * @param dsl
- * @param mdlId
- * @param srcName
- * @return
- */
- private def antlr4(
- dsl: String,
- mdlId: String,
- srcName: String
- ): Set[NCDslIntent] = {
- require(dsl != null)
- require(mdlId != null)
- require(srcName != null)
-
- val aDsl = dsl.strip()
-
- val intents: Set[NCDslIntent] = cache.getOrElseUpdate(aDsl, {
- // ANTLR4 armature.
- val lexer = new NCIntentDslLexer(CharStreams.fromString(aDsl, srcName))
- val tokens = new CommonTokenStream(lexer)
- val parser = new IDP(tokens)
-
- // Set custom error handlers.
- lexer.removeErrorListeners()
- parser.removeErrorListeners()
- lexer.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
- parser.addErrorListener(new CompilerErrorListener(aDsl, mdlId))
-
- // State automata.
- val fsm = new FiniteStateMachine(aDsl, mdlId)
-
- // Parse the input DSL and walk built AST.
- (new ParseTreeWalker).walk(fsm, parser.dsl())
-
- // Return the built intent.
- fsm.getBuiltIntents
- })
-
- intents
- }
-
- /**
- * Compiles inline (supplied) fragments and/or intents from given file. Note that fragments are
- * accumulated in a static map keyed by model ID. Only intents are returned, if any.
- *
- * @param filePath *.nc DSL file to compile.
- * @param mdlId ID of the model *.nc file belongs to.
- * @return
- */
- @throws[NCE]
- def compilePath(
- filePath: Path,
- mdlId: String
- ): Set[NCDslIntent] = antlr4(U.readFile(filePath.toFile).mkString("\n"), mdlId, filePath.getFileName.toString)
-
- /**
- * Compiles inline (supplied) fragments and/or intents. Note that fragments are accumulated in a static
- * map keyed by model ID. Only intents are returned, if any.
- *
- * @param dsl DSL to compile.
- * @param mdlId ID of the model DSL belongs to.
- * @return
- */
- @throws[NCE]
- def compile(
- dsl: String,
- mdlId: String
- ): Set[NCDslIntent] = antlr4(dsl, mdlId, "<inline>")
-}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslFragment.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslFragment.scala
similarity index 95%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslFragment.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslFragment.scala
index beb1e74..9831fe9 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslFragment.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslFragment.scala
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
/**
* DSL fragment.
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala
index fd3b32e..6a20e09 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslIntent.scala
@@ -17,50 +17,39 @@
package org.apache.nlpcraft.model.intent.utils
-import java.util.regex.{Pattern, PatternSyntaxException}
+import java.util.regex.Pattern
/**
- * Intent from intent DSL.
- *
- * @param id Intent ID.
- * @param ordered Whether or not the order of terms is important for matching.
- * @param flow Optional flow matching regex.
- * @param terms Array of terms comprising this intent.
- */
-case class NCDslIntent(id: String, ordered: Boolean, flow: Option[String], terms: Array[NCDslTerm]) {
- if (id == null)
- throw new IllegalArgumentException("Intent ID must be provided.")
- if (terms.length == 0)
- throw new IllegalArgumentException("Intent should have at least one term.")
+ * DSL intent.
+ *
+ * @param dsl Original DSL of this intent.
+ * @param id
+ * @param ordered
+ * @param meta
+ * @param flow
+ * @param terms
+ */
+case class NCDslIntent(
+ dsl: String,
+ id: String,
+ ordered: Boolean,
+ meta: Map[String, Any],
+ flow: Option[String],
+ flowClsName: Option[String],
+ flowMtdName: Option[String],
+ terms: List[NCDslTerm]
+) {
+ require(id != null)
+ require(terms.nonEmpty)
+ require(meta != null)
// Flow regex as a compiled pattern.
- val flowRegex = flow match {
- case Some(r) ⇒
- try
- Some(Pattern.compile(r))
- catch {
- case e: PatternSyntaxException ⇒
- throw new IllegalArgumentException(s"${e.getDescription} in flow regex '${e.getPattern}' near index ${e.getIndex}.")
- }
-
+ // Regex validity check is already done during intent compilation.
+ lazy val flowRegex = flow match {
+ case Some(r) ⇒ Some(Pattern.compile(r))
case None ⇒ None
}
override def toString: String =
- s"Intent: '$id'"
-
- /**
- * Gets full intent string representation in text DSL format.
- *
- * @return Full intent string representation in text DSL format.
- */
- def toDslString: String = {
- val orderedStr = if (!ordered) "" else " ordered=true"
- val flowStr = flow match {
- case Some(r) ⇒ s" flow='$r'"
- case None ⇒ ""
- }
-
- s"intent=$id$orderedStr$flowStr ${terms.mkString(" ")}"
- }
+ s"intent=$id"
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.java b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.java
deleted file mode 100644
index 4192da8..0000000
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.java
+++ /dev/null
@@ -1,131 +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.model.intent.utils;
-
-import org.apache.nlpcraft.model.*;
-import java.io.*;
-import java.util.function.*;
-
-/**
- * Internal DSL intent term representation.
- */
-public class NCDslTerm implements Serializable {
- // Term's predicate.
- final private Function<NCToken, Boolean> pred;
-
- // Conversational or not.
- final private boolean conv;
-
- // Terms quantifiers.
- final private int min, max;
-
- // Optional term ID.
- final private String id;
-
- /**
- * Creates new term with given predicate and quantifiers.
- *
- * @param id Optional term ID.
- * @param pred Token predicate.
- * @param min Minimum quantifier for the predicate (inclusive).
- * @param max Maximum quantifier for the predicate (inclusive).
- * @param conv Whether or not this term is conversational.
- */
- public NCDslTerm(String id, Function<NCToken, Boolean> pred, int min, int max, boolean conv) {
- if (pred == null)
- throw new IllegalArgumentException("Intent DSL term predicate cannot be null.");
- if (min < 0 || min > max)
- throw new IllegalArgumentException(String.format(
- "Invalid intent DSL term min quantifiers: %d (must be min >= 0 && min <= max).", min));
- if (max < 1)
- throw new IllegalArgumentException(String.format(
- "Invalid intent DSL term max quantifiers: %d (must be max >= 1).", max));
-
- this.id = id;
- this.pred = pred;
- this.min = min;
- this.max = max;
- this.conv = conv;
- }
-
- /**
- * Gets term's predicate.
- *
- * @return Term's predicate.
- */
- public Function<NCToken, Boolean> getPredicate() {
- return pred;
- }
-
- /**
- * Gets optional term ID.
- *
- * @return Term ID or {@code null} if not specified.
- */
- public String getId() {
- return id;
- }
-
- /**
- * Gets min quantifier for this term.
- *
- * @return Min quantifier for this term.
- */
- public int getMin() {
- return min;
- }
-
- /**
- * Gets max quantifier for this term.
- *
- * @return Max quantifier for this term.
- */
- public int getMax() {
- return max;
- }
-
- /**
- * Whether or not this term support conversational context.
- *
- * @return {@code true} if this term supports conversational context, {@code false} otherwise.
- */
- public boolean isConversational() { return conv; }
-
- @Override
- public String toString() {
- String minMax;
-
- if (min == 1 && max == 1)
- minMax = "";
- else if (min == 0 && max == 1)
- minMax = "?";
- else if (min == 0 && max == Integer.MAX_VALUE)
- minMax = "*";
- else if (min == 1 && max == Integer.MAX_VALUE)
- minMax = "+";
- else
- minMax = String.format("[%d,%d]", min, max);
-
- String eq = conv ? "~" : "=";
-
- if (id == null)
- return String.format("term%s{%s}%s", eq, pred, minMax);
- else
- return String.format("term(%s)%s{%s}%s", id, eq, pred, minMax);
- }
-}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTerm.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.scala
similarity index 96%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTerm.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.scala
index 79a5ed2..f757511 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTerm.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTerm.scala
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
import org.apache.nlpcraft.model.NCToken
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermContext.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermContext.scala
similarity index 96%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermContext.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermContext.scala
index 291ae9a..e903854 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermContext.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermContext.scala
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
import org.apache.nlpcraft.common.ScalaMeta
import org.apache.nlpcraft.model.NCRequest
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermRetVal.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermRetVal.scala
similarity index 94%
rename from nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermRetVal.scala
rename to nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermRetVal.scala
index 1030416..8eb3a7c 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslTermRetVal.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/NCDslTermRetVal.scala
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-package org.apache.nlpcraft.model.intent.utils.ver2
+package org.apache.nlpcraft.model.intent.utils
/**
*
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslIntent.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslIntent.scala
deleted file mode 100644
index 5053661..0000000
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/utils/ver2/NCDslIntent.scala
+++ /dev/null
@@ -1,55 +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.model.intent.utils.ver2
-
-import java.util.regex.Pattern
-
-/**
- * DSL intent.
- *
- * @param dsl Original DSL of this intent.
- * @param id
- * @param ordered
- * @param meta
- * @param flow
- * @param terms
- */
-case class NCDslIntent(
- dsl: String,
- id: String,
- ordered: Boolean,
- meta: Map[String, Any],
- flow: Option[String],
- flowClsName: Option[String],
- flowMtdName: Option[String],
- terms: List[NCDslTerm]
-) {
- require(id != null)
- require(terms.nonEmpty)
- require(meta != null)
-
- // Flow regex as a compiled pattern.
- // Regex validity check is already done during intent compilation.
- lazy val flowRegex = flow match {
- case Some(r) ⇒ Some(Pattern.compile(r))
- case None ⇒ None
- }
-
- override def toString: String =
- s"intent=$id"
-}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala
index 825c556..3ab3d6a 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/dialogflow/NCDialogFlowManager.scala
@@ -134,28 +134,14 @@ object NCDialogFlowManager extends NCService {
}
/**
- * Gets sequence of intent ID sorted from oldest to newest (i.e. dialog flow) for given user and model IDs.
- *
- * @param usrId User ID.
- * @param mdlId Model ID.
- * @return Dialog flow.
- */
- def getStringFlow(usrId: Long, mdlId: String, parent: Span = null): Seq[String] =
- startScopedSpan("getStringFlow", parent, "usrId" → usrId, "mdlId" → mdlId) { _ ⇒
- flow.synchronized {
- flow.getOrElseUpdate(Key(usrId, mdlId), mutable.ArrayBuffer.empty[NCDialogFlowItem]).map(_.getIntentId)
- }
- }
-
- /**
* Gets sequence of dialog flow items sorted from oldest to newest (i.e. dialog flow) for given user and model IDs.
*
* @param usrId User ID.
* @param mdlId Model ID.
* @return Dialog flow.
*/
- def getItemFlow(usrId: Long, mdlId: String, parent: Span = null): Seq[NCDialogFlowItem] =
- startScopedSpan("getItemFlow", parent, "usrId" → usrId, "mdlId" → mdlId) { _ ⇒
+ def getDialogFlow(usrId: Long, mdlId: String, parent: Span = null): Seq[NCDialogFlowItem] =
+ startScopedSpan("getDialogFlow", parent, "usrId" → usrId, "mdlId" → mdlId) { _ ⇒
flow.synchronized {
flow.getOrElseUpdate(Key(usrId, mdlId), mutable.ArrayBuffer.empty[NCDialogFlowItem])
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala
index 2a70932..9aec9cc 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/NCProbeEnrichmentManager.scala
@@ -586,7 +586,7 @@ object NCProbeEnrichmentManager extends NCService with NCOpenCensusModelStats {
override lazy val getConversation: NCConversation = new NCConversation {
override def getTokens: util.List[NCToken] = conv.getTokens()
- override def getDialogFlow: util.List[NCDialogFlowItem] = NCDialogFlowManager.getItemFlow(usrId, mdlId, span).asJava
+ override def getDialogFlow: util.List[NCDialogFlowItem] = NCDialogFlowManager.getDialogFlow(usrId, mdlId, span).asJava
override def clearStm(filter: Predicate[NCToken]): Unit = conv.clearTokens(filter)
override def clearDialog(filter: Predicate[String]): Unit = NCDialogFlowManager.clear(usrId, mdlId, span)
override def getMetadata = conv.getUserData
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala
index 2f592ee..fdbcb31 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/model/intent/dsl/NCIntentDslCompilerSpec.scala
@@ -18,7 +18,8 @@
package org.apache.nlpcraft.model.intent.dsl
import org.apache.nlpcraft.common._
-import org.apache.nlpcraft.model.intent.impl.ver2.{NCIntentDslCompiler, NCIntentDslFragmentCache}
+import org.apache.nlpcraft.model.intent.impl.{NCIntentDslCompiler, NCIntentDslFragmentCache}
+import org.apache.nlpcraft.model.intent.impl.ver2.NCIntentDslFragmentCache
import org.junit.jupiter.api.Test
import java.nio.file.{Path, Paths}