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 5861102 WIP.
5861102 is described below
commit 5861102a9ece9a8bd1a6773f4e59e89338893638
Author: Aaron Radzinski <[email protected]>
AuthorDate: Fri Mar 12 17:55:47 2021 -0800
WIP.
---
.../apache/nlpcraft/examples/alarm/AlarmModel.java | 10 +-
.../nlpcraft/examples/alarm/alarm_model.json | 2 +-
.../org/apache/nlpcraft/examples/alarm/intents.nc | 2 +-
.../apache/nlpcraft/examples/time/TimeModel.java | 7 +-
.../probe/mgrs/deploy/NCDeployManager.scala | 160 +++++++++++++--------
5 files changed, 108 insertions(+), 73 deletions(-)
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/AlarmModel.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/AlarmModel.java
index c741885..1b71497 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/AlarmModel.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/AlarmModel.java
@@ -45,15 +45,7 @@ public class AlarmModel extends NCModelFileAdapter {
super("org/apache/nlpcraft/examples/alarm/alarm_model.json");
}
- @NCIntent("intent=i11 term={true}")
- @NCIntent("intent=i12 term={true}")
- NCResult cb1(NCIntentMatch ctx) { return NCResult.text(""); }
-
- @NCIntent("intent=i21 term={true}")
- @NCIntent("intent=i22 term={true}")
- NCResult cb2(NCIntentMatch ctx) { return NCResult.text(""); }
-
- /**
+ /**
* Callback on intent match.
*
* @param ctx Intent solver context.
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/alarm_model.json
b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/alarm_model.json
index 14e8821..e441ff2 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/alarm_model.json
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/alarm_model.json
@@ -34,6 +34,6 @@
}
],
"intents": [
- "import('org/apache/nlpcraft/examples/alarm/intents.nc')"
+ "import('org/apache/nlpcraft/examples/alarm/intents.nc')" // Import
intents from external file.
]
}
\ No newline at end of file
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/intents.nc
b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/intents.nc
index 875210a..f51d281 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/intents.nc
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/alarm/intents.nc
@@ -15,7 +15,7 @@
* limitations under the License.
*/
-// Fragments.
+// Fragments (mostly for demo purposes here).
fragment=buzz term~{id() == 'x:alarm'}
fragment=when
term(nums)~{
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModel.java
b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModel.java
index 1601943..b8e87c2 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModel.java
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/examples/time/TimeModel.java
@@ -40,6 +40,9 @@ import static java.time.format.FormatStyle.*;
* <p>
* See 'README.md' file in the same folder for running and testing
instructions.
*/
+// Declaring intents on the class level for demo purposes.
+@NCIntent("intent=intent2 term~{id() == 'x:time'} term(city)~{id() ==
'nlpcraft:city'}")
+@NCIntent("intent=intent1 term={id() == 'x:time'}")
public class TimeModel extends NCModelFileAdapter {
// Medium data formatter.
static private final DateTimeFormatter FMT =
DateTimeFormatter.ofLocalizedDateTime(MEDIUM);
@@ -92,7 +95,7 @@ public class TimeModel extends NCModelFileAdapter {
* @param cityTok Token for 'geo' term.
* @return Query result.
*/
- @NCIntent("intent=intent2 term~{id() == 'x:time'} term(city)~{id() ==
'nlpcraft:city'}")
+ @NCIntentRef("intent2")
@NCIntentSample({
"What time is it now in New York City?",
"What's the current time in Moscow?",
@@ -119,7 +122,7 @@ public class TimeModel extends NCModelFileAdapter {
* @param ctx Intent solver context.
* @return Query result.
*/
- @NCIntent("intent=intent1 term={id() == 'x:time'}")
+ @NCIntentRef("intent1")
@NCIntentSample({
"What's the local time?"
})
diff --git
a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala
b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala
index cbea98c..daac10c 100644
---
a/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala
+++
b/nlpcraft/src/main/scala/org/apache/nlpcraft/probe/mgrs/deploy/NCDeployManager.scala
@@ -474,8 +474,9 @@ object NCDeployManager extends NCService with
DecorateAsScala {
// Check the uniqueness of intent IDs.
U.getDups(intents.map(_._1).toSeq.map(_.id)) match {
case ids if ids.nonEmpty ⇒
- throw new NCE(s"Duplicate intent IDs found [" +
+ throw new NCE(s"Duplicate intent IDs [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"ids=${ids.mkString(",")}" +
s"]")
case _ ⇒ ()
@@ -1169,12 +1170,12 @@ object NCDeployManager extends NCService with
DecorateAsScala {
require(tokParamTypes.length == paramGenTypes.length)
// Checks parameters.
- checkTypes(mdlId, mtd, tokParamTypes, paramGenTypes, ctxFirstParam)
+ checkTypes(mdl, mtd, tokParamTypes, paramGenTypes, ctxFirstParam)
// Checks limits.
val allLimits = terms.map(t ⇒ t.id.orNull → (t.min, t.max)).toMap
- checkMinMax(mdlId, mtd, tokParamTypes, termIds.map(allLimits),
ctxFirstParam)
+ checkMinMax(mdl, mtd, tokParamTypes, termIds.map(allLimits),
ctxFirstParam)
// Prepares invocation method.
(ctx: NCIntentMatch) ⇒ {
@@ -1317,16 +1318,23 @@ object NCDeployManager extends NCService with
DecorateAsScala {
/**
*
- * @param mdlId
+ * @param mdl
* @param mtd
* @param paramCls
* @param paramGenTypes
* @param ctxFirstParam
*/
@throws[NCE]
- private def checkTypes(mdlId: String, mtd: Method, paramCls:
Seq[Class[_]], paramGenTypes: Seq[Type], ctxFirstParam: Boolean): Unit = {
+ private def checkTypes(
+ mdl: NCModel,
+ mtd: Method,
+ paramCls: Seq[Class[_]],
+ paramGenTypes: Seq[Type],
+ ctxFirstParam: Boolean): Unit = {
require(paramCls.length == paramGenTypes.length)
+ val mdlId = mdl.getId
+
paramCls.zip(paramGenTypes).zipWithIndex.foreach { case ((pClass,
pGenType), i) ⇒
def mkArg(): String = arg2Str(mtd, i, ctxFirstParam)
@@ -1340,6 +1348,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
if (compType != CLS_TOKEN)
throw new NCE(s"Unexpected array element type for
@NCIntentTerm annotated argument [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"type=${class2Str(compType)}, " +
s"arg=${mkArg()}" +
s"]")
@@ -1355,6 +1364,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
throw new NCE(
s"Unexpected generic types count for
@NCIntentTerm annotated argument [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"count=${compTypes.length}, " +
s"arg=${mkArg()}" +
s"]")
@@ -1369,6 +1379,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
if (genClass != CLS_TOKEN)
throw new NCE(s"Unexpected generic type
for @NCIntentTerm annotated argument [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"type=${class2Str(genClass)}, " +
s"arg=${mkArg()}" +
s"]")
@@ -1383,12 +1394,14 @@ object NCDeployManager extends NCService with
DecorateAsScala {
throw new NCE(
s"Unexpected Kotlin generic type for
@NCIntentTerm annotated argument [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"type=${wc2Str(wildcardType)}, " +
s"arg=${mkArg()}" +
s"]")
case _ ⇒
throw new NCE(s"Unexpected generic type for
@NCIntentTerm annotated argument [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"type=${compType.getTypeName}, " +
s"arg=${mkArg()}" +
s"]")
@@ -1396,6 +1409,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
case _ ⇒ throw new NCE(s"Unexpected parameter type for
@NCIntentTerm annotated argument [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"type=${pGenType.getTypeName}, " +
s"arg=${mkArg()}" +
s"]")
@@ -1404,6 +1418,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
else
throw new NCE(s"Unexpected parameter type for @NCIntentTerm
annotated argument [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"type=${class2Str(pClass)}, " +
s"arg=${mkArg()}" +
s"]")
@@ -1412,7 +1427,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
/**
*
- * @param mdlId
+ * @param mdl
* @param mtd
* @param paramCls
* @param limits
@@ -1420,31 +1435,37 @@ object NCDeployManager extends NCService with
DecorateAsScala {
*/
@throws[NCE]
private def checkMinMax(
- mdlId: String,
+ mdl: NCModel,
mtd: Method,
paramCls: Seq[Class[_]],
limits: Seq[(Int, Int)],
ctxFirstParam: Boolean): Unit = {
require(paramCls.length == limits.length)
+ val mdlId = mdl.getId
+
paramCls.zip(limits).zipWithIndex.foreach { case ((cls, (min, max)),
i) ⇒
def mkArg(): String = arg2Str(mtd, i, ctxFirstParam)
val p1 = "its @NCIntentTerm annotated argument"
- val p2 = s"[mdlId=$mdlId, arg=${mkArg()}]"
+ val p2 = s"[" +
+ s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
+ s"arg=${mkArg()}" +
+ s"]"
// Argument is single token but defined as not single token.
if (cls == CLS_TOKEN && (min != 1 || max != 1))
- throw new NCE(s"@Intent term must have [1,1] quantifier
because $p1 is a single value $p2")
+ throw new NCE(s"Intent term must have [1,1] quantifier because
$p1 is a single value $p2")
// Argument is not single token but defined as single token.
else if (cls != CLS_TOKEN && (min == 1 && max == 1))
- throw new NCE(s"@Intent term has [1,1] quantifier but $p1 is
not a single value $p2")
+ throw new NCE(s"Intent term has [1,1] quantifier but $p1 is
not a single value $p2")
// Argument is optional but defined as not optional.
else if ((cls == CLS_SCALA_OPT || cls == CLS_JAVA_OPT) && (min !=
0 || max != 1))
- throw new NCE(s"@Intent term must have [0,1] quantifier
because $p1 is optional $p2")
+ throw new NCE(s"Intent term must have [0,1] quantifier because
$p1 is optional $p2")
// Argument is not optional but defined as optional.
else if ((cls != CLS_SCALA_OPT && cls != CLS_JAVA_OPT) && (min ==
0 && max == 1))
- throw new NCE(s"@Intent term has [0,1] quantifier but $p1 is
not optional $p2")
+ throw new NCE(s"Intent term has [0,1] quantifier but $p1 is
not optional $p2")
}
}
@@ -1467,55 +1488,73 @@ object NCDeployManager extends NCService with
DecorateAsScala {
@throws[NCE]
private def scanIntents(mdl: NCModel): Set[Intent] = {
val mdlId = mdl.getId
+ val intentDecls = mutable.Buffer.empty[NCDslIntent]
val intents = mutable.Buffer.empty[Intent]
-
+
+ // First, get intent declarations from the JSON/YAML file, if any.
+ mdl match {
+ case adapter: NCModelFileAdapter ⇒
+ intentDecls ++= adapter
+ .getIntents
+ .asScala
+ .flatMap(NCDslCompiler.compileIntents(_, mdl,
mdl.getOrigin))
+
+ case _ ⇒ ()
+ }
+
+ // Second, scan class for class-level @NCIntent annotations (intent
declarations).
+ val mdlCls = mdl.meta[String](MDL_META_MODEL_CLASS_KEY)
+
+ if (mdlCls != null) {
+ try {
+ val cls = Class.forName(mdlCls)
+
+ for (ann ← cls.getAnnotationsByType(CLS_INTENT); intent ←
NCDslCompiler.compileIntents(ann.value(), mdl, mdlCls))
+ if (intentDecls.exists(_.id == intent.id))
+ throw new NCE(s"Duplicate intent ID [" +
+ s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
+ s"class=$mdlCls, " +
+ s"id=${intent.id}" +
+ s"]")
+ else
+ intentDecls += intent
+ }
+ catch {
+ case _: ClassNotFoundException ⇒ throw new NCE(s"Failed to
scan class for @NCIntent annotation: $mdlCls")
+ }
+ }
+
+ // Third, scan all methods for intent-callback bindings.
for (m ← getAllMethods(mdl)) {
- val mStr = method2Str(m)
+ val mtdStr = method2Str(m)
// Process inline intent declarations by @NCIntent annotation.
- for (ann ← m.getAnnotationsByType(CLS_INTENT); intent ←
NCDslCompiler.compileIntents(ann.value(), mdl, mStr))
- intents += (intent → prepareCallback(m, mdl, intent))
-
+ for (ann ← m.getAnnotationsByType(CLS_INTENT); intent ←
NCDslCompiler.compileIntents(ann.value(), mdl, mtdStr))
+ if (intentDecls.exists(_.id == intent.id) ||
intents.exists(_._1.id == intent.id))
+ throw new NCE(s"Duplicate intent ID [" +
+ s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
+ s"callback=$mtdStr, " +
+ s"id=${intent.id}" +
+ s"]")
+ else
+ intents += (intent → prepareCallback(m, mdl, intent))
+
// Process intent references from @NCIntentRef annotation.
for (ann ← m.getAnnotationsByType(CLS_INTENT_REF)) {
- intents += (mdl match {
- case adapter: NCModelFileAdapter ⇒
- val refId = ann.value().trim
-
- val compiledIntents = adapter
- .getIntents
- .asScala
- .flatMap(NCDslCompiler.compileIntents(_, mdl,
mStr))
-
- U.getDups(compiledIntents.map(_.id)) match {
- case ids if ids.nonEmpty ⇒
- throw new NCE(s"Duplicate intent IDs found [" +
- s"mdlId=$mdlId, " +
- s"origin=${adapter.getOrigin}, " +
- s"callback=$mStr, " +
- s"ids=${ids.mkString(",")}" +
- s"]")
-
- case _ ⇒ ()
- }
-
- compiledIntents.find(_.id == refId) match {
- case Some(intent) ⇒ (intent, prepareCallback(m,
mdl, intent))
- case None ⇒
- throw new NCE(
- s"@IntentRef($refId) references unknown
intent ID [" +
- s"mdlId=$mdlId, " +
- s"refId=$refId, " +
- s"callback=$mStr" +
- s"]")
- }
-
- case _ ⇒
- throw new NCE(s"@IntentRef annotation can only be used
for models extending 'NCModelFileAdapter' class [" +
+ val refId = ann.value().trim
+
+ intentDecls.find(_.id == refId) match {
+ case Some(intent) ⇒ intents += (intent →
prepareCallback(m, mdl, intent))
+ case None ⇒ throw new NCE(
+ s"""@NCIntentRef("$refId") references unknown intent
ID [""" +
s"mdlId=$mdlId, " +
- s"callback=$mStr" +
+ s"mdlOrigin=${mdl.getOrigin}, " +
+ s"refId=$refId, " +
+ s"callback=$mtdStr" +
s"]")
- })
+ }
}
}
@@ -1534,7 +1573,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
val samples = mutable.Buffer.empty[Sample]
for (m ← getAllMethods(mdl)) {
- val mStr = method2Str(m)
+ val mtdStr = method2Str(m)
val smpAnns = m.getAnnotationsByType(CLS_SAMPLE)
val intAnns = m.getAnnotationsByType(CLS_INTENT)
@@ -1542,19 +1581,19 @@ object NCDeployManager extends NCService with
DecorateAsScala {
if (smpAnns.nonEmpty) {
if (intAnns.isEmpty && refAnns.isEmpty)
- throw new NCE(s"@IntentSample annotation without
corresponding @NCIntent or @NCIntentRef annotations: $mStr")
+ throw new NCE(s"@NCIntentSample annotation without
corresponding @NCIntent or @NCIntentRef annotations: $mtdStr")
else {
val seqSeq = smpAnns.toSeq.map(_.value().toSeq)
if (seqSeq.exists(_.isEmpty))
- logger.warn(s"@IntentSample annotation is empty:
$mStr")
+ logger.warn(s"@NCIntentSample annotation is empty:
$mtdStr")
if (U.containsDups(seqSeq.flatten.toList))
- logger.warn(s"@IntentSample annotation has duplicates:
$mStr")
+ logger.warn(s"@NCIntentSample annotation has
duplicates: $mtdStr")
val distinct = seqSeq.map(_.distinct).distinct
for (ann ← intAnns) {
- for (intent ←
NCDslCompiler.compileIntents(ann.value(), mdl, mStr))
+ for (intent ←
NCDslCompiler.compileIntents(ann.value(), mdl, mtdStr))
samples += (intent.id → distinct)
}
for (ann ← refAnns)
@@ -1562,7 +1601,7 @@ object NCDeployManager extends NCService with
DecorateAsScala {
}
}
else if (intAnns.nonEmpty || refAnns.nonEmpty)
- logger.warn(s"@IntentSample annotation is missing for: $mStr")
+ logger.warn(s"@NCIntentSample annotation is missing for:
$mtdStr")
}
if (samples.nonEmpty) {
@@ -1590,8 +1629,9 @@ object NCDeployManager extends NCService with
DecorateAsScala {
val seq: Seq[String] = sNorm.split("
").map(NCNlpPorterStemmer.stem)
if (!allSyns.exists(_.intersect(seq).nonEmpty))
- logger.warn(s"@IntentSample sample doesn't
contain any direct synonyms [" +
+ logger.warn(s"@NCIntentSample sample doesn't
contain any direct synonyms [" +
s"mdlId=$mdlId, " +
+ s"mdlOrigin=${mdl.getOrigin}, " +
s"sample='$s'" +
s"]")
}