请求数据指的是平台发送 http(s) post 请求时 body 中的数据,数据格式为 application/json 。
1. 请求数据对象结构
字段名 | type | 描述 | 是否必要 |
sessionId | String | 会话ID,session内的对话此ID相同 | 是 |
utterance | String | 进入意图时用户所说的语句 | 是 |
requestData | Map<String,String> | 请求附带参数,使用天猫精灵音箱调用技能时额外携带的信息, 在线测试无此数据 | 否 |
token | String | 技能配置 OAuth2.0 授权并且用户登录授权账号后可以得到此 token,详细请查看【OAuth2.0配置文档】, 在线测试无此数据 | 否 |
botId | Long | 应用ID,标识用户所使用的的天猫精灵设备的种类 | 是 |
domainId | Long | 领域ID | 是 |
skillId | Long | 技能ID | 是 |
skillName | String | 技能名称 | 是 |
intentId | Long | 意图ID | 是 |
intentName | String | 意图标识 | 是 |
slotEntities | List | 从用户语句中抽取出的 slot 参数信息 | 是 |
selectIndexList | List<Integer> | 上一轮状态标识 resultType: SELECT 时, 用户所做选择的索引值。 | 否 |
confirmStatus | String | 上一轮状态标识 resultType: CONFIRM 时, 用户所进行的确定(CONFIRMED)或否定(DENIED)回答。 | 否 |
device | Device | 用户的设备信息。在线测试没有设备,不会携带设备数据 | 否 |
requestId | String | 本次请求的ID | 是 |
skillSession | SkillSession | 技能粒度的session信息 | 是 |
RequestData 中包含的主要信息字段:
字段名 | type | 描述 |
userOpenId | String | 天猫精灵用户id和技能id混合加密,只能在当前技能中唯一标识用户 |
deviceOpenId | String | 天猫精灵设备id和技能id混合加密,只能在当前技能中唯一标识设备 |
city | String | 天猫精灵设备所处的城市 |
screenStatus | String | 用户使用带屏设备的标识: "screenStatus": "online", 若用户使用的是无屏设备,则没有此条数据。 需要到 权限包管理 中申请“设备有无屏特性”权限包 |
deviceUnionIds | String | 如果技能挂载到组织下,设备在各个组织中的加密id。默认没有此数据,需要额外开通服务卡片账号打通功能 |
userUnionIds | String | 如果技能挂载到组织下,用户在各个组织中的加密id。默认没有此数据,需要额外开通服务卡片账号打通功能 |
SlotEntities 中每一个数组对象SlotEntity的具体字段:
字段名 | type | 描述 | 是否必要 |
intentParameterId | Long | 意图参数ID | 是 |
intentParameterName | String | 意图参数名 | 是 |
originalValue | String | 原始句子中抽取出来的未做处理的 slot 值 | 是 |
standardValue | String | slot 归一化后的值 | 是 |
liveTime | Integer | 该 slot 已存在的会话轮数 | 是 |
createTimeStamp | Long | 该 slot 产生时的时间戳 | 是 |
SkillSession 中包含的主要信息字段:
字段名 | type | 描述 |
skillSessionId | String | 技能粒度session的id |
newSession | Boolean | 用户首次进入技能时:true 用户后续在技能中对话:false 如果技能交互中用户有跳出技能,再次进入技能时:true |
2. Webhook 服务请求结构样例
POST http://your-webhook-service.com/skill/weather Headers: //默认已填充,规定请求体中的数据格式 Content-type: application/json //开发者自定义的headers //key1: value1 //key2: value2 POST body: { "sessionId": "b112a091-1523-4d2d-8059-e09461dafd73", "utterance": "魔都今天天气", "token": "ozkYw9Y8*******lffDM", //技能配置OAuth2授权,并且用户登陆授权账号后会携带 "requestData": { "userOpenId": "XXXXXXXX==", "deviceOpenId": "YYYYYYYYY==", "city": "上海" }, "botId": 10, "domainId": 12345, "skillId": 23456, "skillName": "天气小助手", "intentId": 34567, "intentName": "weather", "slotEntities": [ { "intentParameterId": 45678, "intentParameterName": "city", "originalValue": "魔都", "standardValue": "上海", "liveTime": 0, "createTimeStamp": 1564110905331, "slotName": "city:city", "slotValue": "魔都" }, { "intentParameterId": 56789, "intentParameterName": "time(公共实体)", "originalValue": "今天", "standardValue": "今天", "liveTime": 0, "createTimeStamp": 1564110905331, "slotName": "time(公共实体):sys.time", "slotValue": "今天" } ], "requestId": "20190726111511958-508551760", "device": { }, "skillSession": { "skillSessionId":"8d7501fe-a80a-46cf-a43f-ff8743a7ec66", "newSession":true } }
3.java方式的处理范例
@RequestMapping(value = "/skill/weather", method = RequestMethod.POST) public @ResponseBody ResultModel<TaskResult> getResponse(@RequestBody String taskQuery) { /** * 将开发者平台识别到的语义理解的结果(json字符串格式)转换成TaskQuery */ logger.info("TaskQuery:{}", taskQuery.toString()); TaskQuery query = MetaFormat.parseToQuery(taskQuery); /** * 构建服务返回结果 */ ResultModel<TaskResult> resultModel = new ResultModel<TaskResult>(); try { TaskResult result = weatherHandle.execute(query); resultModel.setReturnCode("0"); resultModel.setReturnValue(result); } catch (Exception e) { } /** * 直接返回ResultModel<TaskResult>对象就ok */ return resultModel; } // 天气服务执行,根据NLU理解的结果做相应处理并返回回复语句 @Component public class WeatherHandleImpl implements WeatherHandle { @Override public TaskResult execute(TaskQuery taskQuery) { logger.info("WeatherHandleImpl execute..."); //从请求中获取意图参数以及参数值 Map<String, String> paramMap = taskQuery .getSlotEntities() .stream() .collect( Collectors.toMap(slotItem -> slotItem.getIntentParameterName(), slotItem -> slotItem.getOriginalValue())); logger.info("paramMap :" + paramMap.toString()); //如果意图是询问空气质量,则执行空气质量逻辑 if ("air_quality".equals(taskQuery.getIntentName())) { return aqiQuery(taskQuery, paramMap); //如果意图是询问天气情况,则执行天气查询逻辑 } else if ("weather".equals(taskQuery.getIntentName())) { return baseQuery(taskQuery, paramMap); } else { return reply("请检查意图名称是否正确,或者新增的意图没有在代码里添加对应的处理分支。"); } } //空气质量查询方法 private TaskResult aqiQuery(TaskQuery taskQuery, Map<String, String> paramMap) { TaskResult result = new TaskResult(); //TODO 根据参数获取空气质量信息 reply = paramMap.get("city") + paramMap.get("date") + "空气质量 优"; return reply(reply); } //天气查询方法 private TaskResult baseQuery(TaskQuery taskQuery, Map<String, String> paramMap) { TaskResult result = new TaskResult(); //TODO 根据参数获取空气质量信息 reply = paramMap.get("city") + paramMap.get("date") + "天气 晴"; return reply(reply); } private TaskResult reply(String reply) { TaskResult taskResult = new TaskResult(); taskResult.setReply(reply); taskResult.setExecuteCode(ExecuteCode.SUCCESS); taskResult.setResultType(ResultType.RESULT); return taskResult; } }