请求数据指的是平台发送 http(s) post 请求时 body 中的数据,数据格式为 application/json 。
1. 请求数据对象结构
字段名 | type | 描述 | 是否必要 |
---|---|---|---|
sessionId | String | 会话ID,session内的对话此ID相同 | 是 |
utterance | String | 进入意图时用户所说的语句 | 是 |
requestData | Map |
请求附带参数,使用天猫精灵音箱调用技能时额外携带的信息, 在线测试无此数据 |
否 |
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 |
上一轮状态标识 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;
}
}