This is an automated email from the ASF dual-hosted git repository. sergeykamov pushed a commit to branch NLPCRAFT-518 in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
commit 2f136ba610219c3cdce3c4ba3c737ba6665ab355 Author: Sergey Kamov <[email protected]> AuthorDate: Mon Oct 17 11:48:48 2022 +0400 Calculator test moved into examples. --- nlpcraft-examples/calculator/README.md | 48 +++++++++++ nlpcraft-examples/calculator/pom.xml | 93 ++++++++++++++++++++++ .../nlpcraft/examples/time/CalculatorModel.scala | 83 +++++++++++++++++++ .../examples/time/CalculatorModelSpec.scala} | 20 +++-- .../lightswitch/LightSwitchFrModelSpec.scala | 2 +- .../lightswitch/LightSwitchRuModelSpec.scala | 2 +- .../lightswitch/LightSwitchModelSpec.scala | 2 +- .../nlpcraft/examples/time/TimeModelSpec.scala | 2 +- .../nlpcraft/models/NCIntCalcModelSpec.scala | 91 --------------------- pom.xml | 1 + 10 files changed, 238 insertions(+), 106 deletions(-) diff --git a/nlpcraft-examples/calculator/README.md b/nlpcraft-examples/calculator/README.md new file mode 100644 index 00000000..3efbddbc --- /dev/null +++ b/nlpcraft-examples/calculator/README.md @@ -0,0 +1,48 @@ +<!-- + 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 src="https://nlpcraft.apache.org/images/nlpcraft_logo_black.gif" height="80px"> +<br> + +[](https://raw.githubusercontent.com/apache/opennlp/master/LICENSE) +[](https://github.com/apache/incubator-nlpcraft/actions) +[](https://nlpcraft.apache.org/docs.html) +[](https://gitter.im/apache-nlpcraft/community) + +### Calculator Example +This example data model represents simple calculator. It supports '+', '-', '*' and '/' operations for two integer arguments. +Note that first argument can be omitted and last operation result is used instead of it. + +### Documentation +See [Getting Started](https://nlpcraft.apache.org/getting-started.html) guide for more instructions on how to run these examples. + +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 [[email protected]](mailto:[email protected]) + +### 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/calculator/pom.xml b/nlpcraft-examples/calculator/pom.xml new file mode 100644 index 00000000..f4be57e4 --- /dev/null +++ b/nlpcraft-examples/calculator/pom.xml @@ -0,0 +1,93 @@ +<?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 Calculator</name> + <artifactId>nlpcraft-example-calculator</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>${project.groupId}</groupId> + <artifactId>nlpcraft-stanford</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- Test dependencies. --> + <dependency> + <groupId>org.scalatest</groupId> + <artifactId>scalatest_${scala.major.ver}</artifactId> + <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> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <version>${maven.surefire.plugin.ver}</version> + <configuration> + <skipTests>true</skipTests> + </configuration> + </plugin> + <plugin> + <groupId>org.scalatest</groupId> + <artifactId>scalatest-maven-plugin</artifactId> + <version>${maven.scalatest.plugin.ver}</version> + <configuration> + <reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory> + <junitxml>.</junitxml> + <filereports>WDF TestSuite.txt</filereports> + </configuration> + <executions> + <execution> + <id>test</id> + <goals> + <goal>test</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file diff --git a/nlpcraft-examples/calculator/src/main/scala/org/apache/nlpcraft/examples/time/CalculatorModel.scala b/nlpcraft-examples/calculator/src/main/scala/org/apache/nlpcraft/examples/time/CalculatorModel.scala new file mode 100644 index 00000000..49268abf --- /dev/null +++ b/nlpcraft-examples/calculator/src/main/scala/org/apache/nlpcraft/examples/time/CalculatorModel.scala @@ -0,0 +1,83 @@ +/* + * 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.time + +import edu.stanford.nlp.pipeline.StanfordCoreNLP +import org.apache.nlpcraft.* +import org.apache.nlpcraft.annotations.* +import org.apache.nlpcraft.nlp.entity.parser.stanford.* +import org.apache.nlpcraft.nlp.parsers.* +import org.apache.nlpcraft.nlp.token.parser.stanford.NCStanfordNLPTokenParser +import java.util.Properties + +/** + * + */ +object CalculatorModel: + private val OPS: Map[String, (Int, Int) => Int] = Map("+" -> (_ + _), "-" -> (_ - _), "*" -> (_ * _), "/" -> (_ / _)) + + private val PIPELINE: NCPipeline = + val props = new Properties() + props.setProperty("annotators", "tokenize, ssplit, pos, lemma, ner") + + val stanford = new StanfordCoreNLP(props) + + new NCPipelineBuilder(). + withTokenParser(new NCStanfordNLPTokenParser(stanford)). + withEntityParser(new NCNLPEntityParser(t => OPS.contains(t.getText))). // For operations. + withEntityParser(new NCStanfordNLPEntityParser(stanford, Set("number"))). // For numerics. + build + + private def nne(e: NCEntity): Int = java.lang.Double.parseDouble(e[String]("stanford:number:nne")).intValue + +import CalculatorModel.* + +/** + * + */ +class CalculatorModel extends NCModelAdapter(NCModelConfig("nlpcraft.calculator.ex", "Calculator Example Model", "1.0"), PIPELINE) : + private var mem: Option[Int] = None + + private def calc(x: Int, op: String, y: Int): NCResult = + mem = Some(OPS.getOrElse(op, throw new IllegalStateException()).apply(x, y)) + NCResult(mem.get) + + @NCIntent( + "intent=calc options={ 'ordered': true }" + + " term(x)={# == 'stanford:number'} " + + " term(op)={# == 'nlp:token' && has(list('+', '-', '*', '/'), meta_ent('nlp:token:text')) == true} " + + " term(y)={# == 'stanford:number'}" + ) + def onMatch( + ctx: NCContext, + im: NCIntentMatch, + @NCIntentTerm("x") x: NCEntity, + @NCIntentTerm("op") op: NCEntity, + @NCIntentTerm("y") y: NCEntity + ): NCResult = calc(nne(x), op.mkText, nne(y)) + + @NCIntent( + "intent=calcMem options={ 'ordered': true }" + + " term(op)={# == 'nlp:token' && has(list('+', '-', '*', '/'), meta_ent('nlp:token:text')) == true} " + + " term(y)={# == 'stanford:number'}" + ) + def onMatchMem( + ctx: NCContext, + im: NCIntentMatch, + @NCIntentTerm("op") op: NCEntity, + @NCIntentTerm("y") y: NCEntity + ): NCResult = calc(mem.getOrElse(throw new NCRejection("Memory is empty.")), op.mkText, nne(y)) diff --git a/nlpcraft-examples/time/src/test/scala/org/apache/nlpcraft/examples/time/TimeModelSpec.scala b/nlpcraft-examples/calculator/src/test/scala/org/apache/nlpcraft/examples/time/CalculatorModelSpec.scala similarity index 60% copy from nlpcraft-examples/time/src/test/scala/org/apache/nlpcraft/examples/time/TimeModelSpec.scala copy to nlpcraft-examples/calculator/src/test/scala/org/apache/nlpcraft/examples/time/CalculatorModelSpec.scala index 52012ecb..8a95bd1e 100644 --- a/nlpcraft-examples/time/src/test/scala/org/apache/nlpcraft/examples/time/TimeModelSpec.scala +++ b/nlpcraft-examples/calculator/src/test/scala/org/apache/nlpcraft/examples/time/CalculatorModelSpec.scala @@ -23,19 +23,17 @@ import org.scalatest.funsuite.AnyFunSuite import scala.util.Using /** - * JUnit model validation. + * Model validation. */ -class TimeModelSpec extends AnyFunSuite: +class CalculatorModelSpec extends AnyFunSuite: test("test") { - Using.resource(new NCModelClient(new TimeModel())) { client => - def check(txt: String, intentId: String): Unit = - require(client.debugAsk(txt, "userId", true).getIntentId == intentId) + Using.resource(new NCModelClient(new CalculatorModel())) { client => + def check(txt: String, v: Int): Unit = require(v == client.ask(txt, "userId").getBody) - check("What time is it now in New York City?", "intent2") - check("What's the current time in Moscow?", "intent2") - check("Show me time of the day in London.", "intent2") - check("Can you please give me the Tokyo's current date and time.", "intent2") - - check("What's the local time?", "intent1") + check("2 + 2", 4) + check("3 * 4", 12) + check("/ two", 6) + check("+ twenty two", 28) + check("7 + 2", 9) } } diff --git a/nlpcraft-examples/lightswitch-fr/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchFrModelSpec.scala b/nlpcraft-examples/lightswitch-fr/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchFrModelSpec.scala index 4e9a6191..bbef184e 100644 --- a/nlpcraft-examples/lightswitch-fr/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchFrModelSpec.scala +++ b/nlpcraft-examples/lightswitch-fr/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchFrModelSpec.scala @@ -23,7 +23,7 @@ import org.scalatest.funsuite.AnyFunSuite import scala.util.Using /** - * JUnit models validation. + * Model validation. */ class LightSwitchFrModelSpec extends AnyFunSuite: test("test") { diff --git a/nlpcraft-examples/lightswitch-ru/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchRuModelSpec.scala b/nlpcraft-examples/lightswitch-ru/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchRuModelSpec.scala index 0a1d2814..e3548f10 100644 --- a/nlpcraft-examples/lightswitch-ru/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchRuModelSpec.scala +++ b/nlpcraft-examples/lightswitch-ru/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchRuModelSpec.scala @@ -23,7 +23,7 @@ import org.scalatest.funsuite.AnyFunSuite import scala.util.Using /** - * JUnit models validation. + * Model validation. */ class LightSwitchRuModelSpec extends AnyFunSuite: test("test") { diff --git a/nlpcraft-examples/lightswitch/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchModelSpec.scala b/nlpcraft-examples/lightswitch/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchModelSpec.scala index 1cbf693f..bebb30bc 100644 --- a/nlpcraft-examples/lightswitch/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchModelSpec.scala +++ b/nlpcraft-examples/lightswitch/src/test/scala/org/apache/nlpcraft/examples/lightswitch/LightSwitchModelSpec.scala @@ -23,7 +23,7 @@ import org.scalatest.funsuite.AnyFunSuite import scala.util.Using /** - * JUnit models validation. + * Model validation. */ class LightSwitchModelSpec extends AnyFunSuite: test("test") { diff --git a/nlpcraft-examples/time/src/test/scala/org/apache/nlpcraft/examples/time/TimeModelSpec.scala b/nlpcraft-examples/time/src/test/scala/org/apache/nlpcraft/examples/time/TimeModelSpec.scala index 52012ecb..f246ce50 100644 --- a/nlpcraft-examples/time/src/test/scala/org/apache/nlpcraft/examples/time/TimeModelSpec.scala +++ b/nlpcraft-examples/time/src/test/scala/org/apache/nlpcraft/examples/time/TimeModelSpec.scala @@ -23,7 +23,7 @@ import org.scalatest.funsuite.AnyFunSuite import scala.util.Using /** - * JUnit model validation. + * Model validation. */ class TimeModelSpec extends AnyFunSuite: test("test") { diff --git a/nlpcraft-stanford/src/test/scala/org/apache/nlpcraft/models/NCIntCalcModelSpec.scala b/nlpcraft-stanford/src/test/scala/org/apache/nlpcraft/models/NCIntCalcModelSpec.scala deleted file mode 100644 index a7a9a250..00000000 --- a/nlpcraft-stanford/src/test/scala/org/apache/nlpcraft/models/NCIntCalcModelSpec.scala +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * https://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.models - -import edu.stanford.nlp.pipeline.StanfordCoreNLP -import opennlp.tools.stemmer.PorterStemmer -import org.apache.nlpcraft.* -import org.apache.nlpcraft.annotations.* -import org.apache.nlpcraft.nlp.entity.parser.stanford.* -import org.apache.nlpcraft.nlp.parsers.* -import org.apache.nlpcraft.nlp.token.parser.stanford.NCStanfordNLPTokenParser -import org.apache.nlpcraft.nlp.util.* -import org.scalatest.funsuite.AnyFunSuite - -import java.util.Properties -import scala.util.Using - -object NCIntCalcModelSpec: - val MDL: NCModel = new NCTestModelAdapter: - private val OPS: Map[String, (Int, Int) => Int] = Map("+" -> (_ + _), "-" -> (_ - _), "*" -> (_ * _), "/" -> (_ / _)) - - private var mem: Option[Int] = None - - private def nne(e: NCEntity): Int = java.lang.Double.parseDouble(e[String]("stanford:number:nne")).intValue - private def mkProps(k: String, v: String): Properties = - val props = new Properties(); props.setProperty(k, v); props - private def calc(x: Int, op: String, y: Int): NCResult = - mem = Some(OPS.getOrElse(op, throw new IllegalStateException()).apply(x, y)) - NCResult(mem.get) - - override val getPipeline: NCPipeline = - val stanford = new StanfordCoreNLP(mkProps("annotators", "tokenize, ssplit, pos, lemma, ner")) - - new NCPipelineBuilder(). - withTokenParser(new NCStanfordNLPTokenParser(stanford)). - withEntityParser(new NCNLPEntityParser(t => OPS.contains(t.getText))). // For operations. - withEntityParser(new NCStanfordNLPEntityParser(stanford, Set("number"))). // For numerics. - build - - @NCIntent( - "intent=calc options={ 'ordered': true }" + - " term(x)={# == 'stanford:number'} " + - " term(op)={# == 'nlp:token' && has(list('+', '-', '*', '/'), meta_ent('nlp:token:text')) == true} " + - " term(y)={# == 'stanford:number'}" - ) - def onMatch( - ctx: NCContext, - im: NCIntentMatch, - @NCIntentTerm("x") x: NCEntity, - @NCIntentTerm("op") op: NCEntity, - @NCIntentTerm("y") y: NCEntity - ): NCResult = calc(nne(x), op.mkText, nne(y)) - - @NCIntent( - "intent=calcMem options={ 'ordered': true }" + - " term(op)={# == 'nlp:token' && has(list('+', '-', '*', '/'), meta_ent('nlp:token:text')) == true} " + - " term(y)={# == 'stanford:number'}" - ) - def onMatchMem( - ctx: NCContext, - im: NCIntentMatch, - @NCIntentTerm("op") op: NCEntity, - @NCIntentTerm("y") y: NCEntity - ): NCResult = calc(mem.getOrElse(throw new NCRejection("Memory is empty.")), op.mkText, nne(y)) - -class NCIntCalcModelSpec extends AnyFunSuite: - test("test") { - Using.resource(new NCModelClient(NCIntCalcModelSpec.MDL)) { client => - def check(txt: String, v: Int): Unit = require(v == client.ask(txt, "userId").getBody) - - check("2 + 2", 4) - check("3 * 4", 12) - check("/ two", 6) - check("+ twenty two", 28) - check("7 + 2", 9) - } - } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 087d24fd..f49f66e0 100644 --- a/pom.xml +++ b/pom.xml @@ -385,6 +385,7 @@ <module>nlpcraft-examples/lightswitch-ru</module> <module>nlpcraft-examples/lightswitch-fr</module> <module>nlpcraft-examples/pizzeria</module> + <module>nlpcraft-examples/calculator</module> </modules> </profile> </profiles>
