You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nlpcraft.apache.org by se...@apache.org on 2021/07/29 11:31:47 UTC

[incubator-nlpcraft] branch NLPCRAFT-376 updated (2c4b31b -> 369cd99)

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

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


    from 2c4b31b  WIP.
     new 004a3dc  WIP.
     add 9c76f08  WIP on NLPCRAFT-375
     add fef7822  FIx for NLPCRAFT-375.
     new 483a000  Merge branch 'master' into NLPCRAFT-376
     new 369cd99  WIP.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../model/intent/solver/NCIntentSolver.scala       |  70 ++++----
 .../nlpcraft/model/tools/cmdline/NCCli.scala       |  38 ++++-
 .../model/tools/cmdline/NCCliCommands.scala        |  12 +-
 .../tools/cmdline/NCCliFileNameCompleter.java      |   7 +-
 .../mgrs/nlp/enrichers/sort/NCSortEnricher.scala   |  20 ++-
 .../nlpcraft/models/stm/indexes/NCLimitSpec.scala  |  75 ++++++++-
 .../models/stm/indexes/NCRelationSpec.scala        |  74 ++++++++-
 .../nlpcraft/models/stm/indexes/NCSortSpec.scala   | 182 ++++++++++++++++++++-
 .../models/stm/indexes/NCSpecModelAdapter.scala    |  11 +-
 .../nlp/enrichers/sort/NCEnricherSortSpec.scala    | 173 +-------------------
 10 files changed, 409 insertions(+), 253 deletions(-)

[incubator-nlpcraft] 03/03: WIP.

Posted by se...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 369cd9922133f57abe8f2087703cd6c9e156e89d
Author: Sergey Kamov <sk...@gmail.com>
AuthorDate: Thu Jul 29 14:31:37 2021 +0300

    WIP.
---
 .../model/intent/solver/NCIntentSolver.scala       |  70 ++++----
 .../mgrs/nlp/enrichers/sort/NCSortEnricher.scala   |  20 +--
 .../nlpcraft/models/stm/indexes/NCLimitSpec.scala  |  75 ++++++++-
 .../models/stm/indexes/NCRelationSpec.scala        |  74 ++++++++-
 .../nlpcraft/models/stm/indexes/NCSortSpec.scala   | 180 ++++++++++++++++++---
 .../models/stm/indexes/NCSpecModelAdapter.scala    |  11 +-
 .../nlp/enrichers/sort/NCEnricherSortSpec.scala    | 173 +-------------------
 7 files changed, 353 insertions(+), 250 deletions(-)

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 ba9daf5..983c36c 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
@@ -97,18 +97,16 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
                 i += 1
 
                 val allConvToks = ctx.getConversation.getTokens.asScala
-                val nonConvToks = res.groups.flatMap(_.tokens).filterNot(allConvToks.contains)
+                val vrntNotConvToks = res.variant.tokens.asScala.filterNot(allConvToks.contains)
 
                 val intentToks =
                     res.groups.map(_.tokens).map(toks => {
                         toks.filter(allConvToks.contains).foreach(convTok =>
-                            fixBuiltTokensMeta(convTok, nonConvToks, allConvToks))
+                            fixBuiltTokenMeta(convTok, vrntNotConvToks, allConvToks))
 
                         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
@@ -177,12 +175,13 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
 
     /**
       *
-      * @param convTok
-      * @param nonConvToks
+      * @param convTok4Fix
+      * @param vrntNotConvToks
       * @param allConvToks
       */
     @throws[NCE]
-    private def fixBuiltTokensMeta(convTok: NCToken, nonConvToks: Seq[NCToken], allConvToks: Seq[NCToken]): Unit = {
+    @throws[NCIntentSkip]
+    private def fixBuiltTokenMeta(convTok4Fix: NCToken, vrntNotConvToks: Seq[NCToken], allConvToks: Seq[NCToken]): Unit = {
         def isReference(tok: NCToken, id: String, idx: Int): Boolean = tok.getId == id && tok.getIndex == idx
 
         /**
@@ -193,12 +192,15 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
           * 3. Next, for found group, it tries to find actual tokens with this group among non-conversation tokens.
           * If these non-conversation tokens found, they should be validated and returned,
           * If not found - conversation tokens returned.
-          *
+
           * @param refId Reference token ID.
           * @param refIdxs Reference indexes.
           * @param validate Validate predicate.
+          * @throws NCE It means that we sentence is invalid, internal error.
+          * @throws NCIntentSkip It means that we try to process invalid variant and it should be skipped.
           */
         @throws[NCE]
+        @throws[NCIntentSkip]
         def getForRecalc(refId: String, refIdxs: Seq[Int], validate: Seq[NCToken] => Boolean): Seq[NCToken] = {
             val convRefs = allConvToks.filter(_.getId == refId)
 
@@ -211,24 +213,24 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
             if (commonConvGs.isEmpty)
                 throw new NCE(s"Conversation references don't have common group [id=$refId]")
 
-            val actualNonConvRefs = nonConvToks.filter(_.getGroups.asScala.exists(commonConvGs.contains))
+            val actNonConvRefs = vrntNotConvToks.filter(_.getGroups.asScala.exists(commonConvGs.contains))
 
-            if (actualNonConvRefs.nonEmpty) {
-                if (!validate(actualNonConvRefs))
-                    throw new NCE(
+            if (actNonConvRefs.nonEmpty) {
+                if (!validate(actNonConvRefs))
+                    throw new NCIntentSkip(
                         s"Actual valid variant references are not found for recalculation [" +
                             s"id=$refId, " +
-                            s"actualNonConvRefs=${actualNonConvRefs.map(p => s"${p.getOriginalText}(${p.getId}-${p.getIndex})").mkString(",")}" +
+                            s"actualNonConvRefs=${actNonConvRefs.mkString(",")}" +
                             s"]"
                     )
 
-                actualNonConvRefs
+                actNonConvRefs
             }
             else
                 convRefs
         }
 
-        convTok.getId match {
+        convTok4Fix.getId match {
             case "nlpcraft:sort" =>
                 def getNotNullSeq[T](tok: NCToken, name: String): Seq[T] = {
                     val list = tok.meta[JList[T]](name)
@@ -237,8 +239,8 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
                 }
 
                 def process(notesName: String, idxsName: String): Unit = {
-                    val refIds: Seq[String] = getNotNullSeq(convTok, s"nlpcraft:sort:$notesName")
-                    val refIdxs: Seq[Int] = getNotNullSeq(convTok, s"nlpcraft:sort:$idxsName")
+                    val refIds: Seq[String] = getNotNullSeq(convTok4Fix, s"nlpcraft:sort:$notesName")
+                    val refIdxs: Seq[Int] = getNotNullSeq(convTok4Fix, s"nlpcraft:sort:$idxsName")
 
                     require(refIds.length == refIdxs.length)
 
@@ -251,7 +253,7 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
                         // 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 {
+                                vrntNotConvToks.find(isReference(_, refId, refIdx)) match {
                                     case Some(_) => data
                                     case None => notFound
                                 }
@@ -270,8 +272,8 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
 
                             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)
+                            convTok4Fix.getMetadata.put(s"nlpcraft:sort:$notesName", data.map(_._1).asJava)
+                            convTok4Fix.getMetadata.put(s"nlpcraft:sort:$idxsName", data.map(_._2).asJava)
                         }
                     }
                 }
@@ -279,38 +281,38 @@ class NCIntentSolver(intents: List[(NCIdlIntent/*Intent*/, NCIntentMatch => NCRe
                 process("bynotes", "byindexes")
                 process("subjnotes", "subjindexes")
             case "nlpcraft:limit" =>
-                val refId = convTok.meta[String]("nlpcraft:limit:note")
-                val refIdxs = convTok.meta[JList[Int]]("nlpcraft:limit:indexes").asScala
+                val refId = convTok4Fix.meta[String]("nlpcraft:limit:note")
+                val refIdxs = convTok4Fix.meta[JList[Int]]("nlpcraft:limit:indexes").asScala
 
                 require(refIdxs.size == 1)
 
                 val refIdx = refIdxs.head
 
-                if (!nonConvToks.exists(isReference(_, refId, refIdx))) {
-                    val ref = getForRecalc(refId, Seq(refIdx), _.size == 1).head
+                if (!vrntNotConvToks.exists(isReference(_, refId, refIdx))) {
+                    val newRef = getForRecalc(refId, Seq(refIdx), _.size == 1).head
 
-                    convTok.getMetadata.put(s"nlpcraft:limit:note", ref.getId)
-                    convTok.getMetadata.put(s"nlpcraft:limit:indexes", Collections.singletonList(ref.getIndex))
+                    convTok4Fix.getMetadata.put(s"nlpcraft:limit:note", newRef.getId)
+                    convTok4Fix.getMetadata.put(s"nlpcraft:limit:indexes", Collections.singletonList(newRef.getIndex))
                 }
 
             case "nlpcraft:relation" =>
-                val refId = convTok.meta[String]("nlpcraft:relation:note")
-                val refIdxs = convTok.meta[JList[Int]]("nlpcraft:relation:indexes").asScala.sorted
+                val refId = convTok4Fix.meta[String]("nlpcraft:relation:note")
+                val refIdxs = convTok4Fix.meta[JList[Int]]("nlpcraft:relation:indexes").asScala.sorted
 
-                val nonConvRefs = nonConvToks.filter(t => t.getId == refId && refIdxs.contains(t.getIndex))
+                val nonConvRefs = vrntNotConvToks.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, indexes=${refIdxs.mkString(", ")}]")
 
                 if (nonConvRefs.isEmpty) {
-                    val refs = getForRecalc(refId, refIdxs, _.size == refIdxs.size)
-                    val refsIds = refs.map(_.getId).distinct
+                    val newRefs = getForRecalc(refId, refIdxs, _.size == refIdxs.size)
+                    val newRefsIds = newRefs.map(_.getId).distinct
 
-                    if (refsIds.size != 1)
+                    if (newRefsIds.size != 1)
                         throw new NCE(s"Valid variant references are not found [id=$refId]")
 
-                    convTok.getMetadata.put(s"nlpcraft:relation:note", refsIds.head)
-                    convTok.getMetadata.put(s"nlpcraft:relation:indexes", refs.map(_.getIndex).asJava)
+                    convTok4Fix.getMetadata.put(s"nlpcraft:relation:note", newRefsIds.head)
+                    convTok4Fix.getMetadata.put(s"nlpcraft:relation:indexes", newRefs.map(_.getIndex).asJava)
                 }
 
             case _ => // No-op.
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCSortEnricher.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCSortEnricher.scala
index 965d80d..286c8b4 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCSortEnricher.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCSortEnricher.scala
@@ -377,19 +377,21 @@ object NCSortEnricher extends NCProbeEnricher {
 
                                     case TYPE_SUBJ_BY =>
                                         require(seq1.nonEmpty)
-                                        require(seq2.nonEmpty)
                                         require(sortToks.nonEmpty)
                                         require(byToks.nonEmpty)
 
-                                        res = Some(
-                                            Match(
-                                                asc = asc,
-                                                main = sortToks,
-                                                stop = byToks ++ orderToks,
-                                                subjSeq = seq1,
-                                                bySeq = seq2
+                                        if (seq2.isEmpty)
+                                            res = None
+                                        else
+                                            res = Some(
+                                                Match(
+                                                    asc = asc,
+                                                    main = sortToks,
+                                                    stop = byToks ++ orderToks,
+                                                    subjSeq = seq1,
+                                                    bySeq = seq2
+                                                )
                                             )
-                                        )
 
                                     case TYPE_BY =>
                                         require(seq1.nonEmpty)
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCLimitSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCLimitSpec.scala
index 8b9140f..7aeb9b9 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCLimitSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCLimitSpec.scala
@@ -26,19 +26,48 @@ import java.util.{List => JList}
 import scala.jdk.CollectionConverters.ListHasAsScala
 import scala.language.implicitConversions
 
-case class NCLimitSpecModelData(note: String, indexes: Seq[Int])
+case class NCLimitSpecModelData(intentId: String, note: String, indexes: Seq[Int])
 
 class NCLimitSpecModel extends NCSpecModelAdapter {
-    @NCIntent("intent=limit term(limit)~{tok_id() == 'nlpcraft:limit'} term(elem)~{has(tok_groups(), 'G')}")
-    private def onLimit(ctx: NCIntentMatch, @NCIntentTerm("limit") limit: NCToken): NCResult =
+    private def mkResult(intentId: String, limit: NCToken) =
         NCResult.json(
             mapper.writeValueAsString(
                 NCLimitSpecModelData(
+                    intentId = intentId,
                     note = limit.meta[String]("nlpcraft:limit:note"),
                     indexes = limit.meta[JList[Int]]("nlpcraft:limit:indexes").asScala.toSeq
                 )
             )
         )
+
+    @NCIntent(
+        "intent=limit1 " +
+        "term(limit)~{tok_id() == 'nlpcraft:limit'} " +
+        "term(elem)~{has(tok_groups(), 'G1')}"
+    )
+    private def onLimit1(ctx: NCIntentMatch, @NCIntentTerm("limit") limit: NCToken): NCResult =
+        mkResult(intentId = "limit1", limit = limit)
+
+    // `x` is mandatory (difference with `limit3`)
+    @NCIntent(
+        "intent=limit2 " +
+        "term(x)={tok_id() == 'X'} " +
+        "term(limit)~{tok_id() == 'nlpcraft:limit'} " +
+        "term(elem)~{has(tok_groups(), 'G1')}"
+    )
+    private def onLimit2(ctx: NCIntentMatch, @NCIntentTerm("limit") limit: NCToken): NCResult =
+        mkResult(intentId = "limit2", limit = limit)
+
+    // `y` is optional (difference with `limit2`)
+    @NCIntent(
+        "intent=limit3 " +
+            "term(y)~{tok_id() == 'Y'} " +
+            "term(limit)~{tok_id() == 'nlpcraft:limit'} " +
+            "term(elem)~{has(tok_groups(), 'G1')}"
+    )
+    private def onLimit3(ctx: NCIntentMatch, @NCIntentTerm("limit") limit: NCToken): NCResult =
+        mkResult(intentId = "limit3", limit = limit)
+
 }
 
 @NCTestEnvironment(model = classOf[NCLimitSpecModel], startClient = true)
@@ -46,16 +75,50 @@ class NCLimitSpec extends NCTestContext {
     private def extract(s: String): NCLimitSpecModelData = mapper.readValue(s, classOf[NCLimitSpecModelData])
 
     @Test
-    private[stm] def test(): Unit = {
+    private[stm] def test1(): Unit = {
         checkResult(
             "top 23 a a",
             extract,
-            NCLimitSpecModelData(note = "A", indexes = Seq(1))
+            // Reference to variant.
+            NCLimitSpecModelData(intentId = "limit1", note = "A2", indexes = Seq(1))
         )
         checkResult(
             "test test b b",
             extract,
-            NCLimitSpecModelData(note = "B", indexes = Seq(2))
+            // Reference to recalculated variant (new changed indexes).
+            NCLimitSpecModelData(intentId = "limit1", note = "B2", indexes = Seq(2))
+        )
+    }
+
+    @Test
+    private[stm] def test2(): Unit = {
+        checkResult(
+            "x test top 23 a a",
+            extract,
+            // Reference to variant.
+            NCLimitSpecModelData(intentId = "limit2", note = "A2", indexes = Seq(3))
+        )
+        checkResult(
+            "test x",
+            extract,
+            // Reference to conversation (tokens by these ID and indexes can be found in conversation).
+            NCLimitSpecModelData(intentId = "limit2", note = "A2", indexes = Seq(3))
+        )
+    }
+
+    @Test
+    private[stm] def test3(): Unit = {
+        checkResult(
+            "y test top 23 a a",
+            extract,
+            // Reference to variant.
+            NCLimitSpecModelData(intentId = "limit3", note = "A2", indexes = Seq(3))
+        )
+        checkResult(
+            "test y",
+            extract,
+            // Reference to conversation (tokens by these ID and indexes can be found in conversation).
+            NCLimitSpecModelData(intentId = "limit3", note = "A2", indexes = Seq(3))
         )
     }
 }
\ No newline at end of file
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCRelationSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCRelationSpec.scala
index c1d42c5..4198c77 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCRelationSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCRelationSpec.scala
@@ -26,19 +26,47 @@ import java.util.{List => JList}
 import scala.jdk.CollectionConverters.ListHasAsScala
 import scala.language.implicitConversions
 
-case class NCRelationSpecModelData(note: String, indexes: Seq[Int])
+case class NCRelationSpecModelData(intentId: String, note: String, indexes: Seq[Int])
 
 class NCRelationSpecModel extends NCSpecModelAdapter {
-    @NCIntent("intent=rel term(rel)~{tok_id() == 'nlpcraft:relation'} term(elem)~{has(tok_groups(), 'G')}*")
-    private def onRelation(ctx: NCIntentMatch, @NCIntentTerm("rel") rel: NCToken): NCResult =
+    private def mkResult(intentId: String, rel: NCToken) =
         NCResult.json(
             mapper.writeValueAsString(
                 NCRelationSpecModelData(
+                    intentId = intentId,
                     note = rel.meta[String]("nlpcraft:relation:note"),
                     indexes = rel.meta[JList[Int]]("nlpcraft:relation:indexes").asScala.toSeq
                 )
             )
         )
+
+    @NCIntent(
+        "intent=rel1 " +
+        "term(rel)~{tok_id() == 'nlpcraft:relation'} " +
+        "term(elem)~{has(tok_groups(), 'G1')}*"
+    )
+    private def onRelation1(ctx: NCIntentMatch, @NCIntentTerm("rel") rel: NCToken): NCResult =
+        mkResult(intentId = "rel1", rel = rel)
+
+    // `x` is mandatory (difference with `rel3`)
+    @NCIntent(
+        "intent=rel2 " +
+            "term(x)={tok_id() == 'X'} " +
+            "term(rel)~{tok_id() == 'nlpcraft:relation'} " +
+            "term(elem)~{has(tok_groups(), 'G1')}*"
+    )
+    private def onRelation2(ctx: NCIntentMatch, @NCIntentTerm("rel") rel: NCToken): NCResult =
+        mkResult(intentId = "rel2", rel = rel)
+
+    // `y` is optional (difference with `rel2`)
+    @NCIntent(
+        "intent=rel3 " +
+        "term(y)~{tok_id() == 'Y'} " +
+        "term(rel)~{tok_id() == 'nlpcraft:relation'} " +
+        "term(elem)~{has(tok_groups(), 'G1')}*"
+    )
+    private def onRelation3(ctx: NCIntentMatch, @NCIntentTerm("rel") rel: NCToken): NCResult =
+        mkResult(intentId = "rel3", rel = rel)
 }
 
 @NCTestEnvironment(model = classOf[NCRelationSpecModel], startClient = true)
@@ -46,16 +74,50 @@ class NCRelationSpec extends NCTestContext {
     private def extract(s: String): NCRelationSpecModelData = mapper.readValue(s, classOf[NCRelationSpecModelData])
 
     @Test
-    private[stm] def test(): Unit = {
+    private[stm] def test1(): Unit = {
         checkResult(
             "compare a a and a a",
             extract,
-            NCRelationSpecModelData(note = "A", indexes = Seq(1, 3))
+            // Reference to variant.
+            NCRelationSpecModelData(intentId = "rel1", note = "A2", indexes = Seq(1, 3))
         )
         checkResult(
             "b b and b b",
             extract,
-            NCRelationSpecModelData(note = "B", indexes = Seq(0, 2))
+            // Reference to recalculated variant (new changed indexes).
+            NCRelationSpecModelData(intentId = "rel1", note = "B2", indexes = Seq(0, 2))
+        )
+    }
+
+    @Test
+    private[stm] def test2(): Unit = {
+        checkResult(
+            "x compare a a and a a",
+            extract,
+            // Reference to variant.
+            NCRelationSpecModelData(intentId = "rel2", note = "A2", indexes = Seq(2, 4))
+        )
+        checkResult(
+            "test x",
+            extract,
+            // Reference to conversation (tokens by these ID and indexes can be found in conversation).
+            NCRelationSpecModelData(intentId = "rel2", note = "A2", indexes = Seq(2, 4))
+        )
+    }
+
+    @Test
+    private[stm] def test3(): Unit = {
+        checkResult(
+            "y compare a a and a a",
+            extract,
+            // Reference to variant.
+            NCRelationSpecModelData(intentId = "rel3", note = "A2", indexes = Seq(2, 4))
+        )
+        checkResult(
+            "test y",
+            extract,
+            // Reference to conversation (tokens by these ID and indexes can be found in conversation).
+            NCRelationSpecModelData(intentId = "rel3", note = "A2", indexes = Seq(2, 4))
         )
     }
 }
\ No newline at end of file
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala
index ed47ade..4658df6 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala
@@ -29,17 +29,24 @@ import scala.language.implicitConversions
 object NCSortSpecModelData {
     private def nvl[T](list: JList[T]): Seq[T] = if (list == null) Seq.empty else list.asScala.toSeq
 
-    def apply(subjnotes: JList[String], subjindexes: JList[Int], bynotes: JList[String], byindexes: JList[Int]):
-        NCSortSpecModelData = new
-            NCSortSpecModelData(
-                subjnotes = nvl(subjnotes),
-                subjindexes = nvl(subjindexes),
-                bynotes = nvl(bynotes),
-                byindexes = nvl(byindexes)
-            )
+    def apply(
+        intentId: String,
+        subjnotes: JList[String],
+        subjindexes: JList[Int],
+        bynotes: JList[String],
+        byindexes: JList[Int]
+    ): NCSortSpecModelData =
+        new NCSortSpecModelData(
+            intentId = intentId,
+            subjnotes = nvl(subjnotes),
+            subjindexes = nvl(subjindexes),
+            bynotes = nvl(bynotes),
+            byindexes = nvl(byindexes)
+        )
 }
 
 case class NCSortSpecModelData(
+    intentId: String,
     subjnotes: Seq[String] = Seq.empty,
     subjindexes: Seq[Int] = Seq.empty,
     bynotes: Seq[String] = Seq.empty,
@@ -47,11 +54,11 @@ case class NCSortSpecModelData(
 )
 
 class NCSortSpecModel extends NCSpecModelAdapter {
-    @NCIntent("intent=onBySort term(sort)~{tok_id() == 'nlpcraft:sort'} term(elem)~{has(tok_groups(), 'G')}")
-    private def onBySort(ctx: NCIntentMatch, @NCIntentTerm("sort") sort: NCToken): NCResult =
+    private def mkResult(intentId: String, sort: NCToken) =
         NCResult.json(
             mapper.writeValueAsString(
                 NCSortSpecModelData(
+                    intentId = intentId,
                     subjnotes = sort.meta[JList[String]]("nlpcraft:sort:subjnotes"),
                     subjindexes = sort.meta[JList[Int]]("nlpcraft:sort:subjindexes"),
                     bynotes = sort.meta[JList[String]]("nlpcraft:sort:bynotes"),
@@ -59,6 +66,44 @@ class NCSortSpecModel extends NCSpecModelAdapter {
                 )
             )
         )
+
+    @NCIntent(
+        "intent=onSort1 " +
+        "term(sort)~{tok_id() == 'nlpcraft:sort'} " +
+        "term(elem)~{has(tok_groups(), 'G1')}*"
+    )
+    private def onSort1(ctx: NCIntentMatch, @NCIntentTerm("sort") sort: NCToken): NCResult =
+        mkResult(intentId = "onSort1", sort = sort)
+
+    // `x` is mandatory (difference with `onSort3`)
+    @NCIntent(
+        "intent=onSort2 " +
+        "term(x)={tok_id() == 'X'} " +
+        "term(sort)~{tok_id() == 'nlpcraft:sort'} " +
+        "term(elem)~{has(tok_groups(), 'G1')}*"
+    )
+    private def onSort2(ctx: NCIntentMatch, @NCIntentTerm("sort") sort: NCToken): NCResult =
+        mkResult(intentId = "onSort2", sort = sort)
+
+    // `y` is optional (difference with `onSort2`)
+    @NCIntent(
+        "intent=onSort3 " +
+        "term(y)~{tok_id() == 'Y'} " +
+        "term(sort)~{tok_id() == 'nlpcraft:sort'} " +
+        "term(elem)~{has(tok_groups(), 'G1')}*"
+    )
+    private def onSort3(ctx: NCIntentMatch, @NCIntentTerm("sort") sort: NCToken): NCResult =
+        mkResult(intentId = "onSort3", sort = sort)
+
+    @NCIntent(
+        "intent=onSort4 " +
+        "term(z)~{tok_id() == 'Z'} " +
+        "term(elem1)~{has(tok_groups(), 'G1')}+ " +
+        "term(elem2)~{has(tok_groups(), 'G2')}+ " +
+        "term(sort)~{tok_id() == 'nlpcraft:sort'}"
+    )
+    private def onSort4(ctx: NCIntentMatch, @NCIntentTerm("sort") sort: NCToken): NCResult =
+        mkResult(intentId = "onSort4", sort = sort)
 }
 
 @NCTestEnvironment(model = classOf[NCSortSpecModel], startClient = true)
@@ -66,27 +111,124 @@ class NCSortSpec extends NCTestContext {
     private def extract(s: String): NCSortSpecModelData = mapper.readValue(s, classOf[NCSortSpecModelData])
 
     @Test
-    private[stm] def test(): Unit = {
+    private[stm] def testOnSort11(): Unit = {
         checkResult(
             "test test sort by a a",
             extract,
-            NCSortSpecModelData(bynotes = Seq("A"), byindexes = Seq(3))
+            // Reference to variant.
+            NCSortSpecModelData(intentId = "onSort1", bynotes = Seq("A2"), byindexes = Seq(3))
         )
         checkResult(
             "test b b",
             extract,
-            NCSortSpecModelData(bynotes = Seq("B"), byindexes = Seq(1))
+            // Reference to variant.
+            NCSortSpecModelData(intentId = "onSort1", bynotes = Seq("B2"), byindexes = Seq(1))
         )
         checkResult(
             "test test sort a a by a a",
             extract,
-            NCSortSpecModelData(subjnotes = Seq("A"), subjindexes = Seq(3), bynotes = Seq("A"), byindexes = Seq(5))
+            // Reference to variant.
+            NCSortSpecModelData(
+                intentId = "onSort1",
+                subjnotes = Seq("A2"),
+                subjindexes = Seq(3),
+                bynotes = Seq("A2"),
+                byindexes = Seq(5)
+            )
+        )
+
+        checkResult(
+            "test test sort a a, a a by a a, a a",
+            extract,
+            // Reference to variant.
+            NCSortSpecModelData(
+                intentId = "onSort1",
+                subjnotes = Seq("A2", "A2"),
+                subjindexes = Seq(3, 5),
+                bynotes = Seq("A2", "A2"),
+                byindexes = Seq(7, 9)
+            )
+        )
+    }
+
+    @Test
+    private[stm] def testOnSort12(): Unit = {
+        checkResult(
+            "test test sort by a a",
+            extract,
+            // Reference to variant.
+            NCSortSpecModelData(intentId = "onSort1", bynotes = Seq("A2"), byindexes = Seq(3))
+        )
+
+        checkResult(
+            "test b b",
+            extract,
+            // Reference to recalculated variant (new changed indexes).
+            NCSortSpecModelData(intentId = "onSort1", bynotes = Seq("B2"), byindexes = Seq(1))
+        )
+    }
+
+    @Test
+    private[stm] def testOnSort2(): Unit = {
+        checkResult(
+            "test test x sort by a a",
+            extract,
+            // Reference to variant.
+            NCSortSpecModelData(intentId = "onSort2", bynotes = Seq("A2"), byindexes = Seq(4))
+        )
+
+        checkResult(
+            "test x",
+            extract,
+            // Reference to conversation (tokens by these ID and indexes can be found in conversation).
+            NCSortSpecModelData(intentId = "onSort2", bynotes = Seq("A2"), byindexes = Seq(4))
+        )
+    }
+
+    @Test
+    private[stm] def testOnSort3(): Unit = {
+        checkResult(
+            "test test y sort by a a",
+            extract,
+            // Reference to variant.
+            NCSortSpecModelData(intentId = "onSort3", bynotes = Seq("A2"), byindexes = Seq(4))
+        )
+
+        checkResult(
+            "test y",
+            extract,
+            // Reference to conversation (tokens by these ID and indexes can be found in conversation).
+            NCSortSpecModelData(intentId = "onSort3", bynotes = Seq("A2"), byindexes = Seq(4))
         )
+    }
 
-//        checkResult(
-//            "test test sort a a, a a by a a, a a",
-//            extract,
-//            NCSortSpecModelData(subjnotes = Seq("A"), subjindexes = Seq(2, 3), bynotes = Seq("A"), byindexes = Seq(5, 6))
-//        )
+    // Like `testOnSort11` and `testOnSort12`, but more complex.
+    @Test
+    private[stm] def testOnSort4(): Unit = {
+        checkResult(
+            "test z test sort x by a a",
+            extract,
+            // Reference to variant.
+            NCSortSpecModelData(
+                intentId = "onSort4",
+                subjnotes = Seq("X"),
+                subjindexes = Seq(4),
+                bynotes = Seq("A2"),
+                byindexes = Seq(6)
+            )
+        )
+
+        checkResult(
+            "test z y b b",
+            extract,
+            // Reference to recalculated variant (new changed indexes).
+            NCSortSpecModelData(
+                intentId = "onSort4",
+                subjnotes = Seq("Y"),
+                subjindexes = Seq(2),
+                bynotes = Seq("B2"),
+                byindexes = Seq(3)
+            )
+        )
     }
 }
\ No newline at end of file
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSpecModelAdapter.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSpecModelAdapter.scala
index 7d0c5de..81e5563 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSpecModelAdapter.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSpecModelAdapter.scala
@@ -34,8 +34,13 @@ object NCSpecModelAdapter {
 class NCSpecModelAdapter extends NCModelAdapter("nlpcraft.stm.idxs.test", "STM Indexes Test Model", "1.0") {
     override def getElements: util.Set[NCElement] =
         Set(
-            mkElement("A", "G", "a a"),
-            mkElement("B", "G", "b b")
+            mkElement("A2", "G1", "a a"),
+            mkElement("B2", "G1", "b b"),
+
+            mkElement("X", "G2", "x"),
+            mkElement("Y", "G2", "y"),
+
+            mkElement("Z", "G3", "z")
         ).asJava
 
     private def mkElement(id: String, group: String, syns: String*): NCElement =
@@ -48,6 +53,4 @@ class NCSpecModelAdapter extends NCModelAdapter("nlpcraft.stm.idxs.test", "STM I
             }
             override def getGroups: util.List[String] = Collections.singletonList(group)
         }
-
-
 }
diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCEnricherSortSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCEnricherSortSpec.scala
index df089e3..100334f 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCEnricherSortSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/probe/mgrs/nlp/enrichers/sort/NCEnricherSortSpec.scala
@@ -17,10 +17,10 @@
 
 package org.apache.nlpcraft.probe.mgrs.nlp.enrichers.sort
 
-import org.apache.nlpcraft.{NCTestElement, NCTestEnvironment}
 import org.apache.nlpcraft.model.NCElement
 import org.apache.nlpcraft.probe.mgrs.nlp.enrichers.NCTestSortTokenType._
 import org.apache.nlpcraft.probe.mgrs.nlp.enrichers.{NCDefaultTestModel, NCEnricherBaseSpec, NCTestNlpToken => nlp, NCTestSortToken => srt, NCTestUserToken => usr}
+import org.apache.nlpcraft.{NCTestElement, NCTestEnvironment}
 import org.junit.jupiter.api.Test
 
 import java.util
@@ -222,177 +222,6 @@ class NCEnricherSortSpec extends NCEnricherBaseSpec {
                 nlp(text = ", asc", isStop = true)
             ),
             _ => checkExists(
-                "sort A",
-                srt(text = "sort", typ = SUBJ_ONLY, note = "A", index = 1),
-                usr("A", "A")
-            ),
-            _ => checkExists(
-                "sort A by A",
-                srt(text = "sort", subjNote = "A", subjIndex = 1, byNote = "A", byIndex = 3),
-                usr(text = "A", id = "A"),
-                nlp(text = "by", isStop = true),
-                usr(text = "A", id = "A")
-            ),
-            _ => checkExists(
-                "sort A, C by A, C",
-                srt(text = "sort", subjNotes = Seq("A", "C"), subjIndexes = Seq(1, 3), byNotes = Seq("A", "C"), byIndexes = Seq(5, 7)),
-                usr(text = "A", id = "A"),
-                nlp(text = ",", isStop = true),
-                usr(text = "C", id = "C"),
-                nlp(text = "by", isStop = true),
-                usr(text = "A", id = "A"),
-                nlp(text = ",", isStop = true),
-                usr(text = "C", id = "C")
-            ),
-            _ => checkExists(
-                "sort A C by A C",
-                srt(text = "sort", subjNotes = Seq("A", "C"), subjIndexes = Seq(1, 2), byNotes = Seq("A", "C"), byIndexes = Seq(4, 5)),
-                usr(text = "A", id = "A"),
-                usr(text = "C", id = "C"),
-                nlp(text = "by", isStop = true),
-                usr(text = "A", id = "A"),
-                usr(text = "C", id = "C")
-            ),
-            _ => checkExists(
-                "sort A B by A B",
-                srt(text = "sort", subjNotes = Seq("A", "B"), subjIndexes = Seq(1, 2), byNotes = Seq("A", "B"), byIndexes = Seq(4, 5)),
-                usr(text = "A", id = "A"),
-                usr(text = "B", id = "B"),
-                nlp(text = "by", isStop = true),
-                usr(text = "A", id = "A"),
-                usr(text = "B", id = "B")
-            ),
-            _ => checkExists(
-                "sort A B by A B",
-                srt(text = "sort", subjNote = "AB", subjIndex = 1, byNote = "AB", byIndex = 3),
-                usr(text = "A B", id = "AB"),
-                nlp(text = "by", isStop = true),
-                usr(text = "A B", id = "AB")
-            ),
-            _ => checkExists(
-                "A classify",
-                usr(text = "A", id = "A"),
-                srt(text = "classify", typ = SUBJ_ONLY, note = "A", index = 0)
-            ),
-            _ => checkExists(
-                "the A the classify",
-                nlp(text = "the", isStop = true),
-                usr(text = "A", id = "A"),
-                nlp(text = "the", isStop = true),
-                srt(text = "classify", typ = SUBJ_ONLY, note = "A", index = 1)
-            ),
-            _ => checkExists(
-                "segment A by top down",
-                srt(text = "segment", typ = SUBJ_ONLY, note = "A", index = 1, asc = false),
-                usr(text = "A", id = "A"),
-                nlp(text = "by top down", isStop = true)
-            ),
-            _ => checkExists(
-                "segment A in bottom up order",
-                srt(text = "segment", typ = SUBJ_ONLY, note = "A", index = 1, asc = true),
-                usr(text = "A", id = "A"),
-                nlp(text = "in bottom up order", isStop = true)
-            ),
-            // `by` is redundant word here
-            _ => checkExists(
-                "segment A by in bottom up order",
-                srt(text = "segment", typ = SUBJ_ONLY, note = "A", index = 1),
-                usr(text = "A", id = "A"),
-                nlp(text = "by"),
-                nlp(text = "in"),
-                nlp(text = "bottom"),
-                nlp(text = "up"),
-                nlp(text = "order")
-            ),
-            _ => checkExists(
-                "the segment the A the in bottom up the order the",
-                nlp(text = "the", isStop = true),
-                srt(text = "segment", typ = SUBJ_ONLY, note = "A", index = 3, asc = true),
-                nlp(text = "the", isStop = true),
-                usr(text = "A", id = "A"),
-                nlp(text = "the in bottom up the order the", isStop = true)
-            ),
-            _ => checkExists(
-                "the segment the A the by bottom up the order the",
-                nlp(text = "the", isStop = true),
-                srt(text = "segment", typ = SUBJ_ONLY, note = "A", index = 3, asc = true),
-                nlp(text = "the", isStop = true),
-                usr(text = "A", id = "A"),
-                nlp(text = "the by bottom up the order the", isStop = true)
-            ),
-            _ => checkExists(
-                "A classify",
-                usr(text = "A", id = "A"),
-                srt(text = "classify", typ = SUBJ_ONLY, note = "A", index = 0)
-            ),
-            _ => checkAll(
-                "A B classify",
-                Seq(
-                    usr(text = "A B", id = "AB"),
-                    srt(text = "classify", typ = SUBJ_ONLY, note = "AB", index = 0)
-                ),
-                Seq(
-                    usr(text = "A", id = "A"),
-                    usr(text = "B", id = "B"),
-                    srt(text = "classify", subjNotes = Seq("A", "B"), subjIndexes = Seq(0, 1))
-                ),
-                Seq(
-                    usr(text = "A", id = "A"),
-                    usr(text = "B", id = "B"),
-                    srt(text = "classify", subjNotes = Seq("B"), subjIndexes = Seq(1))
-                )
-            ),
-            _ => checkAll(
-                "D classify",
-                Seq(
-                    usr(text = "D", id = "D1"),
-                    srt(text = "classify", typ = SUBJ_ONLY, note = "D1", index = 0)
-                ),
-                Seq(
-                    usr(text = "D", id = "D2"),
-                    srt(text = "classify", typ = SUBJ_ONLY, note = "D2", index = 0)
-                )
-            ),
-            _ => checkAll(
-                "sort by A",
-                Seq(
-                    srt(text = "sort by", typ = BY_ONLY, note = "A", index = 1),
-                    usr(text = "A", id = "A")
-                )
-            ),
-            _ => checkExists(
-                "organize by A, B top down",
-                srt(text = "organize by", byNotes = Seq("A", "B"), byIndexes = Seq(1, 3), asc = Some(false)),
-                usr(text = "A", id = "A"),
-                nlp(text = ",", isStop = true),
-                usr(text = "B", id = "B"),
-                nlp(text = "top down", isStop = true)
-            ),
-            _ => checkExists(
-                "organize by A, B from bottom up order",
-                srt(text = "organize by", byNotes = Seq("A", "B"), byIndexes = Seq(1, 3), asc = Some(true)),
-                usr(text = "A", id = "A"),
-                nlp(text = ",", isStop = true),
-                usr(text = "B", id = "B"),
-                nlp(text = "from bottom up order", isStop = true)
-            ),
-            _ => checkExists(
-                "organize by A, B the descending",
-                srt(text = "organize by", byNotes = Seq("A", "B"), byIndexes = Seq(1, 3), asc = Some(false)),
-                usr(text = "A", id = "A"),
-                nlp(text = ",", isStop = true),
-                usr(text = "B", id = "B"),
-                nlp(text = "the descending", isStop = true)
-            ),
-            _ => checkExists(
-                "organize by A, B, asc",
-                srt(text = "organize by", byNotes = Seq("A", "B"), byIndexes = Seq(1, 3), asc = Some(true)),
-                usr(text = "A", id = "A"),
-                nlp(text = ",", isStop = true),
-                usr(text = "B", id = "B"),
-                nlp(text = ", asc", isStop = true)
-            ),
-            _ => checkExists(
                 "sort A the A the A",
                 srt(text = "sort", typ = SUBJ_ONLY, note = "wrapperA", index = 1),
                 usr("A A A", "wrapperA"),

[incubator-nlpcraft] 02/03: Merge branch 'master' into NLPCRAFT-376

Posted by se...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 483a0003dd65058058d91184b8e15f9f9f47a955
Merge: 004a3dc fef7822
Author: Sergey Kamov <sk...@gmail.com>
AuthorDate: Thu Jul 29 09:47:20 2021 +0300

    Merge branch 'master' into NLPCRAFT-376

 .../nlpcraft/model/tools/cmdline/NCCli.scala       | 38 ++++++++++++++++++----
 .../model/tools/cmdline/NCCliCommands.scala        | 12 +++----
 .../tools/cmdline/NCCliFileNameCompleter.java      |  7 ++--
 3 files changed, 42 insertions(+), 15 deletions(-)

[incubator-nlpcraft] 01/03: WIP.

Posted by se...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 004a3dc373c8450c5fc55927cba5e9599ef03f62
Author: Sergey Kamov <sk...@gmail.com>
AuthorDate: Wed Jul 28 16:16:49 2021 +0300

    WIP.
---
 .../nlpcraft/models/stm/indexes/NCSortSpec.scala   | 30 ++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala
index a33f0cb..ed47ade 100644
--- a/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala
+++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/models/stm/indexes/NCSortSpec.scala
@@ -26,6 +26,19 @@ import java.util.{List => JList}
 import scala.jdk.CollectionConverters.ListHasAsScala
 import scala.language.implicitConversions
 
+object NCSortSpecModelData {
+    private def nvl[T](list: JList[T]): Seq[T] = if (list == null) Seq.empty else list.asScala.toSeq
+
+    def apply(subjnotes: JList[String], subjindexes: JList[Int], bynotes: JList[String], byindexes: JList[Int]):
+        NCSortSpecModelData = new
+            NCSortSpecModelData(
+                subjnotes = nvl(subjnotes),
+                subjindexes = nvl(subjindexes),
+                bynotes = nvl(bynotes),
+                byindexes = nvl(byindexes)
+            )
+}
+
 case class NCSortSpecModelData(
     subjnotes: Seq[String] = Seq.empty,
     subjindexes: Seq[Int] = Seq.empty,
@@ -39,8 +52,10 @@ class NCSortSpecModel extends NCSpecModelAdapter {
         NCResult.json(
             mapper.writeValueAsString(
                 NCSortSpecModelData(
-                    bynotes = sort.meta[JList[String]]("nlpcraft:sort:bynotes").asScala.toSeq,
-                    byindexes = sort.meta[JList[Int]]("nlpcraft:sort:byindexes").asScala.toSeq
+                    subjnotes = sort.meta[JList[String]]("nlpcraft:sort:subjnotes"),
+                    subjindexes = sort.meta[JList[Int]]("nlpcraft:sort:subjindexes"),
+                    bynotes = sort.meta[JList[String]]("nlpcraft:sort:bynotes"),
+                    byindexes = sort.meta[JList[Int]]("nlpcraft:sort:byindexes")
                 )
             )
         )
@@ -62,5 +77,16 @@ class NCSortSpec extends NCTestContext {
             extract,
             NCSortSpecModelData(bynotes = Seq("B"), byindexes = Seq(1))
         )
+        checkResult(
+            "test test sort a a by a a",
+            extract,
+            NCSortSpecModelData(subjnotes = Seq("A"), subjindexes = Seq(3), bynotes = Seq("A"), byindexes = Seq(5))
+        )
+
+//        checkResult(
+//            "test test sort a a, a a by a a, a a",
+//            extract,
+//            NCSortSpecModelData(subjnotes = Seq("A"), subjindexes = Seq(2, 3), bynotes = Seq("A"), byindexes = Seq(5, 6))
+//        )
     }
 }
\ No newline at end of file