Image title

在本文中,我将演示如何为典型的家庭灯开关构建自然语言界面,以便您可以使用简单的命令(如 或 )打开和关闭灯光。 Turn off all the lights, please Get the lights on in the kids bedroom

我们将集中讨论自然语言界面 (NLI) 部分,我将将语音到文本和实际光控制排除在本简短博客的范围之外。如有必要,您可以使用WebSpeech轻松添加语音到文本,而Arduino/HomeKit可以提供简单的 API 来控制您家中的灯光。

对于我们的实现,我们将使用NLPCraft和 Scala 语言(NLPCraft 还支持您选择的任何基于 JVM 的语言,如 Java、Groovy 或 Kotlin)。NLPCraft 是一个免费的开源项目,允许您快速构建特定于域的自然语言接口到任何设备或软件。它使用现代语义建模和基于确定性意图的如果用户输入匹配,而不是传统的计算语言学(即神经网络)。因此,它不需要任何预先存在的域公司或冗长的模型培训和开发。

在使用 NLPCraft 时,大多数工作都是围绕为特定域构建语义模型。模型定义一组命名实体(用户定义或来自spaCy、OpenNLP、斯坦福CoreNLP谷歌自然语言)的第三方),这些实体应在用户中检测到。 NLPCraft 还提供了高级意图匹配,我们将在此示例后面使用。

让我们来思考一下我们手头的任务,即支持一个典型的光开关的自由形式自然语言界面。下面是我们想要支持的命令示例:

Turn the lights off in the entire house
Switch on the illumination in the master bedroom closet
Get the lights on
Please, put the light out in the upstairs bedroom
Set the lights on in the entire house
Turn the lights off in the guest bedroom
Could you please switch off all the lights?
Dial off illumination on the 2nd floor
Please, no lights!
Kill off all the lights now!
No lights in the bedroom, pleaseb

通过查看这些示例,您可以轻松地发现我们需要能够在用户输入中检测到的三个不同的实体,我们稍后将在用户意图中使用这些实体:
– 打开灯的操作
– 关闭灯的操作
– 灯光的位置

下面是 YAML 中 NLPCraft 语义模型的声明性部分,它定义了这三个实体:

id: "nlpcraft.lightswitch.ex"
name: "Light Switch Example Model"
version: "1.0"
description: "NLI-powered light switch example model

元素:
– id:”ls:loc”
描述:”灯光的位置。
同义词:
– “<ENTIRE_OPT>[楼上]楼下][厨房]图书馆[车库]办公室[游戏室]用餐[洗衣]游戏+房间]”
– “<ENTIRE_OPT_gt;[楼上]楼下][主人]孩子\孩子\孩子\客人][卧室]浴室+洗手间]储藏室][壁橱]”
– “<ENTIRE_OPT> [房子]家庭_建设]1楼[一楼]{2 楼}第二层]”

– id:”ls:on”
组:
– “行为”
描述:”灯开关打开操作。
同义词:
– “<ACTION> <LIGHT> 开”
– “<ACTION>在<LIGHT>”

– id:”ls:off”
组:
– “行为”
描述:”灯开关关闭操作”。
同义词:
– “<ACTION> <LIGHT> [关闭] ”
– “<ACTION>[关闭]停止\消除][关闭]<LIGHT>”
– “无 <LIGHT>”

除了一些语法特点,这个模型定义是相当不言自明的:

  • 第 14、2129行定义我们的三个元素(即命名实体): ls:locls:on ls:off 。每个元素都通过一组宏扩展的同义词定义。
  • 第 5 行提供后来在元素定义中使用的宏列表。

此模型的显著之处是,这几十条 YAML 系列具有生产力和经济性:

当 NLPCraft 加载此模型时,此模型将转换为每个元素的 > 100,000 个不同的同义词,在传统方法中,必须手动创建这些同义词。

NLPCraft对同义词处理很明智:除了基本的规范化、标记化、词干化、非数消除等之外,它还执行高级洗牌和加权选择算法。在为更高级的检测用例定义语义元素时,还可以使用 PoS 标记、正则表达式或用户定义的谓词。

现在,我们已经拥有了模型配置的声明性部分,我们可以通过提供意图匹配逻辑来完成模型定义的其余部分。从技术上讲,NLPCraft模型只是NCModelJava接口的实现。我们将使用方便的NCModelFileAdapter适配器来实现基于 YAML 的上述配置的模型:

class LightSwitchModel extends NCModelFileAdapter("org/nlpcraft/examples/lightswitch/lightswitch_model.yaml") {
    @NCIntent("id=act conv=false term(act)={groups @@ 'act'} term(loc)={id == 'ls:loc'}*")
    def onMatch(
        @NCIntentTerm("act") actTok: NCToken,
        @NCIntentTerm("loc") locToks: List[NCToken]
    ): NCQueryResult = {
        val status = if (actTok.getId == "ls:on") "on" else "off"
        val locations = if (locToks.isEmpty) "entire house" else locToks.map(getOriginalText).mkString(", ")

        // Add HomeKit, Arduino or other integration here.

        // By default - just return a descriptive action string.
        NCQueryResult.text(s"Lights '$status' in '${locations.toLowerCase}'.")
    }
}

很少评论:

  • 在第1 行中,我们从基于 YAML 的外部配置(我们在上面讨论)初始化模型。
  • 在第2 行,我们将意图附加到其 onMatch(…) 回调

组织/apis/最新/组织/nlpcraft/模型/意图/NCIntent.html?源\post_page—————————“rel=”nofollow”目标\”\空白”_NCIntentJava注释和基于文本的意图DSL由NLPCraft支持。此意图将匹配具有以下实体的任何用户输入:- 正好一个操作(即属于组的任何实体)和 – "act” 零个或多个灯光位置。

  • 当匹配意图并调用回调时,检测到的实体将通过NCIntentTerm注释映射到回调方法参数。
  • 回调实现只是返回灯光的状态(见第13行)。此时,您可以添加 Arduino、HomeKit 等集成。
  • 我们完成了!

    将模型编译并部署到数据探测中,启动 REST 服务器(此处将对此进行详细信息),并且模型已准备好接受 REST 调用并开始使用自然语言控制灯光。

    尽管您只需要使用任何 REST 工具将输入发送到模型中,但我们将使用内置的 JUnit 5 兼容测试框架来实现更多的自动化。

    使用此代码创建LightSwitchTest.java文件并运行它:

    package org.nlpcraft.examples.lightswitch;
    
    import org.junit.jupiter.api.*;
    import org.nlpcraft.common.*;
    import org.nlpcraft.model.test.*;
    import java.io.*;
    
    import static org.junit.jupiter.api.Assertions.*;
    
    class LightSwitchTest {
        private NCTestClient cli;
    
        @BeforeEach
        void setUp() throws NCException, IOException {
            cli = new NCTestClientBuilder().newBuilder().build();
    
            cli.open("nlpcraft.lightswitch.ex"); 
        }
    
        @AfterEach
        void tearDown() throws NCException, IOException {
            cli.close();
        }
    
        @Test
        void test() throws NCException, IOException {
            assertTrue(cli.ask("Turn the lights off in the entire house.").isOk());
            assertTrue(cli.ask("Switch on the illumination in the master bedroom closet.").isOk());
            assertTrue(cli.ask("Get the lights on.").isOk());
            assertTrue(cli.ask("Please, put the light out in the upstairs bedroom.").isOk());
            assertTrue(cli.ask("Set the lights on in the entire house.").isOk());
            assertTrue(cli.ask("Turn the lights off in the guest bedroom.").isOk());
            assertTrue(cli.ask("Could you please switch off all the lights?").isOk());
            assertTrue(cli.ask("Dial off illumination on the 2nd floor.").isOk());
            assertTrue(cli.ask("Please, no lights!").isOk());
            assertTrue(cli.ask("Kill off all the lights now!").isOk());
            assertTrue(cli.ask("No lights in the bedroom, please.").isOk());
        }
    }

    请注意,我们在测试中使用我们想要在开始时支持的原始句子。可以查看测试输出并验证一切是否按预期工作。

    通过自动测试,您可以快速使用模型、进行更改或迭代修改,而不会破坏过程中的内容。

    继续玩这个模式:你可以添加Arduino集成或采用模型 ls:loc 实体到你自己的家庭配置;你可以添加一些俚语或古怪的方法来操作你的灯。

    快速链接

    Comments are closed.