1 平台基本使用

1.1 命名空间

1.1.1 设置命名空间

当您第一次登录 AIUI 开放平台,需要您设置一个独一无二的namespace,概念类似于 C++ 的 namespace 以及 Java 的 Package。用于避免不同用户拥有相同技能名或者实体名时产生的命名冲突。namespace提交后不可修改

1.png

1.2 技能

1.2.1 新建技能

目前每个普通开发者可以创建10个自定义技能,技能发布后技能名不可修改,暂不支持删除技能,请谨慎操作。自定义技能有以下几个状态:

状态 解释
未发布 创建成功后未线上发布
已私有发布 已私有发布成功的技能,仅能在自己的应用中使用
审核中 未发布到技能商店的技能。该技能正在被审核,审核通过后会自动发布到技能商店中
审核未通过 提交发布到技能商店的技能不合法,未通过原因可在技能版本页查询
已发布到技能商店 审核通过并已发布到技能商店的技能,可被其他用户使用
发布失败 尝试再次发布,如果再次发布失败请提交工单处理
已下架 技能已从技能商店中下架。下架后,技能商店页面将不再展示此技能,同时已配置此技能的应用,依然能继续体验此技能的功能

技能和应用是多对多的关系,一个应用可以添加多个技能,一个技能可以被多个应用添加。

2.png

1.2.2 修改技能意图语料

自定义技能创建成功后,每个自定义技能下可以创建20个意图,每个意图最多拥有100条语料。以一个星座技能为例,将会有以下几个意图:

意图 意图名
查询运势 query_lucky
查询幸运数字 query_luckyNumber
查询幸运颜色 query_luckyColor
查询个性分析 query_personality
查询配对星座 query_matching
查询星座知识 query_knowledge
3.png

1.3 实体

1.3.1 新建实体

仍然以创建星座的技能为例,当用户想要询问射手座的幸运数字的时候,提问的语料是:明天射手座的幸运数字是什么,对于开发者来说,关心的有三个层级的数据:

前两个数据,对应的分别是技能名和意图名,针对第三个数据,时间实体在讯飞官方的开放实体中已经提供,开发者不需要重复开发,开发者需要实现的就是星座实体。每个普通开发者可以创建20个实体,没有被使用到应用中的实体可以删除,每个实体最多有10000个词条,每个词条可以有若干个别名。实体和技能是多对多的关系,一个技能可以拥有多个实体,一个实体可以被用到多个技能。

4.png

1.3.2 在语料中使用实体

明天射手座的幸运数字是什么抽象成语料如下:{time}{xingzuo}的幸运数字是什么

查询幸运数字语料
{time}{xingzuo}的幸运数字
{xingzuo}{time}的幸运数字
5.png

1.4 模糊匹配

开发者在实际编写语料的过程中,并不需要穷举所有语料。AIUI 的模糊匹配功能可以覆盖住以下三种情况:

1. 语料中的语气助词的冗余或者缺失

2. 语料中的礼貌用语的冗余或者缺失

3. 语料中通用场景的近义词(暂不支持特定垂直领域)

星座幸运数字的技能为例,开发者只写了两句语料,但是AIUI 智能引擎实际可以理解以下几种提问方式:
1. 明天射手座幸运数字 语气助词缺失
2. 请问明天射手座的幸运数字 礼貌用语冗余
3. 明天射手座的好运数字 近义词

启用方式为,发布时勾选模糊匹配

1.5 问答

1.5.1 新建问答

自定义问答库不支持实体,用于简单的一问一答,一问多答,多问一答和多问多答。支持批量导入。 6.png

1.6 应用配置

1.6.1 在应用中管理技能

在应用配置页内添加技能或者问答。如果开发者遇到专业术语识别率低的问题,可以通过上传热词来解决,对于应用中有的实体词汇,已自动生效为热词,无需重复添加。

7.png

2 Android集成指南

2.1 导入SDK

在AIUI开放平台创建完应用后,即可下载对应的SDK包。将下载的Android SDK压缩包中libs目录下的所有子文件拷贝至Android工程的libs目录下,并将SDK包中assets目录下cfg文件夹以及res目录下vad文件夹拷贝至工程中。工程结构如下图所示:

将Msc.jar添加至工程依赖,将app module下的gradle配置文件中指定默认jniLibs目录为libs。配置文件如下图所示:

2.2 添加用户权限

在工程AndroidManifest.xml文件中添加如下权限

<!--连接网络权限,用于执行云端语音能力 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!--获取手机录音机使用权限,听写、识别、语义理解需要用到此权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!--读取网络信息状态 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!--获取当前wifi状态 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!--允许程序改变网络连接状态 -->
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<!--读取手机信息权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!--读取联系人权限,上传联系人需要用到此权限 -->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<!--外存储写权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!--外存储读权限,构建语法需要用到此权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!--配置权限,用来记录应用配置信息 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<!--手机定位信息,用来为语义等功能提供定位,提供更精准的服务-->
<!--定位信息是敏感信息,可通过Setting.setLocationEnable(false)关闭定位请求 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

注意:如需在打包或者生成APK的时候进行混淆,请在proguard.cfg中添加如下代码:

-keep class com.iflytek.**{*;}
-keepattributes Signature

2.3 初始化

初始化即创建语音配置对象,只有初始化后才可以使用MSC的各项服务。建议将初始化放在程序入口处(如Application、Activity的onCreate方法),初始化代码如下:

// 将“12345678”替换成您应用对应的APPID,申请地址:http://aiui.xfyun.cn
// 请勿在“=”与appid之间添加任何空字符或者转义符
SpeechUtility.createUtility(context, SpeechConstant.APPID +"=12345678");

2.4 创建AIUIAgent

AIUI封装了交互一切复杂性,为开发者提供语音交互的简单易用的接口。SDK中提供的AIUIAgent就是和AIUI交互的桥梁。先创建AIUIAgent,再发送CMD_START消息,使AIUI处于工作状态,示例如下:

//创建AIUIAgent
AIUIAgent mAIUIAgent = AIUIAgent.createAgent(context,getAIUIParams(),mAIUIListener);
//发送`CMD_START`消息,使AIUI处于工作状态
AIUIMessage startMsg = new AIUIMessage(AIUIConstant.CMD_START, 0, 0, null, null);
mAIUIAgent.sendMessage( startMsg );

createAgent 方法包含三个参数:
  ①第一个参数类型为Context;
  ②第二个参数类型为String,具体值是通过读取assets目录下的cfg/aiui_phone_user.cfg文件而获得的字符串;
  ③第三个参数类型为AIUIListener,是AIUI事件回调监听器。

getAIUIParams()具体示例如下所示:

private String getAIUIParams() {
String params = "";
AssetManager assetManager = getResources().getAssets();
try {
InputStream ins = assetManager.open( "cfg/aiui_phone.cfg" );
byte[] buffer = new byte[ins.available()];
ins.read(buffer);
ins.close();
params = new String(buffer);
} catch (IOException e) {
e.printStackTrace();
}
return params;
}

mAIUIListener具体示例如下所示:

AIUIListener listener = new AIUIListener() {
@Override
public void onEvent(AIUIEvent event) {
switch (event.eventType) {
//唤醒事件
case AIUIConstant.EVENT_WAKEUP:
{
break;
}
//结果事件(包含听写,语义,离线语法结果)
case AIUIConstant.EVENT_RESULT:
{
break;
}
//休眠事件
case AIUIConstant.EVENT_SLEEP:
{
break;
}
//错误事件
case AIUIConstant.EVENT_ERROR:
{
break;
}
}
}

2.5 文本语义理解示例

通过构造CMD_WRITE消息,将要进行语义理解的文本数据发送给AIUI,并通过AIUIListener的回调,获取语义结果。代码示例如下:

AIUIMessage msg = new AIUIMessage(AIUIConstant.CMD_WRITE, 0, 0, "data_type=text", "今天天气怎么样".getBytes());
mAIUIAgent.sendMessage(msg);

2.6 语音语义理解示例

发送CMD_WAKEUP消息至AIUI,使AIUI处于唤醒状态,再发送开始录音消息,使麦克风录入音频,并通过AIUIListener的回调,获取语义结果。代码示例如下:

// 先发送唤醒消息,改变AIUI内部状态,只有唤醒状态才能接收语音输入
if( AIUIConstant.STATE_WORKING != this.mAIUIState ){
AIUIMessage wakeupMsg = new AIUIMessage(AIUIConstant.CMD_WAKEUP, 0, 0, "", null);
mAIUIAgent.sendMessage(wakeupMsg);
}
// 打开AIUI内部录音机,开始录音
String params = "sample_rate=16000,data_type=audio";
AIUIMessage writeMsg = new AIUIMessage( AIUIConstant.CMD_START_RECORD, 0, 0, params, null );
mAIUIAgent.sendMessage(writeMsg);

2.7 结果解析

在AIUIEventListener回调中,可以收到来自AIUI的多种消息,具体示例如下:

private AIUIListener mAIUIListener = new AIUIListener() {
@Override
public void onEvent(AIUIEvent event) {
switch (event.eventType) {
case AIUIConstant.EVENT_WAKEUP:
Log.i( TAG, "on event: "+ event.eventType );
showTip( "进入识别状态" );
break;
case AIUIConstant.EVENT_RESULT: {
//解析结果
try {
JSONObject bizParamJson = new JSONObject(event.info);
JSONObject data = bizParamJson.getJSONArray("data").getJSONObject(0);
JSONObject params = data.getJSONObject("params");
JSONObject content = data.getJSONArray("content").getJSONObject(0);
if (content.has("cnt_id")) {
String cnt_id = content.getString("cnt_id");
JSONObject cntJson = new JSONObject(new String(event.data.getByteArray(cnt_id), "utf-8"));
mNlpText.append( "\n" );
mNlpText.append(cntJson.toString());
String sub = params.optString("sub");
if ("nlp".equals(sub)) {
// 解析得到语义结果
String resultStr = cntJson.optString("intent");
Log.i( TAG, resultStr );
}
}
} catch (Throwable e) {
e.printStackTrace();
mNlpText.append( "\n" );
mNlpText.append( e.getLocalizedMessage() );
}
mNlpText.append( "\n" );
} break;
case AIUIConstant.EVENT_ERROR: {
Log.i( TAG, "on event: "+ event.eventType );
mNlpText.append( "\n" );
mNlpText.append( "错误: "+event.arg1+"\n"+event.info );
} break;
case AIUIConstant.EVENT_VAD: {
if (AIUIConstant.VAD_BOS == event.arg1) {
showTip("找到vad_bos");
} else if (AIUIConstant.VAD_EOS == event.arg1) {
showTip("找到vad_eos");
} else {
showTip("" + event.arg2);
}
} break;
case AIUIConstant.EVENT_START_RECORD: {
Log.i( TAG, "on event: "+ event.eventType );
showTip("开始录音");
} break;
case AIUIConstant.EVENT_STOP_RECORD: {
Log.i( TAG, "on event: "+ event.eventType );
showTip("停止录音");
} break;
case AIUIConstant.EVENT_STATE: { // 状态事件
mAIUIState = event.arg1;
if (AIUIConstant.STATE_IDLE == mAIUIState) {
// 闲置状态,AIUI未开启
showTip("STATE_IDLE");
} else if (AIUIConstant.STATE_READY == mAIUIState) {
// AIUI已就绪,等待唤醒
showTip("STATE_READY");
} else if (AIUIConstant.STATE_WORKING == mAIUIState) {
// AIUI工作中,可进行交互
showTip("STATE_WORKING");
}
} break;
case AIUIConstant.EVENT_CMD_RETURN:{
if( AIUIConstant.CMD_UPLOAD_LEXICON == event.arg1 ){
showTip( "上传"+ (0==event.arg2?"成功":"失败") );
}
} break;
default:
break;
}
}
};