WIP.
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolver.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolver.scala
index bd6e734..5efe204 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolver.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/model/intent/solver/NCIntentSolver.scala
@@ -27,9 +27,9 @@
import org.apache.nlpcraft.model.intent.NCIdlIntent
import org.apache.nlpcraft.model.{NCContext, NCIntentMatch, NCIntentSkip, NCModel, NCRejection, NCResult, NCToken, NCVariant}
import org.apache.nlpcraft.probe.mgrs.dialogflow.NCDialogFlowManager
-import org.apache.nlpcraft.probe.mgrs.sentence.NCSentenceManager
-import java.util.{List => JList}
+import java.util.{Collections, List => JList}
+import scala.collection.mutable
import scala.jdk.CollectionConverters.{ListHasAsScala, SeqHasAsJava}
/**
@@ -102,17 +102,16 @@
val intentToks =
res.groups.map(_.tokens).map(toks => {
toks.filter(allConvToks.contains).foreach(convTok =>
- NCSentenceManager.fixMeta(convTok, nonConvToks, allConvToks)
- )
+ fixBuiltTokensMeta(convTok, nonConvToks, allConvToks))
- toks
- })
+ toks.asJava
+ }).asJava
ctx.getConversation.getTokens
val intentMatch: NCIntentMatch = new NCMetadataAdapter with NCIntentMatch {
override val getContext: NCContext = ctx
- override val getIntentTokens: JList[JList[NCToken]] = intentToks.map(_.asJava).asJava
+ override val getIntentTokens: JList[JList[NCToken]] = intentToks
override val getVariant: NCVariant = new NCVariantImpl(res.variant.tokens)
override val getIntentId: String = res.intentId
override def getTermTokens(idx: Int): JList[NCToken] = res.groups(idx).tokens.asJava
@@ -175,4 +174,163 @@
throw new NCRejection("No matching intent found - all intents were skipped.")
}
+
+
+ /**
+ *
+ * @param convTok
+ * @param nonConvToks
+ * @param allConvToks
+ */
+ private def fixBuiltTokensMeta(convTok: NCToken, nonConvToks: Seq[NCToken], allConvToks: Seq[NCToken]): Unit = {
+ def isReference(tok: NCToken, id: String, idx: Int): Boolean = tok.getId == id && tok.getIndex == idx
+ def sameGroup(t1: NCToken, t2: NCToken): Boolean = {
+ val gs1 = t1.getGroups.asScala
+ val gs2 = t2.getGroups.asScala
+
+ gs1.exists(gs2.contains)
+ }
+
+ def getSeq[T](tok: NCToken,name: String): Seq[T] = {
+ val list = tok.meta[JList[T]](name)
+
+ if (list == null) Seq.empty else list.asScala
+ }
+
+ convTok.getId match {
+ case "nlpcraft:sort" =>
+ def fix(notesName: String, idxsName: String): Unit = {
+ val refIds: Seq[String] = getSeq(convTok, s"nlpcraft:sort:$notesName")
+ val refIdxs: Seq[Int] = getSeq(convTok, s"nlpcraft:sort:$idxsName")
+
+ require(refIds.length == refIdxs.length)
+
+ // Can be empty section for sort.
+ if (refIds.nonEmpty) {
+ var data = mutable.ArrayBuffer.empty[(String, Int)]
+ val notFound = mutable.ArrayBuffer.empty[(String, Int)]
+
+ // Sort elements can be different types.
+ // Part of them can be in conversation , part of them - in actual variant.
+ refIds.zip(refIdxs).map { case (refId, refIdx) =>
+ val seq =
+ nonConvToks.find(isReference(_, refId, refIdx)) match {
+ case Some(_) => data
+ case None => notFound
+ }
+
+ seq += refId -> refIdx
+ }
+
+ notFound.
+ groupBy { case (nfRefId, _) => nfRefId }.
+ map { case (nfRefId, data) => nfRefId -> data.map(_._2).sorted }.foreach {
+ case (nfRefId, nfRefIdsx) =>
+ val convRefs = allConvToks.filter(_.getId == nfRefId)
+
+ if (convRefs.map(_.getIndex).sorted != nfRefIdsx)
+ throw new NCE(
+ s"Conversation references are not found [id=$nfRefId, " +
+ s"indexes=${nfRefIdsx.mkString(", ")}]"
+ )
+
+ val convRefsAny = convRefs.head
+
+ val newNonConvRefs = nonConvToks.filter(sameGroup(convRefsAny, _))
+
+ if (newNonConvRefs.nonEmpty && newNonConvRefs.size != nfRefIdsx.size)
+ throw new NCE(
+ s"Variant references are not found [id=$nfRefId, count=${nfRefIdsx.size}]"
+ )
+
+ val refs = if (newNonConvRefs.nonEmpty) newNonConvRefs else convRefs
+
+ refs.foreach(t => data += t.getId -> t.getIndex)
+ }
+
+ data = data.sortBy(_._2)
+
+ convTok.getMetadata.put(s"nlpcraft:sort:$notesName", data.map(_._1).asJava)
+ convTok.getMetadata.put(s"nlpcraft:sort:$idxsName", data.map(_._2).asJava)
+ }
+ }
+
+ fix("bynotes", "byindexes")
+ fix("subjnotes", "subjindexes")
+ case "nlpcraft:limit" =>
+ val refId = convTok.meta[String]("nlpcraft:limit:note")
+ val refIdxs = convTok.meta[JList[Int]]("nlpcraft:limit:indexes").asScala
+
+ require(refIdxs.size == 1)
+
+ val refIdx = refIdxs.head
+
+ if (!nonConvToks.exists(isReference(_, refId, refIdx))) {
+ val convRefs = allConvToks.filter(_.getId == refId)
+
+ if (convRefs.size != 1 || convRefs.head.getIndex != refIdx)
+ throw new NCE(s"Conversation reference is not found [id=$refId, index=$refIdx]")
+
+ val convRef = convRefs.head
+
+ val nonConvRefs = nonConvToks.filter(sameGroup(convRef, _))
+
+ if (nonConvRefs.nonEmpty && nonConvRefs.size != 1)
+ throw new NCE(s"Variant reference are not found [id=$refId]")
+
+ val ref = if (nonConvRefs.nonEmpty) nonConvRefs.head else convRef
+
+ convTok.getMetadata.put(s"nlpcraft:limit:note", ref.getId)
+ convTok.getMetadata.put(s"nlpcraft:limit:indexes", Collections.singleton(ref.getIndex))
+ }
+
+ case "nlpcraft:relation" =>
+ val refId = convTok.meta[String]("nlpcraft:relation:note")
+ val refIdxs = convTok.meta[JList[Int]]("nlpcraft:relation:indexes").asScala.sorted
+
+ val convRefs = allConvToks.filter(_.getId == refId)
+
+ val nonConvRefs = nonConvToks.filter(t => t.getId == refId && refIdxs.contains(t.getIndex))
+
+ if (nonConvRefs.nonEmpty && nonConvRefs.size != refIdxs.size)
+ throw new NCE(
+ s"References are not found [id=$refId, " +
+ s"indexes=${refIdxs.mkString(", ")}]"
+ )
+
+ if (nonConvRefs.isEmpty) {
+ val convRefs = allConvToks.filter(t => t.getId == refId && refIdxs.contains(t.getIndex))
+
+ if (convRefs.size != refIdxs.size)
+ throw new NCE(
+ s"Conversation references are not found [id=$refId, " +
+ s"indexes=${refIdxs.mkString(", ")}]"
+ )
+
+ val convRefsAny = convRefs.head
+
+ val newNonConvRefs = nonConvToks.filter(sameGroup(convRefsAny, _))
+
+ if (newNonConvRefs.nonEmpty && newNonConvRefs.size != refIdxs.size)
+ throw new NCE(
+ s"Variant references are not found [id=$refId, count=${refIdxs.size}]"
+ )
+
+ val refs = if (newNonConvRefs.nonEmpty) newNonConvRefs else convRefs
+
+ val refsIds = refs.map(_.getId).distinct
+
+ if (refsIds.size != 1)
+ throw new NCE(
+ s"Variant references are not found [id=$refId, count=${refIdxs.size}]"
+ )
+
+
+ convTok.getMetadata.put(s"nlpcraft:relation:note", refsIds.head)
+ convTok.getMetadata.put(s"nlpcraft:relation:indexes", refs.map(_.getIndex).asJava)
+ }
+
+ case _ => // No-op.
+ }
+ }
}
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/sentence/NCSentenceManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/sentence/NCSentenceManager.scala
index 115d7f9..74ead87 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/sentence/NCSentenceManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/sentence/NCSentenceManager.scala
@@ -22,7 +22,7 @@
import org.apache.nlpcraft.common.nlp.pos.NCPennTreebank
import org.apache.nlpcraft.common.nlp.{NCNlpSentence, NCNlpSentenceNote, NCNlpSentenceToken}
import org.apache.nlpcraft.common.{NCE, NCService, U, _}
-import org.apache.nlpcraft.model.{NCModel, NCToken}
+import org.apache.nlpcraft.model.NCModel
import org.apache.nlpcraft.probe.mgrs.NCTokenPartKey
import java.io.{Serializable => JSerializable}
@@ -43,6 +43,7 @@
type CacheValue = Seq[Seq[NCNlpSentenceNote]]
private val combCache = mutable.HashMap.empty[String, mutable.HashMap[CacheKey, CacheValue]]
+
/**
*
* @param notes
@@ -790,57 +791,4 @@
* @param srvReqId
*/
def clearCache(srvReqId: String): Unit = combCache -= srvReqId
-
-
-
- /**
- *
- * @param convTok
- * @param nonConvToks
- * @param allConvToks
- */
- def fixMeta(convTok: NCToken, nonConvToks: Seq[NCToken], allConvToks: Seq[NCToken]): Unit =
- convTok.getId match {
- case "nlpcraft:sort" =>
- def fix(notesName: String, idxsName: String): Unit = {
- val notes = convTok.meta[JList[String]](s"nlpcraft:sort:$notesName")
- val idxs = convTok.meta[JList[Int]](s"nlpcraft:sort:$idxsName")
-
- require(notes == null && idxs == null || notes.size() == idxs.size())
-
- if (notes != null && !notes.isEmpty) {
- val data: Seq[(String, Int)] =
- notes.asScala.zip(idxs.asScala).map { case (note, idx) =>
- nonConvToks.find(t => t.getId == note && t.getIndex == idx) match {
- case Some(_) => (note, idx)
- case None =>
- val ref =
- allConvToks.
- find(t => t.getId == note && t.getIndex == idx).
- getOrElse(
- throw new NCE(s"Reference is not found [note=$note, index=$idx]")
- )
-
- val newRef =
- nonConvToks.
- find(t =>
- t.getGroups.asScala.toSet.intersect(ref.getGroups.asScala.toSet).nonEmpty
- ).
- getOrElse(
- throw new NCE(s"New reference is not found [note=$note, index=$idx]")
- )
-
- (newRef.getId, newRef.getIndex)
- }
- }
-
- convTok.getMetadata.put(s"nlpcraft:sort:$notesName", data.map(_._1).asJava)
- convTok.getMetadata.put(s"nlpcraft:sort:$idxsName", data.map(_._2).asJava)
- }
- }
-
- fix("bynotes", "byindexes")
- fix("subjnotes", "subjindexes")
- case _ => // TODO: implement all other.
- }
}