• Docs
  • Community
  • Use Cases
  • Downloads
  • v.1.0.0
  • GitHub
  1. Home
  2. Light Switch ex

Light Switch ex

  • Introduction
  • Overview
  • Installation
  • First Example
  • Developer Guide
  • Key Concepts
  • Intent Matching
  • Short-Term Memory
  • Examples
  • Calculator
  • Time
  • Light Switch
  • Light Switch FR
  • Light Switch RU
  • Pizzeria

Overview

This example provides a 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". By modifying intent callbacks using, for example, HomeKit or Arduino-based controllers you can provide the actual light switching.

Complexity:
Source code: GitHub
Review: All Examples at GitHub

Create New Project

You can create new Scala projects in many ways - we'll use SBT to accomplish this task. Make sure that build.sbt file has the following content:

            ThisBuild / version := "0.1.0-SNAPSHOT"
            ThisBuild / scalaVersion := "3.2.2"
            lazy val root = (project in file("."))
              .settings(
                name := "NLPCraft LightSwitch Example",
                version := "1.0.0",
                libraryDependencies += "org.apache.nlpcraft" % "nlpcraft" % "1.0.0",
                libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.15" % "test"
              )
        

NOTE: use the latest versions of Scala and ScalaTest.

Create the following files so that resulting project structure would look like the following:

  • lightswitch_model.yaml - YAML configuration file which contains model description.
  • LightSwitchModel.scala - Model implementation.
  • LightSwitchModelSpec.scala - Test that allows to test your model.
            |  build.sbt
            +--project
            |    build.properties
            \--src
               +--main
               |  +--resources
               |  |    lightswitch_model.yaml
               |  \--scala
               |     \--demo
               |          LightSwitchModel.scala
               \--test
                  \--scala
                     \--demo
                          LightSwitchModelSpec.scala
        

Data Model

We are going to start with declaring the static part of our model using YAML which we will later load in our Scala-based model implementation. Open src/main/resources/lightswitch_model.yaml file and replace its content with the following YAML:

            macros:
              "<ACTION>" : "{turn|switch|dial|let|set|get|put}"
              "<KILL>" : "{shut|kill|stop|eliminate}"
              "<ENTIRE_OPT>" : "{entire|full|whole|total|_}"
              "<FLOOR_OPT>" : "{upstairs|downstairs|{1st|first|2nd|second|3rd|third|4th|fourth|5th|fifth|top|ground} floor|_}"
              "<TYPE>" : "{room|closet|attic|loft|{store|storage} {room|_}}"
              "<LIGHT>" : "{all|_} {it|them|light|illumination|lamp|lamplight}"

            elements:
              - type: "ls:loc"
                description: "Location of lights."
                synonyms:
                  - "<ENTIRE_OPT> <FLOOR_OPT> {kitchen|library|closet|garage|office|playroom|{dinning|laundry|play} <TYPE>}"
                  - "<ENTIRE_OPT> <FLOOR_OPT> {master|kid|children|child|guest|_} {bedroom|bathroom|washroom|storage} {<TYPE>|_}"
                  - "<ENTIRE_OPT> {house|home|building|{1st|first} floor|{2nd|second} floor}"

              - type: "ls:on"
                groups:
                  - "act"
                description: "Light switch ON action."
                synonyms:
                  - "<ACTION> {on|up|_} <LIGHT> {on|up|_}"
                  - "<LIGHT> {on|up}"

              - type: "ls:off"
                groups:
                  - "act"
                description: "Light switch OFF action."
                synonyms:
                  - "<ACTION> <LIGHT> {off|out|down}"
                  - "{<ACTION>|<KILL>} {off|out|down} <LIGHT>"
                  - "<KILL> <LIGHT>"
                  - "<LIGHT> <KILL>"
                  - "{out|no|off|down} <LIGHT>"
                  - "<LIGHT> {out|off|down}"
        
  • Line 1 defines several macros that are used later on throughout the model's elements to shorten the synonym declarations. Note how macros coupled with option groups shorten overall synonym declarations 1000:1 vs. manually listing all possible word permutations.
  • Lines 10, 17, 25 define three model elements: the location of the light, and actions to turn the light on and off. Action elements belong to the same group act which will be used in our intent, defined in LightSwitchModel class. Note that these model elements are defined mostly through macros we have defined above.

YAML vs. API

As usual, this YAML-based static model definition is convenient but totally optional. All elements definitions can be provided programmatically inside Scala model LightSwitchModel class as well.

Model Class

Open src/main/scala/demo/LightSwitchModel.scala file and replace its content with the following code:

            package demo

            import org.apache.nlpcraft.*
            import org.apache.nlpcraft.annotations.*

            class LightSwitchModel extends NCModel(
                NCModelConfig("nlpcraft.lightswitch.java.ex", "LightSwitch Example Model", "1.0"),
                new NCPipelineBuilder().withSemantic("en", "lightswitch_model.yaml").build
            ):
                @NCIntent("intent=ls term(act)={has(ent_groups, 'act')} term(loc)={# == 'ls:loc'}*")
                def onMatch(
                    ctx: NCContext,
                    im: NCIntentMatch,
                    @NCIntentTerm("act") actEnt: NCEntity,
                    @NCIntentTerm("loc") locEnts: List[NCEntity]
                ): NCResult =
                    val status = if actEnt.getType == "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.
                    NCResult(s"Lights are [$status] in [${locations.toLowerCase}].")
        

The intent callback logic is very simple - we return a descriptive confirmation message back (explaining what lights were changed). With action and location detected, you can add the actual light switching using HomeKit or Arduino devices. Let's review this implementation step by step:

  • On line 6 our class extends NCModel with two mandatory parameters.
  • Line 7 creates model configuration with most default parameters.
  • Line 8 creates pipeline, based on semantic model definition, described in lightswitch_model.yaml file.
  • Lines 10 and 11 annotate intents ls and its callback method onMatch(). Intent ls requires one action (a token belonging to the group act) and optional list of light locations (zero or more tokens with ID ls:loc) - by default we assume the entire house as a default location.
  • Lines 14 and 15 map terms from detected intent to the formal method parameters of the onMatch() method.
  • On the line 22 the intent callback simply returns a confirmation message.

Testing

The test defined in LightSwitchModelSpec allows to check that all input test sentences are processed correctly and trigger the expected intent ls:

            package demo

            import org.apache.nlpcraft.*
            import org.scalatest.funsuite.AnyFunSuite
            import scala.util.Using

            class LightSwitchModelSpec extends AnyFunSuite:
                test("test") {
                    Using.resource(new NCModelClient(new LightSwitchModel())) { client =>
                        def check(txt: String): Unit =
                            require(client.debugAsk(txt, "userId", true).getIntentId == "ls")

                        check("Turn the lights off in the entire house.")
                        check("Turn off all lights now")
                        check("Switch on the illumination in the master bedroom closet.")
                        check("Get the lights on.")
                        check("Off the lights on the 1st floor")
                        check("Lights up in the kitchen.")
                        check("Please, put the light out in the upstairs bedroom.")
                        check("Set the lights on in the entire house.")
                        check("Turn the lights off in the guest bedroom.")
                        check("Could you please switch off all the lights?")
                        check("Dial off illumination on the 2nd floor.")
                        check("Turn down lights in 1st floor bedroom")
                        check("Lights on at second floor kitchen")
                        check("Please, no lights!")
                        check("Kill off all the lights now!")
                        check("Down the lights in the garage")
                        check("Lights down in the kitchen!")
                        check("Turn up the illumination in garage and master bedroom")
                        check("Turn down all the light now!")
                        check("No lights in the bedroom, please.")
                        check("Light up the garage, please!")
                        check("Kill the illumination now!")
                    }
                }
        
  • Line 9 creates the client for our model.
  • Line 11 calls a special method debugAsk(). It allows to check the winning intent and its callback parameters without actually calling the intent.
  • Lines 13-34 define all the test input sentences that should all trigger ls intent.

You can run this test via SBT task executeTests or using IDE.

            $ sbt executeTests
        

Done! 👌

You've created light switch data model and tested it.

  • On This Page
  • Overview
  • New Project
  • Data Model
  • Model Class
  • Testing
  • Quick Links
  • Examples
  • Scaladoc
  • Download
  • Installation
  • Support
  • JIRA
  • Dev List
  • Stack Overflow
  • GitHub
  • Gitter
  • Twitter
Copyright © 2023 Apache Software Foundation asf Events • Privacy • News • Docs release: 1.0.0 Gitter Built in: