为天猫精灵开发一个日程小秘书

本文涉及的产品
函数计算FC,每月15万CU 3个月
简介: 介绍在天猫精灵开发日程小秘书的流程

1. 背景

作为一个码农,程序猿,不能总沉浸在自己的世界里,也得看看外面的繁华和发展。

我时常关注阿里云开发者社区,这里经常会有一些新产品、新想法、新技能,从中我能获取一些产品、开发、测试、运维相关的思维火花。

近期开发者社区推出了天猫精灵的评测活动,正好之前我在杭州菲住布渴酒店体验过,确实有点意思,可以控制电视、灯光、窗帘,也可以跟用户聊天谈心。

但是实际上,我之前还不确定天猫精灵是否有面向开发者的开放平台,也不甚清楚此类开放平台会如何设计、接入,此次借此活动,也是对这种智慧硬件的一次了解和学习。

2. 概念

2.1 天猫精灵

如下图,天猫精灵是一个可以和用户聊天沟通的硬件产品,类似的产品还有百度的小度。可以通过语音跟它沟通,而它可以通过上面的软件应用,来控制家居设备。所以使用起来还是比较科幻的。
在这里插入图片描述

2.2 天猫精灵开放平台

天猫精灵本质上也是个计算机了,上面的应用有阿里内置的,也有程序员开发的。开放平台就是程序员接入天猫精灵的平台,上面有开发文档,有开发流程,有在线测试工具。开放平台就是程序员的一站式开发服务平台。

2.3 技能应用平台

开放平台包含物联网、AI、技能、数字应用相关的平台,用来开发不同种类的应用。技能应用平台主要面向语音交互,也就是开发跟天猫精灵聊天的应用。
在这里插入图片描述

2.4 技能

对程序员来说,就是开发一个应用。但是对天猫精灵来说,就是它学会了一个新的技能。这个技能就是程序员通过程序赋予给它的。

2.5 语音技能

天猫精灵支持的技能类型比较多,包含语音技能、小程序、安卓APP应用、H5小游戏。很好很强大,不过本文我们选择最经典的语音技能进行测评。
在这里插入图片描述

3. 创建技能

3.1 登录

首先,登录天猫技能应用平台,地址:https://iap.aligenie.com/,然后从控制台进入技能应用平台。
在这里插入图片描述

3.2 创建语音技能

如下图,选择自定义技能,这样我们能享有充分的灵活度。
在这里插入图片描述

3.3 填写技能基本信息

填写技能的名字,此处我们开发一个日程小秘书,可以提醒我们日常的待办事项。技能调用词的意思是:当我们对天猫精灵说出这个词时,就会进入我们开发的技能。
另外此处可以选择后端服务,也就是我们的代码,的部署方式。我们可以选择FAAS,直接使用阿里云在线开发、部署、调试、运行。后面会详解描述FAAS使用过程。
在这里插入图片描述

3.4 选择开发方式

首先选择熟悉的语言,这个根据个人喜好选择即可。然后选择空白模板,这样我们能更自由的发挥。
在这里插入图片描述

4. 开发流程

4.1 概述

终于进入激动人心的开发环节了,我们选择了阿里云的FAAS模式,所以所有开发流程都可以在线上完成。阿里的开发实力还是相当强大的,作为程序员都知道,写普通程序或许比较容易,但是写一个用来开发程序的程序,那就不是一个简单的事情了。

好的,我们通过概览里面的示意图,可以看到开发过程主要分基础信息、语音交互模型、构建后端服务、添加屏显页面、测试、发布。接下来我们逐一实现。
在这里插入图片描述

4.2 语音交互模型

语音交互模型我们需要定义意图和实体。意图就是天猫精灵理解我们想要干啥,这个用户想要做的事情抽象为意图。日程小秘书需要的意图如下:

很好理解,当我们使用日程小秘书时,小秘书会欢迎我们。然后小秘书还可以支持日程查询、日程添加的操作。需要注意的是,这三种操作到代码里面,会匹配welcome/query/add标识,这就是现实中的意图和代码中的字符串的对应关系了。
在这里插入图片描述
然后日程添加的时候,我们需要知道添加何种待办事项。这个在程序里面叫做参数,我们需要先建立一个实体来对应待办事项这个概念:
在这里插入图片描述
最后在日程添加意图中,关联这个实体概念。这样当用户对天猫精灵说【吃饭】的时候,吃饭就会进入item这个参数了。
在这里插入图片描述

4.3 开发后端服务

接下来我们需要创建后端服务应用,来决定如何编辑、部署代码。先点击创建应用。
在这里插入图片描述
然后选择FAAS开发模式,这个模式下开发部署测试全程线上,还是比较爽快的。
在这里插入图片描述
然后使用阿里云账号登录云开发平台。
在这里插入图片描述
接下来是一番操作授权,我个人感觉比较麻烦,本来此处是有若干张具体步骤的截图,我感觉意义不大就去掉了。反正此处就是各种授权、开通、同意,如下图之类的东西。
在这里插入图片描述

4.4 代码编辑

终于开始写代码了,点击前往开发:
在这里插入图片描述
这个云开发平台,核心的编辑器感觉就是个VSCode。
在这里插入图片描述
我们编写核心接入类代码如下,其实很好理解,根据不同的意图和参数决定不同的行为。


/**
 * @Description 天猫精灵技能函数入口
 **/
public class GenieEntry extends AbstractEntry {
  @Override
  public ResultModel<TaskResult> execute(TaskQuery taskQuery, Context context) {
    String token = taskQuery.getToken();// 用户标志
    WorkDao workDao = new WorkDao();
    context.getLogger().info("taskQuery: " + JSON.toJSONString(taskQuery));
    ResultModel<TaskResult> res = new ResultModel<>();
    TaskResult taskResult = new TaskResult();

    // 从请求中获取意图参数以及参数值
    Map<String, String> paramMap = taskQuery.getSlotEntities().stream().collect(
        Collectors.toMap(slotItem -> slotItem.getIntentParameterName(), slotItem -> slotItem.getStandardValue()));
    // taskResult.setReply("你的意图是:" + taskQuery.getIntentName());
    String msg = "";
    try {
      // 处理名称为 welcome 的意图
      if ("welcome".equals(taskQuery.getIntentName())) {
        msg = "欢迎使用日程小秘书,我会开心陪伴你处理好每件工作哦";
      } else if ("query".equals(taskQuery.getIntentName())) {
        taskResult.setReply("您今天的任务是:吃饭、睡觉、打豆豆");
        List<Work> works = workDao.getAll();
        if (works.size() == 0) {
          msg = "主人,您今天的事情都已干完,厉害炸了!";
        } else {
          msg = "主人,您今天待办的工作有:";
          for (Work w : works) {
            msg += w.getItem() + ",";
          }
        }
      } else if ("add".equals(taskQuery.getIntentName())) {
        Work work = new Work();
        work.setToken(token);
        work.setItem(paramMap.get("item"));
        workDao.insert(work);
        msg = "好的,主人,我记下来了";
      } else {
        msg = "对不起主人,这事我处理不了";
      }

    } catch (Exception e) {
      msg = e.getMessage();
    }
    taskResult.setReply(msg);
    taskResult.setExecuteCode(ExecuteCode.SUCCESS);
    taskResult.setResultType(ResultType.RESULT);
    res.setReturnCode("0");
    res.setReturnValue(taskResult);
    return res;
  }
}

另外我们将日程数据存入数据库,数据库操作使用了ApacheCommonDbUtils,这个库比较简单,封装代码如下:

/**
 * 数据访问
 */
public class WorkDao {
  /**
   * 新增
   */
  public void insert(Work work) throws Exception {
    Connection conn = ConnectionUtils.getConnection();
    String sql = "insert into work(token,item)values(?,?)";
    Object[] params = { work.getToken(), work.getItem() };
    QueryRunner runner = new QueryRunner();
    runner.update(conn, sql, params);
    ConnectionUtils.releaseConnection(conn);
  }
  /**
   * 移除
   */
  public void deleteById(String id) throws Exception {
    Connection conn = ConnectionUtils.getConnection();
    String sql = "delete from work where id =?";
    Object[] params = { id };
    QueryRunner runner = new QueryRunner();
    runner.update(conn, sql, params);
    ConnectionUtils.releaseConnection(conn);
  }
  /**
   * 更新
   */
  public void update(Work work) throws Exception {
    Connection conn = ConnectionUtils.getConnection();
    String sql = "update work set token=?,item=? where id =?";
    Object[] params = { work.getToken(), work.getItem(), work.getId() };
    QueryRunner runner = new QueryRunner();
    runner.update(conn, sql, params);
    ConnectionUtils.releaseConnection(conn);
  }

  /**
   * 获取一个
   */
  public Work getById(String id) throws Exception {
    Connection conn = ConnectionUtils.getConnection();
    String sql = "select * from work where id =?";
    Object[] params = { id };
    QueryRunner runner = new QueryRunner();
    Work work = (Work) runner.query(conn, sql, new BeanHandler<Work>(Work.class), params);
    ConnectionUtils.releaseConnection(conn);
    return work;
  }

  /**
   * 获取全部
   */
  public List<Work> getAll() throws Exception {
    Connection conn = ConnectionUtils.getConnection();
    String sql = "select * from work ";
    QueryRunner runner = new QueryRunner();
    List<Work> works = runner.query(conn, sql, new BeanListHandler<Work>(Work.class));
    ConnectionUtils.releaseConnection(conn);
    return works;
  }
}

/**
 - 数据库连接工具类
 */
public class ConnectionUtils {

  // 连接所需的固定参数
  private static String driver = "com.mysql.jdbc.Driver";
  private static String url = "jdbc:mysql://39.101.138.173:3306/calendar?useUnicode=true&characterEncoding=utf-8&useSSL=false";
  private static String user = "root";
  private static String password = "xxxxxx";
  /**
 - 获取连接
 - 
 - @throws ClassNotFoundException
   */
  public static Connection getConnection() throws SQLException, ClassNotFoundException {
    Class.forName(driver);
    return DriverManager.getConnection(url, user, password);
  }
  /**
 - 释放连接
   */
  public static void releaseConnection(Connection conn) {
    if (conn != null)
      try {
        conn.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
  }
}

此处解释几点:

  • 天猫精灵项目基于maven构建,所以我们可以轻易地通过pom.xml引入各种依赖库。
  • 天猫精灵访问公网资源,例如数据库或者HTTP协议的API接口,并无限制。

4.5 使用Git保存源码

跟VSCode类似,直接使用云开发平台提交代码即可。千万不要忘了提交,不然下次进入云开发平台,代码就丢了。
在这里插入图片描述

4.6 代码部署

点击左侧部署菜单,然后选择【预发环境】,点击最下面的部署按钮,即可将天猫精灵部署到预发环境。此处的预发环境可以理解为测试环境。
在这里插入图片描述
点击部署后,控制台会提示部署信息,直到最后部署完成。
在这里插入图片描述

4.7 在线测试

通过在线测试,可以模拟与天猫精灵的会话过程。这个很好理解,就是通过文字代表了语音而已。看看我们日程小秘书的运行过程。是不是有点意思哈。
在这里插入图片描述

4.8 真机测试与发布

由于真机尚未拿到,所以暂时未进行真机测试与正式发布工作,此处简单解释下。

真机测试,就是将开发的技能应用,使用真实的设备进行测试,这样的话更接近真实使用环境,测试效果更加。

发布的话,肯定是需要经过阿里审核的,避免出现质量低下,或者出现不良内容。

5. 小结

其实语音技能还支持屏显页面开发,当然还提供了很丰富的接口供开发者调用,此处不再详细介绍,感兴趣的同学可以登录开放平台自行研究。

从天猫精灵开放平台的推出,可以看到现在很多产品,都是在建立生态。不仅仅是依靠一家公司,还有全世界开发者的合力,凝聚更强大的生命力。

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
JSON 小程序 前端开发
微信小程序会议OA系统
微信小程序会议OA系统
93 0
基于宜搭的“设备报修”实践案例
设备报修是各企业、学校、医院等单位必不可少的应用场景,包括设备管理、用户报修、报修单管理、派单管理、维修管理等。那么,如何利用宜搭+钉钉实现高效的设备报修管理呢?
基于宜搭的“设备报修”实践案例
|
6月前
|
传感器 小程序 搜索推荐
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
通过电子班牌设备和智慧校园数据平台的统一管理,在电子班牌上,班牌展示、学生上课刷卡考勤、考勤状况汇总展示,课表展示,考场管理,请假管理,成绩查询,考试优秀标兵展示、校园通知展示,班级文化各片展示等多种化展示。
97 0
(源码)java开发的一套(智慧校园系统源码、电子班牌、原生小程序开发)多端展示:web端、saas端、家长端、教师端
深入解读:多人语音聊天室源码开发搭建社交分享功能
我们就实现了多人语音聊天室源码开发搭建的社交分享功能,社交分享功能对于多人语音聊天室源码平台是非常重要的,它可以方便地扩大交流范围、提升互动性、促进合作和协作,同时增强用户体验。
深入解读:多人语音聊天室源码开发搭建社交分享功能
|
小程序 容器
【微信小程序】无纸化会议OA系统之首页搭建(上)
【微信小程序】无纸化会议OA系统之首页搭建(上)
80 0
|
小程序 前端开发 安全
【微信小程序】无纸化会议OA系统之首页搭建(下)
【微信小程序】无纸化会议OA系统之首页搭建(下)
140 0
|
JSON 小程序 JavaScript
微信小程序会议OA系统其他页面
微信小程序会议OA系统其他页面
54 0
|
JSON 小程序 JavaScript
会议OA小程序【会议管理,个人中心页面布局】
会议OA小程序【会议管理,个人中心页面布局】
|
机器学习/深度学习 域名解析 网络协议
|
API 智能硬件
天猫精灵私域分享初体验
现在智能家居的使用已经在大众的生活中非常普遍,自己最满意的产品应该算是天猫精灵系列了。最早使用方糖,后来参加活动赢了天猫精灵X5,今天突然听说天猫精灵官方团队开放了私有API,可以让大家DIY一下天猫精灵。