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. 小结
其实语音技能还支持屏显页面开发,当然还提供了很丰富的接口供开发者调用,此处不再详细介绍,感兴趣的同学可以登录开放平台自行研究。
从天猫精灵开放平台的推出,可以看到现在很多产品,都是在建立生态。不仅仅是依靠一家公司,还有全世界开发者的合力,凝聚更强大的生命力。