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 2022/02/24 14:39:28 UTC
[incubator-nlpcraft] 01/01: RU Lightswitch simplified example.
This is an automated email from the ASF dual-hosted git repository.
sergeykamov pushed a commit to branch NLPCRAFT-479
in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
commit c357f02c0a4817596c2f9e36928e5a10f35ff0ca
Author: Sergey Kamov <sk...@gmail.com>
AuthorDate: Thu Feb 24 17:38:12 2022 +0300
RU Lightswitch simplified example.
---
nlpcraft-examples/lightswitch-ru/README.md | 50 ++++++++++++
nlpcraft-examples/lightswitch-ru/pom.xml | 94 ++++++++++++++++++++++
.../examples/lightswitch/LightSwitchModelRu.scala | 89 ++++++++++++++++++++
.../lightswitch/ru/NCSemanticStemmerRu.scala | 26 ++++++
.../ru/NCStopWordsTokenEnricherRu.scala | 43 ++++++++++
.../examples/lightswitch/ru/NCTokenParserRu.scala | 78 ++++++++++++++++++
.../src/main/resources/lightswitch_model_ru.yaml | 45 +++++++++++
.../lightswitch/NCModelValidationSpec.scala | 32 ++++++++
.../internal/impl/NCModelPipelineManager.scala | 26 +++++-
pom.xml | 1 +
10 files changed, 480 insertions(+), 4 deletions(-)
diff --git a/nlpcraft-examples/lightswitch-ru/README.md b/nlpcraft-examples/lightswitch-ru/README.md
new file mode 100644
index 0000000..f073eff
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/README.md
@@ -0,0 +1,50 @@
+<!--
+ 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.
+-->
+
+<img alt="" src="https://nlpcraft.apache.org/images/nlpcraft_logo_black.gif" height="80px">
+<br>
+
+[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://raw.githubusercontent.com/apache/opennlp/master/LICENSE)
+[![Build](https://github.com/apache/incubator-nlpcraft/workflows/build/badge.svg)](https://github.com/apache/incubator-nlpcraft/actions)
+[![Documentation Status](https://img.shields.io/:docs-latest-green.svg)](https://nlpcraft.apache.org/docs.html)
+[![Gitter](https://badges.gitter.im/apache-nlpcraft/community.svg)](https://gitter.im/apache-nlpcraft/community)
+
+### Light Switch Example
+This example provides very simple implementation for NLI-powered light switch. You can say something like `turn the lights off in
+the entire house` or `switch on the illumination in the master bedroom closet`.
+You can easily modify intent callbacks to perform the actual light switching using HomeKit or Arduino-based
+controllers.
+
+### Documentation
+See [Light Switch](https://nlpcraft.apache.org/examples/light_switch.html) guide for more instructions on how to run this example.
+
+For any questions, feedback or suggestions:
+
+ * View & run other [examples](https://github.com/apache/incubator-nlpcraft/tree/master/nlpcraft-examples)
+ * Read [documentation](https://nlpcraft.apache.org/docs.html), latest [Javadoc](https://nlpcraft.apache.org/apis/latest/index.html) and [REST APIs](https://nlpcraft.apache.org/using-rest.html)
+ * Download & Maven/Grape/Gradle/SBT [instructions](https://nlpcraft.apache.org/download.html)
+ * File a bug or improvement in [JIRA](https://issues.apache.org/jira/projects/NLPCRAFT)
+ * Post a question at [Stack Overflow](https://stackoverflow.com/questions/ask) using <code>nlpcraft</code> tag
+ * Access [GitHub](https://github.com/apache/incubator-nlpcraft) mirror repository.
+ * Join project developers on [dev@nlpcraft.apache.org](mailto:dev-subscribe@nlpcraft.apache.org)
+
+### Copyright
+Copyright (C) 2021 Apache Software Foundation
+
+<img src="https://www.apache.org/img/ASF20thAnniversary.jpg" height="64px" alt="ASF Logo">
+
+
diff --git a/nlpcraft-examples/lightswitch-ru/pom.xml b/nlpcraft-examples/lightswitch-ru/pom.xml
new file mode 100644
index 0000000..67c610f
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <name>NLPCraft Example Light Switch RU</name>
+ <artifactId>nlpcraft-example-lightswitch-ru</artifactId>
+
+ <parent>
+ <artifactId>nlpcraft-parent</artifactId>
+ <groupId>org.apache.nlpcraft</groupId>
+ <version>1.0.0</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>nlpcraft</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.lucene</groupId>
+ <artifactId>lucene-analyzers-common</artifactId>
+ <version>8.11.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.languagetool</groupId>
+ <artifactId>language-de</artifactId>
+ <version>5.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.languagetool</groupId>
+ <artifactId>language-ru</artifactId>
+ <version>5.6</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.languagetool</groupId>
+ <artifactId>languagetool-core</artifactId>
+ <version>5.6</version>
+ </dependency>
+
+
+ <!-- Test dependencies. -->
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>nlpcraft</artifactId>
+ <version>${project.version}</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${maven.compiler.plugin.ver}</version>
+ <configuration>
+ <source>${java.ver}</source>
+ <target>${java.ver}</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
\ No newline at end of file
diff --git a/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/LightSwitchModelRu.scala b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/LightSwitchModelRu.scala
new file mode 100644
index 0000000..67af24a
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/LightSwitchModelRu.scala
@@ -0,0 +1,89 @@
+/*
+ * 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.examples.lightswitch
+
+import org.apache.nlpcraft.*
+import org.apache.nlpcraft.examples.lightswitch.ru.*
+import org.apache.nlpcraft.nlp.entity.parser.nlp.NCNLPEntityParser
+import org.apache.nlpcraft.nlp.entity.parser.semantic.NCSemanticEntityParser
+import org.apache.nlpcraft.nlp.entity.parser.semantic.impl.en.NCEnSemanticPorterStemmer
+import org.apache.nlpcraft.nlp.token.parser.opennlp.NCOpenNLPTokenParser
+import org.apache.nlpcraft.nlp.token.enricher.en.NCStopWordsTokenEnricher
+
+/**
+ * This example provides very simple implementation for NLI-powered light switch.
+ * You can say something like this:
+ * <ul>
+ * <li>"Turn the lights off in the entire house."</li>
+ * <li>"Switch on the illumination in the master bedroom closet."</li>
+ * </ul>
+ * You can easily modify intent callbacks to perform the actual light switching using
+ * HomeKit or Arduino-based controllers.
+ * <p>
+ * See 'README.md' file in the same folder for running and testing instructions.
+ */
+
+class LightSwitchModelRu extends NCModel:
+ override val getConfig: NCModelConfig = new NCModelConfig("nlpcraft.lightswitch.ru.ex", "LightSwitch Example Model RU", "1.0")
+ override val getPipeline: NCModelPipeline =
+ val tp = new NCTokenParserRu
+ new NCModelPipelineBuilder(
+ tp,
+ new NCSemanticEntityParser(new NCSemanticStemmerRu(), tp, "lightswitch_model_ru.yaml")
+ ).
+ withTokenEnricher(new NCStopWordsTokenEnricherRu()).
+ build()
+
+ /**
+ * Intent and its on-match callback.
+ *
+ * @param actEnt Token from `act` term (guaranteed to be one).
+ * @param locEnts Tokens from `loc` term (zero or more).
+ * @return Query result to be sent to the REST caller.
+ */
+ @NCIntent("intent=ls term(act)={has(ent_groups, 'act')} term(loc)={# == 'ls:loc'}*")
+ @NCIntentSample(Array(
+ "Выключи свет по всем доме",
+ "Выруби электричество!",
+ "Включи свет в детской",
+ "Включай повсюду освещение",
+ "Зажигай лампы в детской комнате",
+ "Свет на кухне пожалуйста приглуши",
+ "Нельзя ли повсюду выключить свет",
+ "Пожалуйста без света",
+ "Отключи электричесвто в ванной",
+ "Выключи, пожалуйста, тут всюду свет",
+ "Выключай все!",
+ "Свет пожалуйсте везде включи"
+ ))
+ def onMatch(
+ @NCIntentTerm("act") actEnt: NCEntity,
+ @NCIntentTerm("loc") locEnts: List[NCEntity]
+ ): NCResult =
+ val status = if actEnt.getId == "ls:on" then "on" else "off"
+ val locations = if locEnts.isEmpty then "entire house" else locEnts.map(_.mkText()).mkString(", ")
+
+ // Add HomeKit, Arduino or other integration here.
+
+ // By default - just return a descriptive action string.
+ val res = new NCResult()
+
+ res.setType(NCResultType.ASK_RESULT)
+ res.setBody(s"Lights are [$status] in [${locations.toLowerCase}].")
+
+ res
\ No newline at end of file
diff --git a/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCSemanticStemmerRu.scala b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCSemanticStemmerRu.scala
new file mode 100644
index 0000000..e49c72c
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCSemanticStemmerRu.scala
@@ -0,0 +1,26 @@
+/*
+ * 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.examples.lightswitch.ru
+
+import opennlp.tools.stemmer.snowball.SnowballStemmer
+import org.apache.nlpcraft.nlp.entity.parser.semantic.NCSemanticStemmer
+
+class NCSemanticStemmerRu extends NCSemanticStemmer:
+ private val stemmer = new SnowballStemmer(SnowballStemmer.ALGORITHM.RUSSIAN)
+
+ override def stem(txt: String): String = stemmer.synchronized { stemmer.stem(txt.toLowerCase).toString }
diff --git a/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCStopWordsTokenEnricherRu.scala b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCStopWordsTokenEnricherRu.scala
new file mode 100644
index 0000000..0e9c064
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCStopWordsTokenEnricherRu.scala
@@ -0,0 +1,43 @@
+/*
+ * 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.examples.lightswitch.ru
+
+import org.apache.lucene.analysis.ru.RussianAnalyzer
+import org.apache.nlpcraft.*
+
+import java.util
+import scala.jdk.CollectionConverters.*
+
+/**
+ *
+ */
+class NCStopWordsTokenEnricherRu extends NCTokenEnricher:
+ private final val stops = RussianAnalyzer.getDefaultStopSet
+
+ override def enrich(req: NCRequest, cfg: NCModelConfig, toks: util.List[NCToken]): Unit =
+ toks.asScala.foreach(t =>
+ t.put(
+ "stopword",
+ t.getLemma.length == 1 && !Character.isLetter(t.getLemma.head) ||
+ t.getPos.startsWith("PARTICLE") ||
+ t.getPos.startsWith("INTERJECTION") ||
+ t.getPos.startsWith("PREP") ||
+ stops.contains(t.getLemma) ||
+ stops.contains(t.getText.toLowerCase)
+ )
+ )
diff --git a/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCTokenParserRu.scala b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCTokenParserRu.scala
new file mode 100644
index 0000000..5bda243
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/src/main/java/org/apache/nlpcraft/examples/lightswitch/ru/NCTokenParserRu.scala
@@ -0,0 +1,78 @@
+/*
+ * 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.examples.lightswitch.ru
+
+import org.apache.lucene.analysis.ru.RussianAnalyzer
+import org.apache.nlpcraft.*
+import org.languagetool.AnalyzedToken
+import org.languagetool.language.Russian
+import org.languagetool.rules.ngrams.*
+import org.languagetool.tagging.ru.*
+import org.languagetool.tokenizers.WordTokenizer
+
+import java.util
+import scala.jdk.CollectionConverters.*
+
+object NCTokenParserRu:
+ private val tokenizer = new WordTokenizer
+
+ private case class Span(word: String, start: Int, end: Int)
+
+ private def nvl(v: String, dflt : => String): String = if v != null then v else dflt
+
+ private def split(text: String): Seq[Span] =
+ val spans = collection.mutable.ArrayBuffer.empty[Span]
+ var sumLen = 0
+
+ for (((word, len), idx) <- tokenizer.tokenize(text).asScala.map(p => p -> p.length).zipWithIndex)
+ if word.strip.nonEmpty then spans += Span(word, sumLen, sumLen + word.length)
+ sumLen += word.length
+
+ spans.toSeq
+
+import org.apache.nlpcraft.examples.lightswitch.ru.NCTokenParserRu.*
+
+class NCTokenParserRu extends NCTokenParser:
+ override def tokenize(text: String): util.List[NCToken] =
+ val spans = split(text)
+ val tags = RussianTagger.INSTANCE.tag(spans.map(_.word).asJava).asScala
+
+ require(spans.size == tags.size)
+
+ spans.zip(tags).zipWithIndex.map { case ((span, tag), idx) =>
+ val readings = tag.getReadings.asScala
+
+ val (lemma, pos) =
+ readings.size match
+ // No data. Lemma is word as is, POS is undefined.
+ case 0 => (span.word, "")
+ // Takes first. Other variants ignored.
+ case _ =>
+ val aTok: AnalyzedToken = readings.head
+ (nvl(aTok.getLemma, span.word), nvl(aTok.getPOSTag, ""))
+
+ val tok: NCToken =
+ new NCPropertyMapAdapter with NCToken:
+ override val getText: String = span.word
+ override val getIndex: Int = idx
+ override val getStartCharIndex: Int = span.start
+ override val getEndCharIndex: Int = span.end
+ override val getLemma: String = lemma.toLowerCase // TODO: discuss
+ override val getPos: String = pos
+ tok
+ }.asJava
\ No newline at end of file
diff --git a/nlpcraft-examples/lightswitch-ru/src/main/resources/lightswitch_model_ru.yaml b/nlpcraft-examples/lightswitch-ru/src/main/resources/lightswitch_model_ru.yaml
new file mode 100644
index 0000000..f8294ac
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/src/main/resources/lightswitch_model_ru.yaml
@@ -0,0 +1,45 @@
+#
+# 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.
+#
+
+macros:
+ "<TURN_ON>" : "{включить|включать|врубить|врубать|запустить|запускать|зажигать|зажечь}"
+ "<TURN_OFF>" : "{погасить|загасить|гасить|выключить|выключать|вырубить|вырубать|отключить|отключать|убрать|убирать|приглушить|приглушать|стоп}"
+ "<ENTIRE_OPT>" : "{весь|все|всё|повсюду|вокруг|полностью|везде|_}"
+ "<LIGHT_OPT>" : "{это|лампа|бра|люстра|светильник|лампочка|лампа|освещение|свет|электричество|электрика|_}"
+
+elements:
+ - id: "ls:loc"
+ description: "Location of lights."
+ synonyms:
+ - "<ENTIRE_OPT> {здание|помещение|дом|кухня|детская|кабинет|гостиная|спальня|ванная|туалет|{большая|обеденная|ванная|детская|туалетная} комната}"
+
+ - id: "ls:on"
+ groups:
+ - "act"
+ description: "Light switch ON action."
+ synonyms:
+ - "<LIGHT_OPT> <ENTIRE_OPT> <TURN_ON>"
+ - "<TURN_ON> <ENTIRE_OPT> <LIGHT_OPT>"
+
+ - id: "ls:off"
+ groups:
+ - "act"
+ description: "Light switch OFF action."
+ synonyms:
+ - "<LIGHT_OPT> <ENTIRE_OPT> <TURN_OFF>"
+ - "<TURN_OFF> <ENTIRE_OPT> <LIGHT_OPT>"
+ - "без <ENTIRE_OPT> <LIGHT_OPT>"
diff --git a/nlpcraft-examples/lightswitch-ru/src/test/java/org/apache/nlpcraft/examples/lightswitch/NCModelValidationSpec.scala b/nlpcraft-examples/lightswitch-ru/src/test/java/org/apache/nlpcraft/examples/lightswitch/NCModelValidationSpec.scala
new file mode 100644
index 0000000..b6d9d1b
--- /dev/null
+++ b/nlpcraft-examples/lightswitch-ru/src/test/java/org/apache/nlpcraft/examples/lightswitch/NCModelValidationSpec.scala
@@ -0,0 +1,32 @@
+/*
+ * 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.examples.lightswitch
+
+import org.apache.nlpcraft.*
+import org.junit.jupiter.api.*
+
+import scala.util.Using
+
+/**
+ * JUnit models validation.
+ */
+class NCModelValidationSpec:
+ private val MDL = new LightSwitchModelRu
+
+ @Test
+ def test(): Unit = Using.resource(new NCModelClient(MDL)) { client => client.validateSamples() }
diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala
index e1f56cb..afcd63a 100644
--- a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala
+++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/impl/NCModelPipelineManager.scala
@@ -86,6 +86,15 @@ class NCModelPipelineManager(cfg: NCModelConfig, pipeline: NCModelPipeline) exte
/**
*
+ * @param m
+ * @return
+ */
+ private def mkProps(m: NCPropertyMap): String =
+ if m.keysSet().isEmpty then ""
+ else m.keysSet().asScala.toSeq.sorted.map(p => s"$p=${m.get[Any](p)}").mkString("{", ", ", "}")
+
+ /**
+ *
* @param txt
* @param data
* @param usrId
@@ -119,6 +128,19 @@ class NCModelPipelineManager(cfg: NCModelConfig, pipeline: NCModelPipeline) exte
check()
e.enrich(req, cfg, toks)
+ val tbl = NCAsciiTable("Text", "Lemma", "POS", "Start index", "End index", "Properties")
+
+ for (t <- toks.asScala)
+ tbl += (
+ t.getText,
+ t.getLemma,
+ t.getPos,
+ t.getStartCharIndex,
+ t.getEndCharIndex,
+ mkProps(t)
+ )
+ tbl.info(logger, Option(s"Tokens for: ${req.getText}"))
+
// NOTE: we run validators regardless of whether token list is empty.
for (v <- tokVals)
check()
@@ -169,10 +191,6 @@ class NCModelPipelineManager(cfg: NCModelConfig, pipeline: NCModelPipeline) exte
for ((v, i) <- vrnts.zipWithIndex)
val tbl = NCAsciiTable("EntityId", "Tokens", "Tokens Position", "Properties")
- def mkProps(m: NCPropertyMap): String =
- if m.keysSet().isEmpty then ""
- else m.keysSet().asScala.toSeq.sorted.map(p => s"$p=${m.get[Any](p)}").mkString("{", ", ", "}")
-
for (e <- v.getEntities.asScala)
val toks = e.getTokens.asScala
tbl += (
diff --git a/pom.xml b/pom.xml
index fc180eb..49c430d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -393,6 +393,7 @@
<module>nlpcraft-examples/lightswitch</module>
<module>nlpcraft-examples/time</module>
<module>nlpcraft-examples/weather</module>
+ <module>nlpcraft-examples/lightswitch-ru</module>
</modules>
</profile>
</profiles>