docs

为技能定义语音交互

在创建自定义技能的过程中,您需要为此技能定义语音交互,以覆盖用户的语音交互场景,做出合理的响应。

Tips:预定义技能不需要您定义语音交互。

概述

理解语音交互的逻辑

为自定义技能定义语音交互,实际上是将用户语句 词表用户输入和您的后端服务能够处理的意图进行映射关联的过程。

要处理好这个映射关系,你需要弄清楚以下几个主要概念:

  1. 意图定义:一个能够声明您后端服务可以处理的意图合集的JSON结构。
  2. 用户输入数据
    • 用户语句:意图中表达用户输入的部分。可以将用户可能的交互语句和您的意图关联起来。您可以为一个意图预置尽可能多的用户语句。
    • 词表:一个词条的列表,这些词条的内容将会被用户语句或者意图所引用。比如您可以把所有的城市作为值放在「城市」词条中,给「杭州今天天气怎么样」这个用户语句引用。

您将会在Rokid开发者社区 > 开发后台 > 技能工具中某一个技能的语音交互页面编辑上述信息。

下面将会为您详细介绍如何进行语音交互的定义。

意图定义(intent)

在Rokid开发者社区中,意图用来表示用户的一个具体语音请求。如果需要,每一个意图都可以声明自己依赖的词表,也就是需要在语义解析之后需要输出给后端服务的内容。比如在「开始创建第一个技能:我要喝咖啡」这个技能的意图定义中,我们会定义一个询问咖啡馆的意图bestcoffeebar,它需要一个依赖词表city来确定搜索范围。当用户说:“若琪,打开我要喝咖啡问问杭州哪里有好点的咖啡馆。”时,Rokid开发者社区将把bestcoffeebar的intent请求发给您的后端服务,同时还将带上词表名称city中的“杭州”这个值。如果此时未定义city这个词表依赖,“杭州”这个参数将不会被输出给您的后端服务。

您将在意图定义框中用JSON格式定义一套有效的意图。比如如下案例中定义了两个意图:bestcoffeebarnicedrink

{
 "intents": [
  {
   "intent": "bestcoffeebar",
   "slots": [
        {
        "name": "city",
        "type": "LIST_OF_CITIES"
        }
   ],
    "user_says":[
        "..."
        ]
  },
    {
    "intent": "nicedrink"
    }
 ]
}

每个意图都拥有三个参数:

在上述例子中,意图bestcoffeebar依赖的词表是city

词表通过词表名称name和词表内容type来定义。比如,上述例子中的city通过LIST_OF_CITIES这个此表内容来定义,其中包含各城市名称的值(比如杭州、北京)。另外,一个词表还可以引用Rokid开发者社区预先定义好并对外开放的词表内容,比如时间等,此部分将会陆续开放。

用户输入的数据

意图定义完成后,您需要定义用户输入数据和意图之间的映射关系。 用户输入数据通过词表和用户语句来定义。

用户语句(user_says)

您需要为意图配置任何可能的用户语句,形成映射关系。例如,我们对上例中意图定义的JSON进行完善:

{
 "intents": [
  {
   "intent": "bestcoffeebar",
   "slots": [
        {
        "name": "city",
        "type": "LIST_OF_CITIES"
        }
   ],
    "user_says":[
        "$city哪里好点的咖啡馆",
        "$city哪里有好一点的咖啡馆",
        "$city哪里有好点的咖啡馆"
        ]
  }
    {
    "intent": "nicedrink",
    "user_says": [
        "米萨咖啡哪种最好喝",
        "米萨咖啡最好喝的是哪一种",
        ]
    }
 ]
}

这样,有3句不同的用户语句对应到了意图bestcoffeebar,有2句不同的用户语句对应到了意图nicedrink。意味着用户说出这些语句时,就会匹配到对应的意图。

这里面关于$的引用,会在下方自定义词表内容继续说到。

用户语句可以枚举,同时支持正则表达式,具体请参考Rokid正则表达式使用指南

请配置尽可能多的用于语句以匹配用户多种多样的表达方式。另外,在后续填写技能发布信息时,您需要从这些语句中选出3句最能代表您技能特点的语句展示在技能说明中告知用户。

特别提醒: 用户语句是句式强匹配,除特殊情况外,不建议在句末添加标点符号,否则可能会导致句式无法匹配。

比如在上例中将语句加上标点:

杭州哪里好点的咖啡馆?

那么此时只有ASR解析结果为杭州哪里好点的咖啡馆?的语句才可以被识别,而杭州哪里好点的咖啡馆则无法被识别。

相反,如果配置的语句为:

杭州哪里好点的咖啡馆

那么语句杭州哪里好点的咖啡馆?杭州哪里好点的咖啡馆以及末尾带有其他标点的句子均能被正确识别。

自定义词表内容(slot)

在Rokid开发者社区提供的预定义词表之外,开发者可以自定义自己的词表内容。 在上例中,LIST_OF_CITIES词表内容可能包含如下部分:

北京
上海
广州
深圳
杭州

只要有可能被用户说出来的相关词语,你都可以写进词表内容中。Rokid开发者社区将会把用户命中的词表内容直接发送给您的技能。

开发者可以把任何可以抽象的内容定义为词表,并在用户语句中通过$ + 词表名称进行调用。 比如当您希望定义以下几种用户语句时:

我想喝咖啡
我要喝咖啡
我想要喝咖啡
我要喝可乐
我想喝果汁

可以抽象出两个词表:

iwant

我想
我要
我想要

drink

咖啡
可乐
果汁

并通过以下语句统一表达:

$iwant喝$drink

需要注意:

{
  "intents": [
    {
      "intent": "time",
      "slots": [
        {
          "name": "hour",
          "type": "ROKID.NUMBER_ZH"
        },
        {
          "name": "min",
          "type": "ROKID.NUMBER_ZH"
        },
        {
          "name": "sec",
          "type": "ROKID.NUMBER_ZH"
        }
      ],
      "user_says": ["$hour小时", "$min分钟", "$sec秒"]
    }
  ]
}

Confirm用法指南

当您的技能需要在某些场景下对用户的意图进行确认时(尤其是一些不完整的意图,比如当用户说“我饿了”时,您需要向用户确认他想吃什么东西),您可以使用confirm功能来完成语音交互。

以下是一个例子。

补全用户的不完整意图

当用户在您的技能中说:“若琪,我饿了”这样一个不完整意图时,您希望能够去确认并在用户的帮助下补全这个意图。可以参照如下进行语音交互配置。

{
    "intents": [
        {
            "intent": "eat", 
            "slots": [
                {
                    "name": "food", 
                    "type": "list"
                }
            ], 
            "user_says": [
                "!我要吃$food"
            ]
        }, 
        {
            "intent": "confirmeat", 
            "slots": [ ], 
            "user_says": [
                "我饿了"
            ]
        }
    ]
}

语音交互流程

以下是上述场景的完整交互流程。

1502700767023

第一步:当用户说“我饿了”时,交由Rokid Server 处理后,告知技能“我饿了”是confirm类型的用户语句。Request内容如下:

{
    "request": {
        "reqType": "intent", 
        "reqId": "010116000100-ad1f462f4f0946ccb24e9248362c504a", 
        "content": {
            "applicationId": "com.rokid.confirm", 
            "intent": "confirmeat", 
            "slots": { }
        }
    }
}

第二步:技能收到Confirm用户语句时,回传Rokid Server Response,内容示例如下:

{
    "response": {
        "action": {
            "voice": {
                "action": "PLAY", 
                "item": {
                    "tts": "你要吃什么"
                }
            }
        }, 
        "confirm": {
            "confirmIntent": "eat", 
            "confirmSlot": "food", 
            "optionWords": [
                "西瓜", 
                "桔子"
            ]
        }
    }
}

Rokid Server处理消息并向用户询问“你要吃什么”。

第三步:用户回答“我要吃西瓜”,Rokid Server处理消息告知技能{food: 西瓜}。

{
    "request": {
        "reqType": "intent", 
        "reqId": "010116000100-ad1f462f4f0946ccb24e9248362c504a", 
        "content": {
            "applicationId": "com.rokid.confirm", 
            "intent": "eat", 
            "slots": {
                "food": "西瓜"
            }
        }
    }
}

如何退出confirm

使用Js-engine配置Confirm

您可以阅读js-engine 使用指南中 ttsWithConfirm相关配置 了解更多。

Session用法指南

Session可以通过attributes来实现。具体协议请参考技能协议中的Session定义

Session目前只能作用在同一Domain下,切换Domain会清空Session。此时newsession = trueattributes也会被清空。

以问天气为例

当询问天气技能:“今天天气怎么样”时,会开启一个新的session,此时attributes为空,newSession = true,将会发送如下Request给此技能的后端服务:

{
 "context": {
  "application": {
   "applicationId": "xxx"
  },
 },
 "request": {
  "content": {
   "domain": "custom.skill.xxx",
   "intent": "query_weather",
   "slots": {"date":"今天"}
  },
  "reqId": "57792AB32F114788A3E48910FB9CD7BC",
  "reqType": "INTENT"
 },
 "session": {
  "attributes": {},
  "newSession": true
 },
 "version": "2.0.0"
}

收到询问天气的请求后,后端服务会给出Response。 在这一步中,开发者需要让后端服务把city值插入到Response的attributes中,如下:

{
 "response": {
  "action": {
   "shouldEndSession": false,
   "type": "NORMAL",
   "version": "2.0.0",
   "voice": {
    "behaviour": "REPLACE_ALL",
    "item": {
     "tts": "杭州今天的天气很好"
    },
    "needEventCallback": false
   }
  }
 },
 "version": "2.0.0",
 "session": {
        "attributes": {
           "city":"杭州"
        }
    }
}

之后,用户继续向天气技能询问:“明天呢?”。 此时Rokid开发者社区会把attributes中的city属性带到这次的Request中:

{
 "context": {
  "application": {
   "applicationId": "xxx"
  },
 },
 "request": {
  "content": {
   "domain": "custom.skill.xxx",
   "intent": "query_weather",
   "slots": {"date":"明天"}
  },
  "reqId": "57792AB32F114788A3E48910FB9CD7BC",
  "reqType": "INTENT"
 },
 "session": {
  "attributes": {"city":"杭州"},
  "newSession": false
 },
 "version": "2.0.0"
}

以此类推。 但当切换Domain,比如用户说:“我想听一首歌”时,session将会被清空。

其他参考