Unresolved directive in index.adoc - include::/root/.jenkins/workspace/deep-brain-admin(prod-106)/target/asciidoc/generated/deep-brain-skills-development-api/overview.adoc[]
== DeepBrain system Introduction

1. DeepBrain简介

    DeepBrain,深度语义云大脑,是一套基于语义理解的机器人SaaS云大脑平台,整个平台包含Web管理系统、DeepBrain API服务接口以及云大脑语义理解系统、技能商店。DeepBrain API提供了平台的对外服务接口,包含平台的核心业务如意图识别、技能服务、私有对话等。本文档主要介绍如何基于API开发用户自己的技能。

2. DeepBrain 技能简介

    DeepBrain 技能,是Deepbrain云平台的核心组成部分,也是平台对外输出的重要形式。智能终端或者智能服务平台,通过调用Deepbrain的技能,实现自身功能的智能化和多样化。以机器人厂商为例,厂商首先在Deepbrain平台上创建自有品牌的机器人,然后从技能商店以购买的方式为机器人添加各种技能。这些技能可以是 Deepbrain 平台的标准技能,也可以是技能开发者提供的技能。一个完整的技能,主要由两个部分构成:意图识别以及内容服务。以讲故事技能为例:第一步,技能开发者需要实现故事意图的识别,并提取出故事的相关信息,如故事名称、故事类型等。第二步,基于意图识别的结果,遵循一定的格式提供相关故事的内容信息,如文本、资源链接等。所以,技能开发者,在开发 Deepbrain 技能的时候,需要同时实现意图识别并提供内容服务。技能开发者开发完技能,可以提交到 Deepbrain 平台的技能商店进行销售,机器人厂商可以在平台上为机器人购买技能,机器人的终端用户,可以在机器App中购买技能,两者都是技能的潜在客户。

Unresolved directive in index.adoc - include::/root/.jenkins/workspace/deep-brain-admin(prod-106)/target/asciidoc/generated/deep-brain-skills-development-api/paths.adoc[]
== 技能开发说明

3. 技能开发准备

    开发者开发Deepbrain技能,首先需要在Deepbrain平台注册自己的账号(参照Appendix获取邀请码),然后以技能开发者的身份进入系统,创建想要开发的技能。

3.1. 选择用户角色

img 02

3.2. 创建技能

img 03

4. 如何实现意图识别

    技能开发者可以(需要)在 Deepbrain 平台上创建意图及相关参数,配置句式,完成意图识别的过程。关于如何合理的配置意图及参数,请参照网站的演示视频介绍。
img 05

5. 如何提供内容服务

技能的内容服务,可以通过Deepbrain平台配置实现,也可以通过自定义内容服务实现。

5.1. 基于平台的内容服务

    基于平台的内容服务,可以是问答服务,也可以是资源链接服务。问答服务通过配置知识库实现,资源链接服务通过配置资源实现。详细的配置,请参照网站deepbrain.ai的演示视频。

img 07

5.2. 自定义内容服务

    除了在 Deepbrain 平台配置内容服务,用户也可以自定义内容服务,只要内容服务的输入输出符合Deepbrain平台的接口规范(参照下一章节)即可。用户配置好意图识别功能,并且在平台之外开发好内容服务后,可以通过技能商店-"我发布的技能"模块发布该技能。
img 08
img 10

Unresolved directive in index.adoc - include::/root/.jenkins/workspace/deep-brain-admin(prod-106)/target/asciidoc/generated/deep-brain-skills-development-api/definitions.adoc[]
== 技能开发接口详情

6. 接口通用说明

DeepBrain API为Restful风格的服务,采用HTTP/HTTPS协议实现,接口输入输出参数均使用UTF-8编码的JSON格式字符串。

HTTP数据 说明

调用地址

开发者技能发布界面配置的URL,如http://<mydomain>:<myport>/<myServicePath>

调用方式

POST

数据格式

JSON

安全认证

Deepbrain平台在调用用户自定义内容服务接口时,会提供appId+functionId信息作为技能账号信息,服务提供方可以据此验证请求的合法性。

请求数据

消息主体采用JSON格式定义。消息头部需要设置contentType及accept支持json数据发送和接受。消息体区分大小写。

6.1. 技能服务请求参数FunctionServiceRequest

字段 类型 描述 非空

inputText

String

输入文本

Y

functionServiceAccount

FunctionServiceAccount

技能账号信息

Y

commandCode

String

意图代码

commandName

String

意图名称

location

RequestLocation

请求源地址信息

extParams

List<CommonAttribute>

扩展的请求参数

6.2. 技能账号信息 FunctionServiceAccount

字段 类型 描述 非空 默认值

appId

String

公司唯一编码

Y

functionId

7. 请求位置信息

字段 类型 描述 非空

cityName

String

城市信息(中文名,如上海、北京、广州)

longitude

String

经度信息(浮点类型字符串)

latitude

String

纬度信息(浮点类型字符串)

7.1. 通用属性信息CommonAttribute

字段 类型 描述 非空 默认值

attrName

String

属性名

Y

attrValue

7.2. 技能服务响应参数FunctionServiceResponse

字段 类型 描述 非空 默认值

commandData

CommandData

响应数据

functionServiceRequest

7.3. 内容数据CommandData

字段 类型 描述 非空

inputText

String

文本输入内容

commandCode

String

意图代码

Y

commandName

String

意图名称

commandSource

String

意图源 private standard

commandAttrs

List< CommonAttribute> 意图参数列表,参数识别结果

dataType

String

数据类型1)text纯文本 2)hylink访问地址

Y

isAsk

Boolean

是否为反问

ttsText

String

反问内容或者对话结果

linkType

String

连接资源类型 1)video视频资源 2)audio音频资源 3)img图片资源 4)rpc远程调用资源

textResources

List<TextResource >

tts列表

linkReources

7.4. 链接资源信息 LinkResource

字段 类型 描述 非空

accessURL

String

链接地址

Y

linkType

String

连接资源类型 1)video视频资源 2)audio音频资源 3)img图片资源 4)rpc远程调用资源

Y

resName

String

资源名称

Y

resAttrs

List< CommonAttribute>

资源属性列表

7.5. 文本资源信息TextResource

字段 类型 描述 非空

ttsText

String

文本输出

1. 技能开发示例

1.1. 天气技能开发Java示例

1.1.1. 技能配置

创建技能"生活百科"
img 15
配置实体参数日期城市,添加数据
img 157
img 18
img 19
创建意图"别问天气"并添加句式
img 21
img 22
测试配置
img 24
内容服务开发
    详细内容可以参照SDK包,这里仅介绍开发的几个主要步骤。
定义内容服务实现
@Component("别问天气")
public class WeatherQueryService extends BaseAbilityService {
    private static String[] daily_term = new String[]{"今天", "明天", "后天", "大后天"};
    private static String[] weekly_term = new String[]{"一周"};
    private static Log logger = LogFactory.getLog(WeatherQueryService.class);

    public FunctionServiceResponse invoke(FunctionServiceRequest request) {
        FunctionServiceResponse response = new FunctionServiceResponse();
        if (request != null && StringUtils.isNoneBlank(request.getInputText()) && request.getExtParams() !=
                null) {
            String city = getParamValue("城市", request.getExtParams());
            String day = getParamValue("日期", request.getExtParams());
            String weatherReport = queryWeather(city, day);
            logger.info(weatherReport);
            CommandData commandData = getCommandFromRequest(request);
            commandData.setDataType(DataType.TEXT.getValue());
            commandData.setTtsText(weatherReport);
            response.setCommandData(commandData);
        }
        return response;
    }

    private static String queryWeather(String city, String day) {
        String weatherReport = null;
        String baiduURL = SysConfigUtils.getConfigProperty("jd-weather-url");
        baiduURL = StringUtils.replace(baiduURL, "{城市}", city);
        String result = HttpRequestUtils.httpGet(baiduURL);
        Map weather = new Gson().fromJson(result, Map.class);
        if (weather != null && "查询成功".equals(weather.get("msg"))) {
            Map resultData = (Map) ((Map) weather.get("result")).get("result");
            List<Map> dailyWeather = (List<Map>) resultData.get("daily");
            if (StringUtils.isEmpty(day)) {
                day = "今天";
            }
            if (ArrayUtils.contains(daily_term, day)) {
                if ("今天".equals(day)) {
                    String weatherStr = (String) resultData.get("weather");
                    String tempStr = resultData.get("templow") + "至" + resultData.get("temphigh") + "度";
                    String windStr = resultData.get("winddirect") + ", 风力" +
                            resultData.get("windpower");
                    Map aqiInfo = ((Map) ((Map) resultData.get("aqi")).get("aqiinfo"));
                    String qualityStr = "空气质量" + aqiInfo.get("level") + ", " + aqiInfo.get("affect");
                    String weatherReportTemp = dailyWeatherReportTemplate();
                    weatherReportTemp = StringUtils.replace(weatherReportTemp, "${日期}", "今天");
                    weatherReportTemp = StringUtils.replace(weatherReportTemp, "${城市}", city);
                    weatherReportTemp = StringUtils.replace(weatherReportTemp, "${天气}", weatherStr);
                    weatherReportTemp = StringUtils.replace(weatherReportTemp, "${温度}", tempStr);
                    weatherReportTemp = StringUtils.replace(weatherReportTemp, "${风力}", windStr);
                    weatherReport = StringUtils.replace(weatherReportTemp, "${空气质量}", qualityStr);
                } else {
                    Map dailyReport = dailyWeather.get(dayIndex(day));
                    Map dayWeather = (Map) dailyReport.get("day");
                    Map nightWeather = (Map) dailyReport.get("night");
                    String dayWeatherStr = day + "白天, " + dayWeather.get("weather") + ", " +
                            dayWeather.get("winddirect") + ", 风力" + dayWeather.get("windpower") + ", 最高温度" +
                            dayWeather.get("temphigh") + "度";
                    String nightWeatherStr = day + city + "夜间 " + nightWeather.get("weather") + ", " +
                            nightWeather.get("winddirect") + ", 风力" + nightWeather.get("windpower") + ", 最低温度" +
                            nightWeather.get("templow") + "度";
                    weatherReport = city + dayWeatherStr + ", " + city + nightWeatherStr;
                }
            } else if (ArrayUtils.contains(weekly_term, day)) {
            }
        }
        System.out.println(weatherReport);
        return weatherReport;
    }

    public static int dayIndex(String day) {
        for (int i = 0; i < daily_term.length; i++) {
            String s = daily_term[i];
            if (StringUtils.equalsIgnoreCase(day, s)) {
                return i;
            }
        }
        return 0;
    }

    public static String dailyWeatherReportTemplate() {
        return "${日期} ${城市} ${天气}, ${温度}, ${风力}, ${空气质量}";
    }
}
定义对外接口
@Controller
@Scope("prototype")
public class AbilityController {
    @ResponseBody
    @RequestMapping(value = "/api/invoke", method = RequestMethod.POST, produces =
            MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<FunctionServiceResponse> abilityInvoke(
            @RequestBody FunctionServiceRequest functionServiceRequest, HttpServletRequest
            httpRequest) {
        FunctionServiceResponse response = null;
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        if (AbilityServiceDispatcher.validRequest(functionServiceRequest)) {
            response = AbilityServiceDispatcher.dispatch(functionServiceRequest);
            if (response == null) {
                response = new FunctionServiceResponse();
            }
            response.setFunctionServiceRequest(functionServiceRequest);
            MultiValueMap<String, String> header = new LinkedMultiValueMap<String, String>();
            header.add("PROCESSED_TIME_IN_MS", "" + stopWatch.getTotalTimeMillis());
            return new ResponseEntity<FunctionServiceResponse>(response, header, HttpStatus.OK);
        } else {
            MultiValueMap<String, String> header = new LinkedMultiValueMap<String, String>();
            header.add("PROCESSED_TIME_IN_MS", "" + stopWatch.getTotalTimeMillis());
            response = new FunctionServiceResponse();
            response.setFunctionServiceRequest(functionServiceRequest);
            return new ResponseEntity<FunctionServiceResponse>(response, header,
                    HttpStatus.BAD_REQUEST);
        }
    }
}

1.2. 接口地址测试

    http://xxx:xx/myAbility/api/Invoke

1.3. 服务发布及测试

1.3.1. 发布技能

img 28
img 30

1.3.2. 待平台审核通过后,技能商店中可以测试

img 31
img 33

1.4. 请求响应消息JSON示例

1.4.1. FunctionServiceRequest请求示例

{
  "functionServiceAccount": {
    "appId": "6ef0f5e60d3711e79cf590b11c244b31",
    "functionId": "6ef0f5e60d3711e79cf590b11c244b88"
  },
  "inputText": "明天广州天气",
  "commandCode": "C879889442000109568",
  "commandName": "别问天气",
  "extParams": [
    {
      "attrName": "日期",
      "attrValue": "明天"
    },
    {
      "attrName": "城市",
      "attrValue": "广州"
    }
  ]
}

1.4.2. FunctionServiceResponse响应示例

{
  "commandData": {
    "inputText": "明天广州天气",
    "commandCode": "C879889442000109568",
    "commandName": "别问天气",
    "isAsk": false,
    "ttsText": "广州明天白天,雷阵雨,无持续风向,风力微风, 最高温度35度,广州明天广州夜间多云,无持续风向, 风力微风, 最低温度27度",
    "dataType": "text"
  },
  "functionServiceRequest": {
    "functionServiceAccount": {
      "appId": "6ef0f5e60d3711e79cf590b11c244b31"
    },
    "inputText": "明天广州天气",
    "commandCode": "C879889442000109568",
    "commandName": "别问天气",
    "extParams": [
      {
        "attrName": "日期",
        "attrValue": "明天"
      },
      {
        "attrName": "城市",
        "attrValue": "广州"
      }
    ]
  }
}

2. SDK下载

2.1. Java语言SDK下载