小爱语音技能开发--币价查询

Xiaoai Skill Development

Posted by Shunda on June 8, 2018

前言

五月份参加清华黑客马拉松时了解到了小米的小爱技能开发大赛,因为之前有过类似的百度DuerOS技能开发的经验,所以就想着顺手做个小爱的语音技能,顺便看下小爱开放平台和百度的有什么区别。

技能介绍

实现的语音技能很简单:币价查询。通过技能可以查询到 gate.io 上各种加密数字货币的当前价格和涨跌幅度。

技能配置

1. 创建技能

首先进入小爱技能平台,创建技能:

2. 填写技能信息

技能创建后需要填写技能信息,主要是介绍技能的功能和调用方式,用于在技能商店对用户进行呈现。

特别需要注意的一点是,小爱对于技能图标有着比较严格的设计规范,如果图标不按规范进行设计,应该是很难通过技能审核的(技能认证标准)。

技能图标需要提供两种,一种是用于技能中心的技能列表,需要使用小爱提供的颜色基础进行设计,同时表面的图案需要是白色如图:

另一种是用于技能的详情页中,需要把原有的底色变成透明同时设计投影:

详细的设计规范论坛中有提供下载,包括背景板的PNG文件:skill图标规范

不过设计规范文件是sketch格式的,让我这个Windows用户感受到了伤害。。。我装了个叫 Icons8 Lunacy 的软件来在Windows中打开sketch格式的文件,图标最后我是拿PS手画出来的。本来只是想写写代码的,没想到还要干设计的活。

Windows中打开sketch文件的多种方法:
https://icons8.com/articles/how-to-open-sketch-file-on-windows/

3. 创建意图

下一步便是创建技能的意图,需要设定常用表达和槽位。我在这里创建了一个叫query_price的意图,由于需要知道用户要查询的是哪个币种,所以在常用表达中得设置一个{coin}槽位,用来获取请求的币种。

4. 自定义词表

槽位需要和词表进行关联,这样技能才知道这个槽位对应有哪些关键词。一些常用的词表系统里有自带,如数字、城市、颜色等,但是数字货币的币种是没有自带的词表的,所以需要自己创建自定义词表。gate.io 上的币种列表可以通过这个接口获取:https://data.gateio.io/api2/1/marketlist

为了方便之后构造不同币种的查询链接,我这里的词条都设置为了币种的小写英文名称。之所以设置成小写,是因为在模拟APP上测试的时候我发现小爱在识别英文字母时,都是识别成小写字母,而且只能匹配到小写的关键词。如果词表里的是大写的关键词,会识别不到。这点我觉得小爱可以改进下,在匹配英文关键词时忽略大小写。

有的币种有中文名称,比如以太坊、比特币等,这些可以在同义词一栏设置。这样的话在槽位识别时也能识别出这些中文的关键词,而且返回的槽位值都是对应的词条名称,也就是币种的小写英文名称。

5. 关联词表

词表创建好后回到之前的意图页面,将槽位和词表关联起来:

然后可以使用系统里提供的交互模型测试工具来测试意图和槽位是不是能被正确识别出来:

可以看到输入查询以太坊价格后,能正确得到槽位值eth,说明技能的交互模型已经正确创建好了。

币价查询

能正确得到槽位值后,还得根据槽位值去查询交易所中相应币种的价格,并且将查询的结果返回给用户。

币价查询用的是 gate.io 提供的api:

返回的数据格式是这样的:

{
    "quoteVolume": "10950.8828518602",
    "baseVolume": "6614629.680875099508",
    "highestBid": "599.77",
    "high24hr": "608.88",
    "last": "599.77",
    "lowestAsk": "601.45",
    "elapsed": "23ms",
    "result": "true",
    "low24hr": "596",
    "percentChange": "-0.016670278560359"
}

我做的功能比较简单,只告诉用户当前的价格和涨跌幅度,所以只用到了其中的lastpercentChange字段。

技能开发

终于到需要写代码的部分了,基本这类技能开放平台都提供了两种方式来开发技能:一种是通过函数计算的方式,另一种是通过SDK自己搭个HTTPS服务。函数计算肯定是方便很多,不需要关心环境怎么搭,我这里也使用了小米提供的函数计算服务来开发技能。

1. 新建工作空间

进入 小米开放云,选择函数计算,然后新建一个工作空间:

2. 新建函数

进入刚建的工作空间,新建一个函数用于查询币价:

3. 编写技能代码

小米提供的函数计算服务支持Python语言,我这里选择的运行环境是python3,技能代码如下:

from xiaoai import *
import requests

def outputJson(toSpeakText, is_session_end, openMic=True):
    xiaoAIResponse=XiaoAIResponse(to_speak=XiaoAIToSpeak(type_=0, text=toSpeakText), open_mic=openMic)
    response = xiaoai_response(XiaoAIOpenResponse(version="1.0",
                                     is_session_end=is_session_end,
                                     response=xiaoAIResponse))
    return response

def main(event):
    req = xiaoai_request(event)
    
    if req.request.type == 0:
        return outputJson("欢迎来到币价查询,你可以通过此技能查询数字货币的当前币价,请问你要查询什么币种", False)
    elif req.request.type == 1:
        if ((not hasattr(req.request, "slot_info")) or (not hasattr(req.request.slot_info, "intent_name"))):
            return outputJson("抱歉,我没有听懂", False)
        else:
            if req.request.slot_info.intent_name == 'query_price':
                slotsList = req.request.slot_info.slots
                coin_type = [item for item in slotsList if item['name'] == 'coin'][0]['value']
                r = requests.get('https://data.gateio.io/api2/1/ticker/' + coin_type.lower() + '_usdt')
                data = r.json()
                reply = coin_type + "当前币价为" + data['last'] + "美元,"
                if data['percentChange'][0] == '-':
                    reply += "跌幅百分之" + data['percentChange'][1:6]
                else:
                    reply += "涨幅百分之" + data['percentChange'][0:5]
                return outputJson(reply, False)
            else:
                return outputJson("抱歉,我没有听懂", False)
    else:
        return outputJson("感谢使用币价查询,下次再见", True, False)

4. 设置触发器

触发器这里选择SkiilTrigger

然后在函数详情页中可以看到触发器对应的key

5. 配置服务端口类型

回到技能配置页面,将触发器的key填到服务端口类型中,技能就算对接好了:

测试与调试

小爱开放平台提供了三种测试技能的方式:在线测试、真机测试和模拟APP测试。我因为没有小爱音响,所以就只通过在线测试和模拟APP进行了测试。

此外,小米的函数计算服务提供了日志功能,可以查看一些报错信息,所以如果有bug调试起来还是挺方便的。

小结

整个技能开发流程和之前开发DuerOS技能时基本一致,体验还是不错的,特别是函数计算,提供了日志和监控功能,对于开发者来说在调试和监控上方便了很多。

比较特殊的就是图标有设计规范,花了不少时间画图标。词表那部分在使用时也发现存在着一些bug,比如有时候词条删除后页面中还会照样显示被删除的词条。

在线测试现在只支持文本输入,建议可以考虑支持语音输入。