1 AIUI SDK

1.1 AIUI接口概述

1.1.1 概述

AIUI封装了交互一切复杂性,为开发者提供语音交互的简单易用的接口。

SDK中提供的AIUIAgent就是和AIUI交互的桥梁。开发者可以通过发送不同的AIUIMessage控制AIUI的运行,如通过发送CMD_WAKEUP使AIUI进入唤醒就绪状态,发送CMD_RESET_WAKEUP使AIUI进入休眠状态。同时通过AIUIListener监听接收AIUI抛出的AIUIEvent进行解析,如通过EVENT_RESULT解析AIUI返回的听写和语义结果,通过EVENT_SLEEP得知AIUI进入休眠状态。

AIUI移动端解决方案支持Android,iOS,Linux,Windows,在各个平台下提供的接口都和上述描述的类似,因各平台语言不同会有些许差别。

后面的功能说明的示例代码都是针对Android平台下,但其功能也同样适用于其他平台,如有特殊情况会有说明。

Android下的AIUI接口调用示例:

AIUIListener listener = new AIUIListener() {
@Override
public void onEvent(AIUIEvent event) {
switch (event.eventType) {
//唤醒事件
case AIUIConstant.EVENT_WAKEUP:
{
break;
}
//结果事件(包含听写,语义,离线语法结果,定义和解析格式参见2.2.2 AIUIEvent一节)
case AIUIConstant.EVENT_RESULT:
{
break;
}
//休眠事件
case AIUIConstant.EVENT_SLEEP:
{
break;
}
//错误事件
case AIUIConstant.EVENT_ERROR:
{
break;
}
}
}
String config = ConfigUtil.readSdcardCfg(ServiceConstant.SDCARD_AIUI_CFG_PATH);
AIUIAgent agent = AIUIAgent.createAgent(MainActivity.this, listener);
//只是为了演示sendMessage的调用逻辑,放在此处并没有什么意义
//agent.sendMessage(new AIUIMessage(AIUIConstant.CMD_RESET_WAKEUP, 0, 0, null, null);

后面会详细介绍Android系统下的AIUI接口定义及调用,其他平台可以参考Android平台的说明和对应平台下SDK中对应的定义和Demo源码。

1.1.2 调用流程注意

使用AIUIAgent前需要初始化MSC,在Android平台下如下示例初始化:

SpeechUtility.createUtility(SpeechApp.this, "appid=" + getString(R.string.app_id));

根据AIUI状态的说明,AIUI只有在唤醒状态下才能接收语音交互, 所以SDK在初始化先需要发送CMD_START开始AIUI,再发送CMD_WAKEUP让AIUI进入唤醒状态:

mAIUIAgent = AIUIAgent.createAgent( this, getAIUIParams(), mAIUIListener );

AIUIMessage startMsg = new AIUIMessage(AIUIConstant.CMD_START, 0, 0, null, null);
mAIUIAgent.sendMessage(startMsg);

AIUIMessage wakeupMsg = new AIUIMessage(AIUIConstant.CMD_WAKEUP, 0, 0, "", null); 
mAIUIAgent.sendMessage(wakeupMsg);

进入唤醒状态后再根据录音配置写入音频或者控制内部录音进行交互, 具体实现参考SDK中SpeechDemo的源码实现。

1.2 Android

1.2.1 接口说明

AIUIServiceKit中用于与AIUIService交互的接口类为AIUIAgent
AIUIAgent提供如下接口:

//创建AIUIAgent实例
static AIUIAgent createAgent(Context context, String cfg, AIUIListener listener)
//发送AIUI消息
void sendMessage(AIUIMessage message)
//销毁AIUIAgent实例
void destroy()

cfg内容参见AIUI配置文件

AIUIListener

创建AIUIAgent时传递的参数AIUIListener是用于接受AIUIService抛出事件的监听器。
AIUIListener定义如下:

interface AIUIListener
{
  void onEvent(AIUIEvent event);
}

AIUIEvent

AIUIListener中监听的抛出事件的类型是AIUIEvent

AIUIEvent定义如下:

class AIUIEvent
{
  int eventType; //事件类型
  int arg1; //参数1
  int arg2; //参数2
  String info;
  Bundle data;
}

AIUI定义了多种AIUIEvent,有不同eventType。当AIUIEvent取不同的eventType时,其余字段有不同的定义,详细定义请见 AIUIEvent的定义说明。

AIUIMessage

AIUIAgent中sendMessage方法用于向AIUIService发送AIUI消息。消息类型是AIUIMessage

AIUIMessage定义如下:

class AIUIMessage
{
  int msgType; //消息类型
  int arg1; //参数1 默认空值 0
  int arg2; //参数2 默认空值0
  String params; //默认空值 ""
  byte[] data; //默认空值 null
}

AIUI定义了多种AIUIMessage,有不同的msgType。当AIUIMessage取不同的msgType时,其他成员有不同的定义,详细定义解释请见 AIUIMessage的定义说明。

1.2.2 调用流程

AIUIServiceKit的一般调用流程如下:

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;
}
}
}
}
String config = ConfigUtil.readSdcardCfg(ServiceConstant.SDCARD_AIUI_CFG_PATH);
AIUIAgent agent = AIUIAgent.createAgent(MainActivity.this, config, listener);
//开始AIUI
AIUIMessage startMsg = new AIUIMessage(AIUIConstant.CMD_START, 0, 0, null, null);
mAIUIAgent.sendMessage( startMsg );

1.3 IOS

1.3.1 接口说明

IAIUIAgent
iflyMSC.framework中用于与AIUIService交互的接口类为IAIUIAgent
IAIUIAgent提供如下接口:

/
* AIUI代理类,单例对象,应用通过代理与AIUI交互。
*/
class IAIUIAgent
{
public:
AIUIEXPORT virtual ~IAIUIAgent();
/
* 创建Agent单例对象,AIUI开始工作。
* 注:该方法总是返回非空对象,非空并不代表创建过程中无错误发生。
*
* @param params 参数设置
* @param listener 事件监听器
* @return AIUIAgent单例对象指针
*/
AIUIEXPORT static IAIUIAgent* createAgent(const char* params, IAIUIListener* listener);
/
* 发送消息给AIUI,消息中可以包含命令、参数和数据,具体格式参见IAIUIMessage。
*
* @param msg AIUI消息
* message 如果指定了非空的Buffer *data, 在Message在内部处理后会自动release()这部分data;
* 而不能外部去释放掉。
*/
virtual void sendMessage(IAIUIMessage* message) = 0;
/
* 销毁AIUIAgent对象,AIUI停止工作。
*/
virtual void destroy() = 0;
};

cfg内容参见AIUI配置文件

IAIUIListener

创建IAIUIAgent时传递的参数IAIUIListener是用于接受AIUIService抛出事件的监听器。
IAIUIListener定义如下:

/
* AIUI事件监听接口。SDK所有输出都通过回调onEvent方法抛出。
*/
class AIUIListener
{
public:
AIUIEXPORT virtual ~AIUIListener();
/
* 事件回调,SDK所有输出都通过event抛出。
*
* @param event AIUI事件
*/
virtual void onEvent(IAIUIEvent& event) = 0;
};
typedef AIUIListener IAIUIListener;

IAIUIEvent

IAIUIListener中监听的抛出事件的类型是IAIUIEvent

IAIUIEvent定义如下:

/
* AIUI事件类。业务结果、SDK内部状态变化等输出信息都通过事件抛出。SDK通过回调抛出事件后会
* 立即释放事件中的内存对象,若要在别处使用到这些内存对象,开发者需要在回调中做拷贝。
*/
class IAIUIEvent
{
public:
AIUIEXPORT virtual ~IAIUIEvent();
/
* 获取事件类型。取值参见AIUIConstant中EVENT_开头的常量定义。
*/
virtual int getEventType() = 0;
/
* 获取扩展参数1。
*/
virtual int getArg1() = 0;
/
* 获取扩展参数2。
*/
virtual int getArg2() = 0;
/
* 获取描述信息。返回的指针不可外部delete或者free。
*/
virtual const char* getInfo() = 0;
/
* 获取附带数据。返回的内存不可外部delete或者free。
*/
virtual IDataBundle* getData() = 0;
};

AIUI定义了多种IAIUIEvent,有不同eventType。当IAIUIEvent取不同的eventType时,其余字段有不同的定义,详细定义请见AIUIEvent的定义说明。

IAIUIMessage

IAIUIAgent中sendMessage方法用于向AIUIService发送AIUI消息。消息类型是IAIUIMessage

IAIUIMessage定义如下:

/
* AIUI消息类。AIUI所有的输入都是通过消息发送到SDK内部。
*/
class IAIUIMessage
{
public:
AIUIEXPORT virtual ~IAIUIMessage();
/
* 创建消息对象。
*
* @param msgType 消息类型,参见AIUIConstant中CMD_开头的常量定义
* @param arg1 扩展参数1
* @param arg2 扩展参数2
* @param params 业务参数,传入后内部会做拷贝
* @param data 附带数据,Message在SDK内部处理后会自动释放, 不需要外部释放。
*
* @return IAIUIMessage 对象指针
*/
AIUIEXPORT static IAIUIMessage* create(
int msgType ,
int arg1 = 0,
int arg2 = 0,
const char* params = "",
Buffer* data = 0);
/
* 获取消息类型。类型取值参见AIUIConstant中CMD_开头的常量定义。
*/
virtual int getMsgType() = 0;
/
* 获取扩展参数1。
*/
virtual int getArg1() = 0;
/
* 获取扩展参数2。
*/
virtual int getArg2() = 0;
/
* 获取业务参数。
*/
virtual const char* getParams() = 0;
/
* 获取附带数据。
*/
virtual Buffer* getData() = 0;
/
* 释放附带数据
*/
virtual void releaseData() = 0;
/
* 销毁消息对象本身。注意:不会释放Buffer* data。
*/
virtual void destroy() = 0;
};

AIUI定义了多种IAIUIMessage,有不同的msgType。当IAIUIMessage取不同的msgType时,其他成员有不同的定义,详细定义解释请见AIUIMessage的定义说明。

注意事项

iOS中命名与android中的命名类似,稍有不同,一般加前缀“I”表示接口,如,“AIUIMessage”在android中为AIUIMessage,在iOS中为IAIUIMessage,使用时请注意比较区分。

1.3.2 调用流程

AIUIService的一般调用流程如下:

// 先实现一个监听器
class TestListener : public IAIUIListener
{
public:
void onEvent(IAIUIEvent& event);
};
void TestListener::onEvent(IAIUIEvent& event)
{
NSLog(@"%s",__func__);
switch (event.getEventType()) {
case AIUIConstant::EVENT_STATE:
break;
//唤醒事件
case AIUIConstant::EVENT_WAKEUP:
break;
//休眠事件
case AIUIConstant::EVENT_SLEEP:
break;
//录音前、后端点、音量
case AIUIConstant::EVENT_VAD:
break;
//结果事件
case AIUIConstant::EVENT_RESULT:
break;
//错误事件
case AIUIConstant::EVENT_ERROR:
break;
case AIUIConstant::EVENT_CMD_RETURN:
default:
break;
}
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachePath = [paths objectAtIndex:0];
cachePath = [cachePath stringByAppendingString:@"/"];
NSLog(@"cachePath=%@",cachePath);
AIUISetting::setSaveDataLog(true);
AIUISetting::setLogLevel(info);
AIUISetting::initLogger([cachePath UTF8String]);
//set the configuration file path
NSString *appPath = [[NSBundle mainBundle] resourcePath];
NSString *cfgFilePath = [[NSString alloc] initWithFormat:@"%@/aiui.cfg",appPath];
NSString *cfg = [NSString stringWithContentsOfFile:cfgFilePath encoding:NSUTF8StringEncoding error:nil];
//set the resource path for module VAD
NSString *vadFilePath = [[NSString alloc] initWithFormat:@"%@/meta_vad_16k.jet",appPath];
//set correct resource path for module VAD in aiui configuration file
NSString *cfgString = [cfg stringByReplacingOccurrencesOfString:@"vad_res_path" withString:vadFilePath];
const char *cfgBuffer = [cfgString UTF8String];
m_angent = IAIUIAgent::createAgent(cfgBuffer, &m_listener);
//开始AIUI
if (NULL != m_angent)
{
IAIUIMessage * wakeupMsg = IAIUIMessage::create(AIUIConstant::CMD_WAKEUP);
m_angent->sendMessage(wakeupMsg);
wakeupMsg->destroy();
}

1.4 Windows

1.4.1 接口说明

IAIUIAgent
aiui.dll中用于与AIUI业务交互的接口类为IAIUIAgent
IAIUIAgent提供如下接口:

/
* AIUI代理类,单例对象,应用通过代理与AIUI交互。
*/
class IAIUIAgent
{
public:
AIUIEXPORT virtual ~IAIUIAgent();
/
* 创建Agent单例对象,AIUI开始工作。
* 注:该方法总是返回非空对象,非空并不代表创建过程中无错误发生。
*
* @param params 参数设置
* @param listener 事件监听器
* @return AIUIAgent单例对象指针
*/
AIUIEXPORT static IAIUIAgent* createAgent(const char* params, IAIUIListener* listener);
/
* 发送消息给AIUI,消息中可以包含命令、参数和数据,具体格式参见IAIUIMessage。
*
* @param msg AIUI消息
* message 如果指定了非空的Buffer *data, 在Message在内部处理后会自动release()这部分data;
* 而不能外部去释放掉。
*/
virtual void sendMessage(IAIUIMessage* message) = 0;
/
* 销毁AIUIAgent对象,AIUI停止工作。
*/
virtual void destroy() = 0;
};

cfg内容参见AIUI配置文件

IAIUIListener

创建IAIUIAgent时传递的参数IAIUIListener是用于接受AIUIService抛出事件的监听器。
IAIUIListener定义如下:

typedef AIUIListener IAIUIListener;

/
* AIUI事件监听接口。SDK所有输出都通过回调onEvent方法抛出。
*/
class AIUIListener
{
public:
AIUIEXPORT virtual ~AIUIListener();
/
* 事件回调,SDK所有输出都通过event抛出。
*
* @param event AIUI事件
*/
virtual void onEvent(IAIUIEvent& event) = 0;
};

IAIUIEvent

IAIUIListener中监听的抛出事件的类型是IAIUIEvent

IAIUIEvent定义如下:

/
* AIUI事件类。业务结果、SDK内部状态变化等输出信息都通过事件抛出。SDK通过回调抛出事件后会
* 立即释放事件中的内存对象,若要在别处使用到这些内存对象,开发者需要在回调中做拷贝。
*/
class IAIUIEvent
{
public:
AIUIEXPORT virtual ~IAIUIEvent();
/
* 获取事件类型。取值参见AIUIConstant中EVENT_开头的常量定义。
*/
virtual int getEventType() = 0;
/
* 获取扩展参数1。
*/
virtual int getArg1() = 0;
/
* 获取扩展参数2。
*/
virtual int getArg2() = 0;
/
* 获取描述信息。返回的指针不可外部delete或者free。
*/
virtual const char* getInfo() = 0;
/
* 获取附带数据。返回的内存不可外部delete或者free。
*/
virtual IDataBundle* getData() = 0;
};

IAIUIMessage

IAIUIAgent中sendMessage方法用于向AIUIService发送AIUI消息。消息类型是IAIUIMessage

IAIUIMessage定义如下:

/
* AIUI消息类。AIUI所有的输入都是通过消息发送到SDK内部。
*/
class IAIUIMessage
{
public:
AIUIEXPORT virtual ~IAIUIMessage();
/
* 创建消息对象。
*
* @param msgType 消息类型,参见AIUIConstant中CMD_开头的常量定义
* @param arg1 扩展参数1
* @param arg2 扩展参数2
* @param params 业务参数,传入后内部会做拷贝
* @param data 附带数据,Message在SDK内部处理后会自动释放, 不需要外部释放。
*
* @return IAIUIMessage 对象指针
*/
AIUIEXPORT static IAIUIMessage* create(
int msgType ,
int arg1 = 0,
int arg2 = 0,
const char* params = "",
Buffer* data = 0);
/
* 获取消息类型。类型取值参见AIUIConstant中CMD_开头的常量定义。
*/
virtual int getMsgType() = 0;
/
* 获取扩展参数1。
*/
virtual int getArg1() = 0;
/
* 获取扩展参数2。
*/
virtual int getArg2() = 0;
/
* 获取业务参数。
*/
virtual const char* getParams() = 0;
/
* 获取附带数据。
*/
virtual Buffer* getData() = 0;
/
* 释放附带数据
*/
virtual void releaseData() = 0;
/
* 销毁消息对象本身。注意:不会释放Buffer* data。
*/
virtual void destroy() = 0;
};

AIUI定义了多种IAIUIEvent,有不同eventType。当IAIUIEvent取不同的eventType时,其余字段有不同的定义,详细定义请见AIUIEvent的定义说明。

1.4.2 调用流程

AIUI 接口简单易用,调用示例如下:

1.首先实现IAIUIListener监听器接口类,在onEvent回调中处理AIUI服务抛出的各种事件。

class TestListener : public IAIUIListener
{
public:
~TestListener() {}
void onEvent(IAIUIEvent& event);
};
void TestListener::onEvent(IAIUIEvent& event)
{
switch (event.getEventType()) {
case AIUIConstant::EVENT_STATE:
{
switch (event.getArg1()) {
case AIUIConstant::STATE_IDLE:
{
cout << "EVENT_STATE:" << "IDLE" << endl;
} break;
case AIUIConstant::STATE_READY:
{
cout << "EVENT_STATE:" << "READY" << endl;
} break;
case AIUIConstant::STATE_WORKING:
{
cout << "EVENT_STATE:" << "WORKING" << endl;
} break;
}
} break;
case AIUIConstant::EVENT_WAKEUP:
{
cout << "EVENT_WAKEUP:" << event.getInfo() << endl;
} break;
case AIUIConstant::EVENT_SLEEP:
{
cout << "EVENT_SLEEP:arg1=" << event.getArg1() << endl;
} break;
case AIUIConstant::EVENT_VAD:
{
switch (event.getArg1()) {
case AIUIConstant::VAD_BOS:
{
cout << "EVENT_VAD:" << "BOS" << endl;
} break;
case AIUIConstant::VAD_EOS:
{
cout << "EVENT_VAD:" << "EOS" << endl;
} break;
case AIUIConstant::VAD_VOL:
{
//cout << "EVENT_VAD:" << "VOL" << endl;
} break;
}
} break;
case AIUIConstant::EVENT_RESULT:
{
using namespace VA;
Json::Value bizParamJson;
Json::Reader reader;
if (!reader.parse(event.getInfo(), bizParamJson, false)) {
cout << "parse error!" << endl << event.getInfo() << endl;
break;
}
Json::Value data = (bizParamJson["data"])[0];
Json::Value params = data["params"];
Json::Value content = (data["content"])[0];
string sub = params["sub"].asString();
cout << "EVENT_RESULT:" << sub << endl;
if (sub == "nlp")
{
Json::Value empty;
Json::Value contentId = content.get("cnt_id", empty);
if (contentId.empty())
{
cout << "Content Id is empty" << endl;
break;
}
string cnt_id = contentId.asString();
Buffer* buffer = event.getData()->getBinary(cnt_id.c_str());
string resultStr;
if (NULL != buffer)
{
resultStr = string((char*)buffer->data());
cout << resultStr << endl;
}
}
} break;
case AIUIConstant::EVENT_ERROR:
{
cout << "EVENT_ERROR:" << event.getArg1() << endl;
} break;
case AIUIConstant::EVENT_CMD_RETURN:
{
cout << "EVENT_CMD_RETURN: CMD " << event.getArg1() << ",Return code:"<< event.getArg2() <<", Info:"<< event.getInfo() << endl;
} break;
}
}

2.登录鉴权,创建ISpeechUtility实例,传入appid 等参数。appid是www.xfyun.cn上申请获得。

ISpeechUtility::createSingleInstance("", "", "appid=xxxxx ");

3.创建IAIUIAgent的对象,传入应用上下文、IAIUIListener监听器。

agent = IAIUIAgent::createAgent(paramStr.c_str(), &listener);

4.向AIUI服务发送各种消息,以msgType字段区分类型,可携带参数和数据。如:

IAIUIMessage * wakeupMsg = IAIUIMessage::create(AIUIConstant::CMD_WAKEUP);
agent->sendMessage(wakeupMsg);
wakeupMsg->destroy();

5.当不再使用AIUI服务时,销毁IAIUIAgent对象。

agent->destroy();
agent = NULL;
如果进程退出,注销服务,调用ISpeechUtility::destroy()
ISpeechUtility::getInstance()->destroy();

1.5 Linux

1.5.1 接口说明

IAIUIAgent
aiui.so中用于与AIUI业务交互的接口类为IAIUIAgent
IAIUIAgent提供如下接口:

/
AIUI代理,单例对象,应用通过代理与AIUI交互。
*/
class IAIUIAgent
{
public:
AIUIEXPORT virtual ~IAIUIAgent();
/
* 创建Agent单例对象,AIUI开始工作。
* 注:该方法总是返回非空对象,非空并不代表创建过程中无错误发生。
*
* @param params 参数设置
* @param listener 监听器
* @return AIUIAgent单例对象
*/
AIUIEXPORT static IAIUIAgent* createAgent(const char* params, IAIUIListener* listener);
/
* 发送消息给AIUI,消息中可以包含命令、参数和数据,具体格式参见AIUIMessage。
*
* @param msg AIUI消息
* message 如果指定了非空的Buffer *data, 在Message在内部处理后会自动release()这部分data;
* 而不能外部去释放掉。
*/
virtual void sendMessage(IAIUIMessage* message) = 0;
/
* 销毁AIUIAgent对象,AIUI停止工作。
*/
virtual void destroy() = 0;
}

cfg内容参见AIUI配置文件

IAIUIListener

创建IAIUIAgent时传递的参数IAIUIListener是用于接受AIUIService抛出事件的监听器。
IAIUIListener定义如下:

/
* AIUI监听接口。需要使用者实现
*/
class AIUIListener
{
public:
AIUIEXPORT virtual ~AIUIListener();
/
* 事件回调,SDK所有输出都通过event抛出。
*
* @param event AIUI事件
*/
virtual void onEvent( IAIUIEvent& event) = 0;
};
typedef AIUIListener IAIUIListener;

IAIUIEvent

IAIUIListener中监听的抛出事件的类型是IAIUIEvent

IAIUIEvent定义如下:

/
* AIUI事件类,业务结果、SDK内部状态变化等都通过事件抛出。
* 回调后事件内存即可能立即释放。如需留用,做拷贝。
*/
class IAIUIEvent
{
public:
AIUIEXPORT virtual ~IAIUIEvent();
/
* 事件类型,具体取值参见AIUIConstant。
*/
virtual int getEventType() = 0;
/
* 扩展参数1。
*/
virtual int getArg1() = 0;
/
* 扩展参数2。
*/
virtual int getArg2() = 0;
/
* 描述信息。
* 返回的内存不可外部直接 delete。
*/
virtual const char* getInfo() = 0;
/
* 附带数据。
* 返回的内存不可外部直接 delete。
*/
virtual IDataBundle* getData() = 0;
};

IAIUIMessage

IAIUIAgent中sendMessage方法用于向AIUIService发送AIUI消息。消息类型是IAIUIMessage

IAIUIMessage定义如下:

class IAIUIMessage
{
public:
AIUIEXPORT virtual ~IAIUIMessage();
/
* 创建消息对象
* @param msgType 消息类型 参见AIUIConstant::CMD_开头的定义
* @param arg1 参数1 参见http://www.xfyun.cn/中AIUI的技术文档
* @param arg2 参数2 参见http://www.xfyun.cn/中AIUI的技术文档
* @param params 业务参数。 传入后内部会做copy。取值参见http://www.xfyun.cn/中AIUI的技术文档
* @param data 业务数据。不会做拷贝. 参见http://www.xfyun.cn/中AIUI的技术文档
* 在Message在内部处理后会自动release, 不能在外部释放掉。
* @return IAIUIMessage对象指针
*/
AIUIEXPORT static IAIUIMessage* create(
int msgType ,
int arg1 = 0,
int arg2 = 0,
const char* params = "",
Buffer* data = 0);
/
* 消息类型,具体取值参见AIUIConstant。
*/
virtual int getMsgType() = 0;
/
* 扩展参数1。
*/
virtual int getArg1() = 0;
/
* 扩展参数2。
*/
virtual int getArg2() = 0;
/
* 业务参数。
*/
virtual const char* getParams() = 0;
/
* 附带数据。
*/
virtual Buffer* getData() = 0;
/
* 释放附带数据
*/
virtual void releaseData() = 0;
/
* 仅销毁自身,注意不会释放Buffer* data;
*/
virtual void destroy() = 0;
};

AIUI定义了多种IAIUIEvent,有不同eventType。当IAIUIEvent取不同的eventType时,其余字段有不同的定义,详细定义请见AIUIEvent的定义说明。

1.5.2 调用流程

AIUI 接口简单易用,调用示例如下:

1. 首先实现IAIUIListener监听器接口类,在onEvent回调中处理AIUI服务抛出的各种事件。

class TestListener : public IAIUIListener
{
public:
void onEvent(IAIUIEvent& event);
};
void TestListener::onEvent(IAIUIEvent& event)
{
switch (event.getEventType()) {
case AIUIConstant::EVENT_STATE:
{
switch (event.getArg1()) {
case AIUIConstant::STATE_IDLE:
{
cout << "EVENT_STATE:" << "IDLE" << endl;
} break;
case AIUIConstant::STATE_READY:
{
cout << "EVENT_STATE:" << "READY" << endl;
} break;
case AIUIConstant::STATE_WORKING:
{
cout << "EVENT_STATE:" << "WORKING" << endl;
} break;
}
} break;
case AIUIConstant::EVENT_WAKEUP:
{
cout << "EVENT_WAKEUP:" << event.getInfo() << endl;
} break;
case AIUIConstant::EVENT_SLEEP:
{
cout << "EVENT_SLEEP:arg1=" << event.getArg1() << endl;
} break;
case AIUIConstant::EVENT_VAD:
{
switch (event.getArg1()) {
case AIUIConstant::VAD_BOS:
{
cout << "EVENT_VAD:" << "BOS" << endl;
} break;
case AIUIConstant::VAD_EOS:
{
cout << "EVENT_VAD:" << "EOS" << endl;
} break;
case AIUIConstant::VAD_VOL:
{
//cout << "EVENT_VAD:" << "VOL" << endl;
} break;
}
} break;
case AIUIConstant::EVENT_RESULT:
{
using namespace VA;
Json::Value bizParamJson;
Json::Reader reader;
if (!reader.parse(event.getInfo(), bizParamJson, false)) {
cout << "parse error!" << endl << event.getInfo() << endl;
break;
}
Json::Value data = (bizParamJson["data"])[0];
Json::Value params = data["params"];
Json::Value content = (data["content"])[0];
string sub = params["sub"].asString();
cout << "EVENT_RESULT:" << sub << endl;
if (sub == "nlp")
{
Json::Value empty;
Json::Value contentId = content.get("cnt_id", empty);
if (contentId.empty())
{
cout << "Content Id is empty" << endl;
break;
}
string cnt_id = contentId.asString();
Buffer* buffer = event.getData()->getBinary(cnt_id.c_str());
string resultStr;
if (NULL != buffer)
{
resultStr = string((char*)buffer->data());
cout << resultStr << endl;
}
}
}
break;
case AIUIConstant::EVENT_ERROR:
{
cout << "EVENT_ERROR:" << event.getArg1() << endl;
} break;
}
}

2. 登录鉴权,创建ISpeechUtility实例,传入appid 等参数。appid是www.xfyun.cn上申请获得。

ISpeechUtility::createSingleInstance("", "", "appid=xxxxx ");

3. 创建IAIUIAgent的对象,传入应用上下文、IAIUIListener监听器。

agent = IAIUIAgent::createAgent(paramStr.c_str(), &listener);

4. 向AIUI服务发送各种消息,以msgType字段区分类型,可携带参数和数据。如:

IAIUIMessage * wakeupMsg = IAIUIMessage::create(AIUIConstant::CMD_WAKEUP);
agent->sendMessage(wakeupMsg);
wakeupMsg->destroy();

5. 当不再使用AIUI服务时,销毁IAIUIAgent对象。

agent->destroy();
agent = NULL;
如果进程退出,注销服务,调用ISpeechUtility::destroy()
ISpeechUtility::getInstance()->destroy();

2 功能特性

AIUI的交互类似一个IO系统,I(Input)就是发送给AIUI的AIUIMessage, O(Output)就是AIUI抛出来的AIUIEvent。开发者通过集成AIUI SDK, 发送AIUIMessage、接收AIUIEvent。 除了AIUIMessage和AIUIEvent控制使用AIUI的功能外,还可以通过AIUI配置文件不同字段配置控制AIUI的功能。 通过AIUI配置文件和AIUIMessage的组合配置使用,可以使用AIUI提供的不同功能点。 下面将详细介绍。

2.1 AIUI配置

配置文件示例

AIUI的配置内容格式是json,配置了AIUI运行时各方面的参数:

/* AIUI Mobile版本参数配置 */
{
	/* 交互参数 */
	"interact":{
		"interact_timeout":"60000",
		"result_timeout":"5000"
	},

	/* 全局设置 */
	"global":{
		"scene":"main",
		"clean_dialog_history":"auto"
	},

	/* 业务相关参数 */
	// 本地vad参数
	"vad":{
		"vad_enable":"1",
		"engine_type":"meta",
		"res_type":"assets",
		"res_path":"vad/meta_vad_16k.jet"
	},

	// 识别(音频输入)参数
	"iat":{
		"sample_rate":"16000"
	},

	/* 业务流程相关参数 */
	// 语音业务流程控制
	"speech":{
		"data_source":"sdk"
	}
}
配置字段说明

对于各个字段的解释如下:

参数类型 参数名称
login 语音云登录参数 appid
在讯飞开放平台上注册的8位应用唯一标识。

global 全局参数设置 scene
用户定制的场景参数,不同的场景可对应不同的云端处理流程。

clean_dialog_history
清除交互历史设置

● auto 自动清除历史(默认模式)

● user 用户手动清除历史

interact 交互参数 interact_timeout
交互超时(单位:ms)
即唤醒之后,如果在这段时间内无有效交互
则重新进入待唤醒状态,取值:[10000,180000)
默认为1min。

result_timeout
结果超时(单位:ms)
即检测到语音后端点后一段时间内
无结果返回则抛出结果等待超时
默认值:5000。

speech 业务相关参数 data_source
录音数据来源配置

● sdk sdk内部录音

● user 外部录音

interact_mode
交互模式设置
  • continuous(默认模式)
  • 持续交互,对于语音即“一次唤醒,多次交互”
  • oneshot
  • 一次交互,对于语音即“一次唤醒,一次交互”。
oneshot举例:

问:叮咚叮咚,给我唱首歌 //说完后AIUI即进入休眠状态

答:请欣赏xxxx

后续AIUI因已休眠不能继续交互,需重新唤醒才能继续交互

vad 音频端点检测参数 engine_type
vad引擎类型
取值:meta(模型vad)
默认值:meta。

res_type
资源类型
使用模型vad时必须设置,取值:

● assets资源(apk工程的assets文件)

● res资源(apk工程的res文件)

● path资源(sdcard文件)

res_path
资源文件路径
使用模型vad时必须设置。

vad_bos
VAD前端超时时间
单位:毫秒 示例 “5000”

vad_eos
VAD后端超时时间
单位:毫秒 示例 “1000”

audioparams 音频参数设置 msc.lng
经度
示例:117.16334474130745

msc.lat
纬度
示例:31.821021912318592

log 日志相关参数 debug_log
Debug日志开关
取值:1(打开),0(关闭),默认值:0。
日志打开时会向logcat打印调试日志。

save_datalog
是否保存数据日志
取值:1(打开),0(关闭),默认值:0。
打开之后会将所有上传到云端的音频和云端返回的结果保存到本地

datalog_path
数据日志的保存路径
当不设置或者为空值时,使用默认值:“/sdcard/AIUI/data/”

datalog_size
数据日志的大小限制(单位:MB)
取值:[-1,+∞)
默认值:-1(表示无大小限制)。
注意:设置成-1可能会造成SD卡被日志写满,从而导致AIUI
Service性能下降,影响体验效果。

2.2 Msg&Event

2.2.1 AIUIMessage

msgType定义

注意: CMD_WAKEUP是用于手动唤醒,不能用于频繁的唤醒以延长交互时间,否则我们会停止AIUI的服务。

msgType(消息类型) 取值 返回 说明
CMD_GET_STATE 1
获取服务状态
CMD_RESET 4
重置AIUI服务的状态
服务会立即停止并重新启动,进入到待唤醒状态。

CMD_START 5
启动AIUI服务
当AIUI服务停止后,使用此命令启动服务。

CMD_STOP 6
停止AIUI服务
服务停止之后,将不响应外部输入。

CMD_WAKEUP 7
唤醒消息
用于手动唤醒AIUI服务

CMD_RESET_WAKEUP 8
重置唤醒状态
AIUI服务重置为待唤醒状态。若当前为唤醒状态,
发送该消息重置后会抛出EVENT_SLEEP事件。

CMD_SET_PARAMS 10
设置参数配置
用params携带参数设置JSON字符串,
具体格式参照aiui.cfg文件
暂时可以用如下参数,实时生效
  • global
  • speech

示例:

{"global":{"scene":main"}}
CMD_UPLOAD_LEXICON 11
上传用户识别热词

AIUI的识别热词,可以让AIUI在识别时优先识别成热词中的内容。比如用户说`yàn jīng pí jiǔ`,在没有上传热词的情况下很大概率会被通用模型识别成`眼睛啤酒`,但是当开发者上传了`燕京啤酒`的热词,则识别成功率会显著提升。 AIUI热词分为两种,一种是用户级别热词,通过CMD_UPLOAD_LEXICON上传, 仅对上传该热词的设备生效。 一种是应用热词,通过AIUI后台应用管理界面中上传,对使用APPID配置的所有设备生效。 两种类型热词共同生效,互相不会覆盖,同类型热词第二次上传会覆盖生效。 无论是哪种热词,热词的生效时间为10~60分钟。

CMD_SEND_LOG 12
发送应用日志到云端,可以帮助分析应用问题
需要将JSON格式的字符串放在params字段中携带。

CMD_SYNC 13
上传同步资源数据
arg1表示同步的数据类型
data表示同步数据的内容

CMD_RESULT_VALIDATION_ACK 20
结果确认
在接收到语义、听写、后处理的结果后5s内可发送该指令对结果进行确认,
AIUI会认为该条结果有效,并重新开始AIUI交互超时的计时
关于交互超时的机制参看AIUI配置interact_timeout的解释

CMD_CLEAN_DIALOG_HISTORY 21
清空交互历史

CMD_QUERY_SYNC_STATUS 24
查询数据同步状态
arg1表示状态查询的类型
params包含查询条件

注:有返回的含义是在向 AIUI 发送一条 CMD 消息后,AIUI会抛出一个对应的EVENT_CMD_RETURN事件返回 CMD 消息的处理结果

2.2.2 AIUIEvent

定义

eventType(事件类型) 取值 说明
EVENT_RESULT 1
结果事件
data字段携带结果数据,info字段为描述数据的JSON字符串。

EVENT_ERROR 2
出错事件
arg1字段为错误码,info字段为错误描述信息。

EVENT_STATE 3
服务状态事件

EVENT_WAKEUP 4
唤醒事件

EVENT_SLEEP 5
休眠事件
当出现交互超时,服务会进入休眠状态(待唤醒),
或者发送了CMD_RESET_WAKEUP时,抛出该事件。
arg1字段取值:
0 => TYPE_AUTO(自动休眠,即交互超时)、
1 => TYPE_COMPEL (外部强制休眠,即发送CMD_RESET_WAKEUP)。

EVENT_VAD 6
VAD事件
当检测到输入音频的前端点后,会抛出该事件,
用arg1标识前后端点或者音量信息:0(前端点)、1(音量)、2(后端点)。
当arg1取值为1时,arg2为音量大小。

EVENT_CMD_RETURN 8
某条CMD命令对应的返回事件
对于除CMD_GET_STATE外的有返回的命令,都会返回该事件,
用arg1标识对应的CMD命令,arg2为返回值,0表示成功,
info字段为描述信息。

2.3 AIUI状态

2.3.1 Msg&Event

Message
msgType(消息类型) 取值 返回 说明
CMD_GET_STATE 1
获取服务状态

CMD_RESET 4
重置AIUI服务的状态
服务会立即停止并重新启动,进入到待唤醒状态。

CMD_START 5
启动AIUI服务
当AIUI服务停止后,使用此命令启动服务。

CMD_STOP 6
停止AIUI服务
服务停止之后,将不响应外部输入。

CMD_WAKEUP 7
唤醒消息
用于手动唤醒AIUI服务

CMD_RESET_WAKEUP 8
重置唤醒状态
AIUI服务重置为待唤醒状态。若当前为唤醒状态,
发送该消息重置后会抛出EVENT_SLEEP事件。


Event
EVENT_STATE 3
服务状态事件
当向AIUI发送CMD_GET_STATE命令时抛出该事件,
arg1字段取值为:
1 => STATE_IDLE(空闲状态)、
2 => STATE_READY(就绪状态,待唤醒)、
3 => STATE_WORKING(工作状态,已唤醒)状态之一。

EVENT_WAKEUP 4
唤醒事件
AIUI配置

EVENT_SLEEP 5
休眠事件
当出现交互超时,服务会进入休眠状态(待唤醒),
或者发送了CMD_RESET_WAKEUP时,抛出该事件。
arg1字段取值:
0 => TYPE_AUTO(自动休眠,即交互超时)、
1 => TYPE_COMPEL (外部强制休眠,即发送CMD_RESET_WAKEUP)。

2.3.2 状态转换

AIUI内部具有三种工作状态:STATE_IDLE(空闲)、STATE_READY(就绪)和STATE_WORKING(工作),AIUI只有在唤醒状态下才能进行录音交互 状态转换关系如下:

状态名称 说明
STATE_IDLE
服务未开启
此时只能进行start(开启服务)操作。

STATE_READY
就绪,等待用户唤醒状态
向服务发送CMD_WAKEUP消息唤醒服务。
调用AIUIAgent.createAgent创建对象之后,服务即为就绪状态。

STATE_WORKING
唤醒后,服务进入工作状态
此时可以输入语音、文本与AIUI后台进行交互。

操作名称 说明
start
启动后默认状态或者向SDK发送CMD_START消息。
stop
向SDK发送CMD_STOP消息。
wakeup
向SDK发送CMD_WAKEUP消息。
reset_wakeup
向SDK发送CMD_RESET_WAKEUP消息。
sleep
休眠,当一段时间内无有效交互(语义)发生
re_wakeup
在STATE_WORKING状态下,向SDK发送CMD_WAKEUP消息。

2.3.3 状态查询

通过构造CMD_GET_STATE查询消息发送给AIUI,AIUI会返通过EVENT_STATE事件将当前状态返回, EVENT_STATE事件的arg1参数表示状态值有如下取值:

  • 1 => STATE_IDLE(空闲状态)、
  • 2 => STATE_READY(就绪状态,待唤醒)、
  • 3 => STATE_WORKING(工作状态,已唤醒)状态之一。

2.3.4 打开和关闭

通过CMD_STARTCMD_STOP控制AIUI启动和停止。

AIUI在停止状态下没有任何操作,此时功耗也是最低, 停止状态下不能唤醒,需要通过CMD_START进入就绪状态才能唤醒。

CMD_RESET用于重置服务,用于在出现致命错误无法恢复或者重新读取配置文件等场合。

2.3.5 唤醒和休眠

AIUI处于休眠状态时,通过向SDK发送CMD_WAKEUP消息,让AIUI进入唤醒工作状态。

在进入工作状态后,可以通过语音或文本进行交互,但是如果连续一段时间(配置文件interact_timeout可配置) 无有效交互就会进入就绪休眠状态。也可以通过手动发送CMD_RESET_WAKEUP进入休眠状态。

上面两种休眠方式都会对外抛出EVENT_SLEEP事件表示AIUI已进入休眠状态,arg1字段表明进入休眠的方式。

  • 0 => TYPE_AUTO(自动休眠,即交互超时)、
  • 1 => TYPE_COMPEL (外部强制休眠,即发送CMD_RESET_WAKEUP)。

2.3.6 唤醒结果

AIUI进入唤醒状态后,对应的唤醒事件通过EVENT_WAKEUP类型消息抛出。

2.4 录音处理

2.4.1 Msg&Event

cfg

"speech": {
"data_source": "sdk",
},

Message

CMD_WRITE 2
向AIUI写入数据

CMD_STOP_WRITE 3
停止写入数据

CMD_START_RECORD 22
开始录制数据

CMD_STOP_RECORD 23
停止录制数据

Event

eventType(事件类型) 取值 说明
EVENT_START_RECORD 11
抛出该事件通知外部录音开始,用户可以开始说话
EVENT_STOP_RECORD 12
通知外部录音开始

2.4.2 录音来源

通过data_source指定AIUI录音来源,值为sdk时使用AIUI内部录音,通过CMD_START_RECORDCMD_STOP_RECORD进行控制。另一取值user,表示由 外部写入录音数据,通过CMD_WRITECMD_STOP_WRITE通知AIUI数据写入和写入结束。

data_source取值为sdk,仅在Android平台SDK下可用,其他平台只能取值user,通过外部输入音频数据。

2.4.3 开始停止录音

使用CMD_START_RECORDCMD_STOP_RECORD控制录音开始和停止,当录音开始或结束时会抛出 EVENT_START_RECORDEVENT_STOP_RECORD事件通知。

注:params参数传data_type=audio

2.4.4 数据写入

通过`CMD_WRITE`向AIUI写入数据,params字段中指定数据类型、采样率等描述信息,例如:”data_type=audio,sample_rate=16000”。 data字段为待写入的二进制数据(如音频、图像、文本等)。 params支持的描述字段如下:

参数名称 说明
data_type
数据类型,取值:
audio(音频)、text(文本)、image(图像,暂不支持)。

sample_rate
数据采样率,
audio数据采样取值:16000(单通道)。

msc.lng和msc.lat
GPS经纬度信息。
当使用weather等需要位置信息的语义服务时可以传GPS坐标定位,
在具有GPS模块的Android设备上可以不传。

rec_user_data
识别用的用户私有数据,用于增强特定词语的识别效果。
示例:rec_user_data=”{“recHotWords”: “播报内容|地图显示|
路径优先”, “sceneInfo”: {}}”。

在指定为外部录音后,通过构造CMD_WRITE写入音频,params字段中 必须指定data_type为audio,sample_rate指定写入音频采样率。

除了可以写入音频外,也可以写入文本数据,data_type指定为text。写入的文本会直接作为语义的输入,影响交互 的语义上下文,并且如正常交互一样,返回对应的语义结果。

代码示例:

//写入音频
byte[] audio = xxx; //初始化
String params = "data_type=audio,sample_rate=16000";
AIUIMessage msg = new AIUIMessage(AIUIConstant.CMD_WRITE, 0, 0, params, audio);
mAIUIAgent.sendMessage(msg);
//写入文本
byte[] content= "确定预定".getBytes();
String params = "data_type=text";
AIUIMessage msg = new AIUIMessage(AIUIConstant.CMD_WRITE, 0, 0, params, content);
mAIUIAgent.sendMessage(msg);

2.5 结果解析

2.5.1 Msg&Event

Event

eventType(事件类型) 取值 说明
EVENT_RESULT 1
结果事件
data字段携带结果数据,info字段为描述数据的JSON字符串。

2.5.2 AIUI结果格式

AIUI交互结果中除了唤醒结果其他所有结果都通过EVENT_RESULT事件抛出,包括:

  • ● 听写结果(iat)
  • ● 语义结果(nlp)
  • ● 后处理服务结果(tpp)
    EVENT_RESULT的info字段中json包容如下格式的内容:
{
"data": [{
"params": {
"sub": "iat",
},
"content": [{
"dte": "utf8",
"dtf": "json",
"cnt_id": "0"
}]
}]
}

通过sub字段的值确定对应的结果类型,如果EVENT_RESULT包含的是语义结果, 那info数据描述的中sub的值就对应为nlp

EVENT_RESULT的data中包含结果的数据,需要根据info描述信息获取,不同SDK获取的方式有差异:

AIUIEvent定义中,data的类型为Bundle,获取结果数据的示例代码如下:

private void processResult(AIUIEvent event) {
JSONObject data = new JSONObject(event.info).getJSONArray("data").getJSONObject(0);
String sub = data.getJSONObject("params").optString("sub");
JSONObject content = data.getJSONArray("content").getJSONObject(0);
if (content.has("cnt_id")) {
String cnt_id = content.getString("cnt_id");
JSONObject result = new JSONObject(new String(event.data.getByteArray(cnt_id), "utf-8"));
}
}

2.5.3听写结果格式

举例如下:

{
"text": {
"bg": 0,
"sn": 1,
"ws": [{
"bg": 0,
"cw": [{
"w": "叫",
"sc": 0
}]
},
{
"bg": 0,
"cw": [{
"w": "什么",
"sc": 0
}]
},
{
"bg": 0,
"cw": [{
"w": "名字",
"sc": 0
}]
}],
"ls": false,
"ed": 0
}
}

听写结果说明

JSON字段 英文全称 类型 说明
sn sentence number 第几句
ls last sentence boolean 是否最后一句
bg begin number 开始
ed end number 结束
ws words array
cw chinese word array 中文分词
w word string 单字
sc score number 分数

2.5.4 后处理服务结果

后处理结果由开发者配置的后处理服务构造。

2.6 交互控制

2.6.1 Config&Msg&Event

Config

"interact":{
/* 交互参数 */
"interact_timeout":"60000",
"result_timeout":"5000"
},
"global":{
/* 交互历史清除方式 */
"clean_dialog_history":"auto"
}

Message

msgType(消息类型) 取值 返回 说明
CMD_UPLOAD_LEXICON 11
上传用户识别热词

AIUI的识别热词,可以让AIUI在识别时优先识别成热词中的内容。比如用户说`yàn jīng pí jiǔ`,在没有上传热词的情况下很大概率会被通用模型识别成`眼睛啤酒`,但是当开发者上传了`燕京啤酒`的热词,则识别成功率会显著提升。 AIUI热词分为两种,一种是用户级别热词,通过CMD_UPLOAD_LEXICON上传, 仅对上传该热词的设备生效。 一种是应用热词,通过AIUI后台应用管理界面中上传,对使用APPID配置的所有设备生效。 两种类型热词共同生效,互相不会覆盖,同类型热词第二次上传会覆盖生效。 无论是哪种热词,热词的生效时间为10~60分钟。

CMD_RESULT_VALIDATION_ACK 20
结果确认
在接收到语义、听写、后处理的结果后5s内可发送该指令对结果进行确认,
AIUI会认为该条结果有效,并重新开始AIUI交互超时的计时
关于交互超时的机制参看AIUI配置中interact_timeout的解释
CMD_CLEAN_DIALOG_HISTORY 21
清空交互历史

2.6.2 上传用户热词

通过CMD_UPLOAD_LEXICON上传热词,用户词表按格式组成JSON字符串, 放在params字段传入SDK。

具体格式:

{
"name":"userword",
"content":"XXXX"
}

其中XXXX也为一个JSON字符串,示例:

{
"userword": [{
"name": "我的常用词",
"words": ["佳晨实业",
"蜀南庭苑",
"高兰路",
"复联二"]
},
{
"name": "我的好友",
"words": ["李馨琪",
"鹿晓雷",
"张集栋",
"周家莉",
"叶震珂",
"熊泽萌"]
}]
}

2.6.3 延迟休眠

AIUI中有效交互的定义是交互的结果有语义结果,并且语义结果中的rc字段的值为0。

AIUI中如果持续一段时间(配置文件interact_timeout可配置)无有效交互,AIUI就会自动休眠。

如用户在AIUI后台的应用管理中只勾选了听写,那客户端收到的交互结果中会一直没有语义结果, 都算是无效交互,在持续一段时间(interact_timeout)后就会自动休眠。对接入AIUI第三方后 处理的情况,也是类似的情况,AIUI无法识别第三方后处理结果中的有效语义,故也算是是无效交互。

对于上述这种情况,AIUI提供CMD_RESULT_VALIDATION_ACK命令,在接收到语义, 听写或者后处理结果后5秒内发送该条指令,AIUI即会认为该条结果为有效交互,并重新开始无效结果自动休眠的倒计时。

2.6.4 清除交互历史

AIUI支持多轮对话,如在问合肥今天的天气怎么样之后,再询问明天呢,AIUI会结合上一句询问合肥今天 天气的历史,就会会回答合肥明天的天气。

AIUI默认在休眠后唤醒会清除交互历史,在交互状态下唤醒,则不会清除交互历史。

AIUI清除历史的方式是可配置的,默认为auto即是上面描述的模式。当配置成user值后, 用户可以通过发送CMD_CLEAN_DIALOG_HISTORY在任何时候手动清除交互的历史。

即使在上面两种情况下,客户端都不主动清除交互历史,服务端保存用户交互历史的时间也是有限的120秒。

2.7 动态配置

2.7.1 Config&Msg&Event

Config

/* 情景模式设置 */
"global":{
"scene":"main"
}

Message

CMD_SET_PARAMS 10
设置参数配置

用params携带参数设置JSON字符串,具体格式参照aiui.cfg文件,目前仅可动态切换场景参数,实时生效。

2.7.2 切换场景

配置文件中的情景模式和后台应用定义的情景模式对应,在后台可以为不同情景模式配置不同语义技能、问答库, 通过本地的配置文件或者动态设置使用的情景模式。

动态切换场景,如下方法使用:

String setParams = "\"global\":{\"scene\":\"main\"}"
AIUIMessage setMsg = new AIUIMessage(CMD_SET_PARAMS, 0 , 0, setParams, "");
mAgent.sendMessage(setMsg)

2.8 后处理

AIUI后处理开放平台是为AIUI开发者提供更方便的后台接入能力,能够根据语音听写或语义等结果,提供个性化的服务和资讯。

在后处理过程中,AIUI服务将听写或语义的消息发送给配置的后处理服务器,服务器将处理的结果返回给AIUI服务,AIUI服务 再将处理结果下发给客户端,开发者通过集成AIUI SDK接收后处理结果,结果的解析参考AIUI结果解析

交互过程中,开发者也可以自定义一些数据,发送给后处理服务器。开发者可通过在配置文件中配置userparams参数或者发送CMD_SET_PARAMS消息来指定自定义数据。配置文件中可添加如下示例:

/* 用户参数,用于后处理(非必须)*/
"userparams":{
   "xxxx": "xxx", //自定义字段
}

服务端详细后处理协议参考AIUI应用管理中回调参设置查看文档协议。

2.9 错误处理

2.9.1 Msg&Event

Event

eventType(事件类型) 取值 说明
EVENT_ERROR 2
出错事件
arg1字段为错误码,info字段为错误描述信息。

2.9.2 处理

出错抛出错误事件,arg1携带错误码,info为错误描述信息。

错误码参考错误码查询

2.10 用户个性化

2.10.1 Config&Msg&Event

Config

"audioparams": {
"pers_param":"{\"appid\":\"\", \"uid\":\"\", \"custom_key\":\"custom_val\"}",
}

Message

msgType(消息类型) 取值 返回 说明
CMD_SET_PARAMS 10
设置参数配置
用params携带参数设置JSON字符串,
具体格式参照aiui.cfg文件,实时生效

CMD_SYNC 13
向AIUI服务同步数据
arg1表示同步的数据类型
data表示同步数据的内容

CMD_QUERY_SYNC_STATUS 24
查询数据同步状态
arg1表示状态查询的类型
params包含查询条件

2.10.2 使用场景

AIUI开放平台支持开发者DIY自己的自定义技能,以满足平台内置技能不能满足的需求。

在自定义技能中,开发者可以将语法定义中的语义槽与某个实体关联,实体类似一个包含所有支持说法的字典,比如开放平台支持内置的开放实体艺术家IFLYTEK.Artist就涵盖了很多歌手的名字和对应昵称等这些说法。

除了内置的开放实体,AIUI开放平台也支持开发者定义新的实体,在后台添加对应的支持的说法,这种实体为静态实体。另外支持开发者只在后台定义实体的数据格式,然后通过AIUI客户端接口动态上传支持说法的具体内容,这种实体为动态实体。下面提到的接口的作用即为动态上传和使用动态实体。

自定义技能和实体的更多细节参考自定义技能

2.10.3 动态实体

2.10.3.1 动态实体定义 

一个动态实体的定义可以包含多个资源Resource的定义,资源定义中包含了资源名称,以及从客户端上传数据抽取说法的字段名以及生效的维度。生效的维度目前有用户级(uid)、应用级(appid)、自定义级,在客户端上传对应的资源数据时,维度信息需要和定义时保持一致。

2.10.3.2 动态上传资源数据

通过CMD_SYNC 上传同步资源数据,arg1表示同步的数据类型,动态实体对应SYNC_DATA_SCHEMA(常量对应值为3)。 data为同步JSON内容的utf-8二进制数据。JSON内容示例如下:

{
"param": {
"appid": "56ac196f", // 开放平台appid
"id_name": "uid", // 维度
"id_value": "", // 维度具体值,当维度取uid或appid时,该值可取空,AIUI会自动补全
"res_name": "user_applist" // 资源名称
},
"data": "xxxxxx" // 与schema名称对应的数据内容base64编码
}

id_name与动态实体定义资源时指定的维度对应,如果定义时是用户级,那此处id_name就对应uidid_value是维度具体值,如id_nameuidid_value就需要是该资源针对生效的用户的具体UID,AIUI会使用 当前用户UID进行补全,appid同理。自定义维度因为是由开发者自定义,所以id_nameid_value都需要设置具体值。

通过指定id_nameid_value,上传的动态实体资源数据到服务端就有了唯一的从属,在生效使用时就可以指定此处的id_nameid_value的值就能生效使用当前上传的动态实体资源。

res_name对应的是平台自定义动态实体资源名,格式:“命名空间.资源名”,如IFLYTEK.telephone_contact。注:IFLYTEK.telephone_contact为开放动态实体,不需要后台自定义,被开放技能“电话”使用。

data中是原始资源数据的base64编码内容。原始资源数据是包含多条json记录的文本,通过动态实体定义时的抽取字段名可以从每条 json记录中抽取出定义支持的说法。

如定义资源时数据抽取的主列名为appName,别名为alias,那就要确保每条json记录中都要包含如上的字段(可以包含冗余字段,如下面的extra字段), 示例如下:

{"appName": "微信""alias": "wechat", "extra": "xxx"}
{"appName": "新浪微博""alias": "微博", "extra": "yyy"}
{"appName": "Telegram""alias": "电报", "extra": "zzz"}
{"appName": "讯飞输入法""alias": "", "extra": "uuu"}

data的实际内容是将如上数据进行base64编码后的结果。

同步上传的代码示例如下:

JSONObject syncSchemaJson = new JSONObject();
JSONObject paramJson = new JSONObject();
paramJson.put("appid", "56ac196f");
paramJson.put("id_name", "uid");
paramJson.put("res_name", "user_applist");
syncSchemaJson.put("param", paramJson);
syncSchemaJson.put("data", Base64.encodeToString(FileUtil.readAssetsFile(context, "file_path"), Base64.DEFAULT | Base64.NO_WRAP));
// 传入的数据一定要为utf-8编码
byte[] syncData = syncSchemaJson.toString().getBytes("utf-8");
AIUIMessage syncAthenaMessage = new AIUIMessage(AIUIConstant.CMD_SYNC,
AIUIConstant.SYNC_DATA_SCHEMA, 0, "", syncData);

CMD_SYNC完成后会有EVENT_CMD_RETURN事件回调,可以获取该操作对应的sid,便于后面查询使用:

private void processCmdReturnEvent(AIUIEvent event) {
switch (event.arg1) {
case AIUIConstant.CMD_SYNC: {
int dtype = event.data.getInt("sync_dtype");
//arg2表示结果
if (0 == event.arg2) { // 同步成功
if (AIUIConstant.SYNC_DATA_SCHEMA == dtype) {
mSyncSid = event.data.getString("sid");
showTip("schema数据同步成功,sid=" + mSyncSid);
}
} else {
if (AIUIConstant.SYNC_DATA_SCHEMA == dtype) {
mSyncSid = event.data.getString("sid");
showTip("schema数据同步出错:" + event.arg2 + ",sid=" + mSyncSid);
}
}
} break;
}
}

2.10.3.3 查询打包状态

通过CMD_SYNC上传同步动态实体的资源数据后,AIUI服务端会进行处理然后生效,处理的过程是异步的,可以通过CMD_QUERY_SYNC_STATUS查询上传的资源数据是否处理成功。

arg1表示状态查询的类型,动态实体对应SYNC_DATA_SCHEMA(常量对应值为3),params为json,包含需要对应同步上传操作的sid,示例如下:

JSONObject paramsJson = new JSONObject();
paramsJson.put("sid", mSyncSid);
AIUIMessage querySyncMsg = new AIUIMessage(AIUIConstant.CMD_QUERY_SYNC_STATUS,
AIUIConstant.SYNC_DATA_SCHEMA, 0,
paramsJson.toString(), null);
mAIUIAgent.sendMessage(querySyncMsg);

CMD_QUERY_SYNC_STATUS执行完成后会有EVENT_CMD_RETURN事件回调,表示查询结果,解析示例如下:

private void processCmdReturnEvent(AIUIEvent event) {
switch (event.arg1) {
//schema数据打包结果查询结果
case AIUIConstant.CMD_QUERY_SYNC_STATUS: {
int syncType = event.data.getInt("sync_dtype");
if (AIUIConstant.SYNC_DATA_QUERY == syncType) {
String result = event.data.getString("result");
if (0 == event.arg2) {
showTip("查询结果:" + result);
} else {
showTip("schema数据状态查询出错:" + event.arg2 +
", result:" + result);
}
}
} break;
}
}

2.10.3.4 生效使用

通过CMD_SET_PARAMS设置pers_param即可使用已设置的动态实体(CMD_SET_PARAMS具体用法参见动态配置pers_param的示例如下:

"audioparams": {
"pers_param":"{\"appid\":\"\", \"uid\":\"\", \"custom_key\":\"custom_val\"}",
}

如果需要在本机器上生效当前应用对应的所有应用级的动态实体,在pers_param加入\"appid\":\"\"(值留空, AIUI中会自动补全appid和uid的值),同理用户级动态实体生效需要加入\"uid\":\"\"

对于自定义维度需要用后台定义实体时的自定义维度名作为key,使用动态上传指定的自定义维度作为值。如后台定义的自定义维度名为vendor,那在动态上传时就需要构造如下数据进行上传:

{
"param": {
"appid": "56ac196f", // 开放平台appid
"id_name": "vendor", // 自定义维度名
"id_value": "spec_vendor", // 自定义维度value
"res_name": "user_applist" // 资源名称
},
"data": "xxxxxx" // 与schema名称对应的数据内容base64编码
}

那对应需要在交互时使用该自定义维度对应的动态实体就需要加入\"vendor\":\"spec_vendor\"

除了通过CMD_SET_PARAMS设置pers_param,也可以在写入音频时设置该参数。

2.10.4 所见即可说

2.10.4.1 所见即可说定义

动态实体还有一种特殊的维度,名为所见即可说。该种动态实体上传的内容只会生效使用一次,在上传后生效交互一次后,即会恢复无数据的状态。该维度适用于一些临时数据,如只在当前屏幕显示的信息,在上传当前屏幕内容数据后,用户根据当前屏幕的内容进行交互,交互过后屏幕内容即会刷新, 更多示例和解释参考AIUI开放平台上自定义技能

2.10.4.2 动态上传资源数据

通过CMD_SYNC上传同步资源数据,arg1表示同步的数据类型,所见即可说对应SYNC_DATA_SPEAKABLE(常量对应值为5)。data为同步JSON内容的utf-8二进制数据。JSON内容示例如下:

{
// 识别数据
"iat_user_data": {
"recHotWords": "播报内容|地图显示|路径优先",
"sceneInfo": {}
},
// 语义数据
"nlp_user_data": {
"res": [
{
"res_name": "vendor_applist", // 资源名称
"data": "xxxxxx" // 数据的base64编码
}
],
"skill_name": "telephone" // 对应的技能名称
}
}

上传数据中包含识别和语义数据,识别数据包含所有识别热词,以|分隔,语义数据中包含资源名称,资源数据,资源对应的技能名称。资源名称和资源数据与上面描述的动态实体中的字段相同,技能名称是该实体对应生效的技能。

上传的代码示例参考如上动态实体数据构造上传部分。

生效使用

动态实体生效使用类似,需要在pers_param中添加uid即可生效使用:

"pers_param":"{\"uid\":\"\"}"

3 WebAPI

3.1 简介

AIUI 通过 REST API 的方式给开发者提供一个通用的 HTTP 接口,基于该接口,开发者可以轻松的获取AIUI 的语音识别,语音语义以及文本语义的能力,方便开发者使用自己熟悉的编程语言快速集成。

3.2 接口概述

3.2.1 API说明

1. 授权认证,调用接口需要将APPID,CurTime, Param和CheckSum信息放在HTTP请求头中。

2. 所有接口统一为UTF-8编码。

3. 所有接口支持http和https。

3.2.2 授权认证

在调用所有业务接口时,都需要在Http Request Header中加入以下参数作为授权验证:

参数 说明 是否必须
X-Appid 讯飞开放平台注册申请应用的应用ID(APPID)
X-CurTime 当前UTC时间戳,从1970年1月1日0点0 分0 秒开始到现在的秒数(String)
X-Param Base64编码的json,见接口详细说明
X-CheckSum MD5(ApiKey + CurTime + Param + http_body),四个参数拼接的字符串,进行MD5哈希计算。其中http_body 即为请求服务的实际服务HTTP body

注:

1.CheckSum有效期:出于安全性考虑,每个CheckSum的有效期为5分钟(用curTime计算),同时CurTime要与标准时间同步,否则,时间相差太大,服务端会直接认为CurTime无效。

2. checkSum生成示例

例如:

ApiKey是abcd1234, CurTime是1502607694,Param是eyJzY2VuZSI6Im1haW4ifQ==, http_body是text=5LuK5aSp5pif5pyf5Yeg。那么CheckSum为MD5(abcd12341502607694eyJzY2VuZSI6Im1haW4ifQ==text=5LuK5aSp5pif5pyf5Yeg)

最终MD5为32位小写 a2fe085df68c87b8aca5f539df8e1a3d

3.2.3 IP 白名单

在调用所有业务接口时,授权认证通过后。检查调用方ip是否在aiui开放平台配置的ip白名单中。存在通过,否则拒绝提供服务。

注:拒绝提供服务返回值:{"code":"20004","desc":"ip非法","data":null}

3.2.4 通用请求地址

base_url:api.xfyun.cn

3.3 AIUI接口

3.3.1 接口说明

3.3.1.1 通用返回参数

参数 说明 是否必须
code 结果码
data 返回结果
desc 描述
sid 本次webapi服务唯一标识

3.3.2 文本语义接口

3.3.2.1 接口描述

本接口对用户的文本进行解释分析,返回文本的语义意图。

3.3.2.2 接口地址

POST /v1/aiui/v1/text_semantic HTTP/1.1
Content-Type:application/x-www-form-urlencoded; charset=utf-8

3.3.2.3 参数说明

在调用本接口时,需要在Http Request Header中加入参数X-Param

参数 类型 必须 说明 示例
X-Param Base64编码的json 标准JSON格式参数需把参数组装json对象,然后对json进行base64编码 json: {"scene":"main", "userid":"user_0001"}
base64编码: eyJzY2VuZSI6Im1haW4iLCAidXNlcmlkIjoidXNlcl8wMDAxIn0=

X-Param参数说明:

参数 类型 必须 说明 示例
scene String 情景模式 main
userid String 用户 id,适用于多轮对话。 user_0001

Http Request Body中加入以下参数:

参数 类型 必须 说明 示例
text String 文本 今天星期几
base64编码:5LuK5aSp5pif5pyf5Yeg

3.3.2.4 返回说明

返回结果data如下:

参数 类型 必须 说明
rc int 应答码(response code)
text String 用户的输入,可能和请求中的原始text不完全一致,因服务器可能会对text进行语言纠错
vendor String 技能提供者,不存在时默认表示为IFLYTEK提供的开放技能
service String 技能的全局唯一名称,一般为vendor.name,vendor不存在时默认为IFLYTEK提供的开放技能。
semantic Array 本次语义(包括历史继承过来的语义)结构化表示,各技能自定义
data Object 数据结构化表示,各技能自定义
answer Object 对结果内容的最简化文本/图片描述,各技能自定义
dialog_stat String 用于客户端判断是否使用信源返回数据
moreResults Object 在存在多个候选结果时,用于提供更多的结果描述
sid String 本次服务唯一标识

3.3.2.5 curl示例

请求:
curl –XPOST http[s]://base_url/v1/aiui/v1/text_semantic -H "X-Appid: 594b62c3 "
-H "X-CurTime: 1502610698" -H "X-CheckSum: 3c22f7c07620776172675c7143c33026"
-H "X-Param: eyJzY2VuZSI6Im1haW4iLCAidXNlcmlkIjoidXNlcl8wMDAxIn0=" -d "text=5LuK5aSp5pif5pyf5Yeg"
响应体:
{
  "code": "00000",
  "desc": "成功",
  "data": {
    "answer": {
      "text": "今天是2017年08月08日 丁酉年六月十七 星期二",
      "type": "T"
    },
    "match_info": {
      "type": "gparser_path",
      "value": "-----"
    },
    "operation": "ANSWER",
    "rc": 0,
    "service": "datetime",
    "text": "今天星期几",
    "uuid": "atn00210ce6@un782b0ce4cac76f2601",
    "sid": "rwa2ac04d1c@chfca30da12150000100"
  },
  "sid":"rwa2ac04d1c@chfca30da12150000100"
}

3.3.3 语音识别接口

3.3.3.1 接口描述

本接口将自然语言识别为文本输出。

注:语音识别最大支持60秒

3.3.3.2 接口地址

POST /v1/aiui/v1/iat HTTP/1.1
Content-Type:application/x-www-form-urlencoded; charset=utf-8

3.3.3.3 参数说明

在调用本接口时,需要在Http Request Header中加入参数X-Param。

参数 类型 必须 说明 示例
X-Param Base64编码的json 标准JSON格式参数。 需按照参数示例组装json对象,然后对json进行base64编码 json: {"auf":"8k","aue":"raw","scene":"main"}
base64编码:
eyJhdWYiOiI4ayIsImF1ZSI6InJhdyIsInNjZW5jZSI6Im1haW4ifQ==

X-Param参数说明:

参数 类型 必须 说明 示例
auf String 音频格式(8k、16k)
(audio/L16;rate=8000时取8k; audio/L16;rate=16000时取16k)
8k
aue String 音频编码
1. 当音频为未压缩的 pcm、wav格式时,为raw
2. 当音频为 speex 宽带压缩时,auf为16k使用speex-wb,8k使用speex
raw
scene String 情景模式 main
spx_fsize String speex 编码器对每帧音频(SPEEX_GET_FRAME_SIZE获取)进行编码压缩后的纯语音数据大小。
备注:由于采用不同压缩率(SPEEX_SET_QUALITY)等参数值会导致压缩音频大小的变化,且上传数据为不含头信息的纯音频数据, 故需此参数辅助解码。如微信 speex 音频,该参数传值 spx_fsize=60(可通过微信示例代码确认)。音频为 speex 宽带压缩时此参数必传
60

Http Request Body中加入以下参数:

参数 类型 必须 说明 示例
data String Base64 编码的音频, 支持 pcm 或 wav 以及 speex 宽带压缩格式 Base64编码内容(音频二进制): xxxxxxxxxxxxxxxxx

3.3.3.4 返回说明

返回结果data如下:

参数 类型 必须 说明
sid String 本次服务唯一标识
result String 音频对应的识别结果
ret int 错误码(0表示成功)

3.3.3.5 curl示例

请求:
curl –XPOST http[s]://base_url/v1/aiui/v1/iat -H "X-Appid: 594b62c3 " -H
"X-CurTime: 1502184180" -H "X-CheckSum: 001388491350e266fab5e15da9aea749" –H
"X-Param: eyJhdWYiOiI4ayIsImF1ZSI6InJhdyIsInNjZW5jZSI6Im1haW4ifQ==" –d
"data=PDXOSEarAABo6Ojo6Ojo6IOh9HR0cl8oFw9BVeNc2jFr2ZFfsszurkqtCWGbDVo4BbWtYr
VcURYFsaBzhzw1zOFgTIk3FRsH2E9tYG1N+YqGAPrFrJl70D2jrjK7UjHoKSsP1bxZ5TWiPqUqOh
IMMWGEB4GkIANo3Zc8Ndltx4vefwFWQWS00vNr3z++TcAi6Zs0A4vN3VWC4FDG2urTVuG3GSLfAo
9NujshWduRgGhAztDgLkw3PDHPLovLerbSod+ZLjopVprhgqHgi6a7F/P/w9NnTSpHeFKV+ibtpENr7miGWC…"
响应体:
{
    "code": "00000",
    "desc": "成功",
    "data": {
        "ret": 0,
        "result": "今天星期几。",
        "sid": "watb37fe700@ch47730ce51e04477300"
    },
    "sid":"rwa8066ef80@cha4320da12234000100"
}

3.3.4 语音语义接口

3.3.4.1 接口描述

本接口先将自然语言识别为文本,后对该文本进行解释分析,返回文本的语义意图。

3.3.4.2 接口地址

POST /v1/aiui/v1/voice_semantic HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=utf-8

3.3.4.3 参数说明

在调用本接口时,需要在Http Request Header中加入参数X-Param。

参数 类型 必须 说明 示例
X-Param Base64编码的json 标准JSON格式参数。 需按照参数示例组装json对象,然后对json进行base64编码 json: {"auf":"8k","aue":"raw","scene":"main","userid":"user_0001"}
base64编码: eyJhdWYiOiI4ayIsImF1ZSI6InJhdyIsInNjZW5lIjoibWFpbiIsInVzZXJp
ZCI6InVzZXJfMDAwMSJ9

X-Param参数说明:

参数 类型 必须 说明 示例
auf String 音频格式 (audio/L16;rate=8000时取8k; audio/L16;rate=16000时取16k) 8k
aue String 音频编码
1. 当音频为未压缩的 pcm、wav格式时,为raw
2. 当音频为 speex 宽带压缩时,auf为16k使用speex-wb,8k使用speex
raw
scene String 情景模式 main
userid String 用户 id,适用于多轮对话 user_0001
spx_fsize String speex 编码器对每帧音频(SPEEX_GET_FRAME_SIZE获取)进行编码压缩后的纯语音数据大小。
备注:由于采用不同压缩率(SPEEX_SET_QUALITY)等参数值会导致压缩音频大小的变化,且上传数据为不含头信息的纯音频数据, 故需此参数辅助解码。如微信 speex 音频,该参数传值 spx_fsize=60(可通过微信示例代码确认)。音频为 speex 宽带压缩时此参数必传
60

Http Request Body中加入以下参数:

参数 类型 必须 说明 示例
data String Base64 编码的音频, 支持 pcm 或 wav 以及 speex 宽带压缩格式 Base64编码内容(音频二进制): xxxxxxxxxxxxxxxxx

3.3.4.4 返回说明

返回结果data如下:

参数 说明 是否必须
code 结果码
data 返回结果
desc 描述
iat_code 识别结果码

返回结果data如下:

参数 类型 必须 说明
rc int 应答码(response code)
text String 用户的输入,可能和请求中的原始text不完全一致,因服务器可能会对text进行语言纠错
vendor String 技能提供者,不存在时默认表示为IFLYTEK提供的开放技能
service String 技能的全局唯一名称,一般为vendor.name,vendor不存在时默认为IFLYTEK提供的开放技能。
semantic Array 本次语义(包括历史继承过来的语义)结构化表示,各技能自定义
data Object 数据结构化表示,各技能自定义
answer Object 对结果内容的最简化文本/图片描述,各技能自定义
dialog_stat String 用于客户端判断是否使用信源返回数据
moreResults Object 在存在多个候选结果时,用于提供更多的结果描述
sid String 本次服务唯一标识

3.3.4.5 curl示例

请求:
curl –XPOST http[s]://base_url/v1/aiui/v1/iat -H "X-Appid: 594b62c3 " -H
"X-CurTime: 1502184180" -H "X-CheckSum: 001388491350e266fab5e15da9aea749" –H
"X-Param: eyJhdWYiOiI4ayIsImF1ZSI6InJhdyIsInNjZW5lIjoibWFpbiIsInVzZXJpZCI6InVzZXJfMDAwMSJ9" –d
"data=PDXOSEarAABo6Ojo6Ojo6IOh9HR0cl8oFw9BVeNc2jFr2ZFfsszurkqtCWGbDVo4BbWtYr
VcURYFsaBzhzw1zOFgTIk3FRsH2E9tYG1N+YqGAPrFrJl70D2jrjK7UjHoKSsP1bxZ5TWiPqUqOh
IMMWGEB4GkIANo3Zc8Ndltx4vefwFWQWS00vNr3z++TcAi6Zs0A4vN3VWC4FDG2urTVuG3GSLfAo
9NujshWduRgGhAztDgLkw3PDHPLovLerbSod+ZLjopVprhgqHgi6a7F/P/w9NnTSpHeFKV+ibtpENr7miGWC…"
响应体:
{
  "code": "00000",
  "desc": "成功",
  "iat_code": "0",
  "data": {
    "answer": {
      "text": "今天是2017年08月08日 丁酉年六月十七 星期二",
      "type": "T"
    },
    "match_info": {
      "type": "gparser_path",
      "value": "-----"
    },
    "operation": "ANSWER",
    "rc": 0,
    "service": "datetime",
    "text": "今天星期几",
    "uuid": "atn00210ce6@un782b0ce4cac76f2601",
    "sid": "atn00210ce6@un782b0ce4cac76f2601"
  },
  "sid":"rwa482dff1f@ch5ba50da12250000100"
}

3.4 错误码

错误码信息如下表:

错误码 错误描述
00000 成功
10001 授权请求头参数为空
10002 过期请求
10003 无效的APPID
10004 TOKEN无效
10005 无权操作
10006 服务异常
10007 该appid调用次数已用完
20001 必选参数为空
20002 请求超时
20003 参数非法
20004 ip非法
20005 http消息体为空
99999 系统异常

3.5 常见问题

1. 音频格式 pcm 与wav 格式之间的关系。

Pcm 几乎就是 wav 格式,内部存储音频方式是一样的。但 wav 比 pcm 多了一 个很短的文件头用来告诉播放器所存储音频的采样频率,声道为单声道或立体声,一 次采样使用的 bit 数等参数,故 wav 是可以在播放器中直接播放的,而 pcm 却不行。 当用 Cool Edit 打开 pcm 音频时,选择的参数相当于临时确定了文件头,此时音频才 可以播放。

2. 可以通过给 pcm 添加一个文件头,将 pcm 音频直接转换为 wav 格式。

语音识别接口中,每次都能返回文本,但为什么识别率却不高? 服务中,每次都能返回文本,但为什么识别率却不高?

首先请确保你的音频有一定的清晰度。

其次 webapi 所接收和返回的文本原始编码均为 utf-8,请查看你的编码设置。 最后,请关注读取音频文本并进行 base64 加密的过程。要直接对整个文本进行 base64 加密。如果你用的是 C++,而且你是先把文本读到字符串中,再对字符串进行 加密,就有可能出现字符串中只存储了部分音频(遇到文本中的'\0',字符串就结束了), 致使所发送的音频信息缺失。

4 语义协议

4.1 概述

科大讯飞Athena系统,是一个集人工智能对话、语义理解以及智能问答能力的技术性平台,通过AIUI开放平台对外开放,面向广大开发者提供一站式语义、对话解决方案。

该系统提供覆盖多个垂直领域的语义、对话技能,提供海量开放问答库;通过AIUI开放平台,也支持开发者自定义技能和问答库。

支持Andriod、IOS、JAVA、Linux等多终端接入,通过多样化的结果输出,满足应用的个性化需求。

4.2 应答消息格式

交互返回协议为JSON格式,内容示例如下:

    {
        "answer" : {
            "text" : "\"合肥\"今天\"中雨\", \"15℃\", \"东北风微风\", 雨天出行记得准备带伞"
        },
        "data" : {
            "result" : [
                {
                    ......
                }
            ]
        },
        "dialog_stat" : "DataValid",
        "text" : "合肥的天气",
        "service" : "weather",
        "rc" : 0,
        "semantic" : [
            {
                "intent" :  "QUERY",
                "slots" : {
                     ......
                }
            }
        ]
    }

4.3 应答消息字段定义

字段名称 字段类型 是否必须 说明
rc int 应答码(response code)
error Object 错误信息
text String 用户的输入,可能和请求中的原始text不完全一致,因服务器可能会对text进行语言纠错
vendor String 技能提供者,不存在时默认表示为IFLYTEK提供的开放技能
service String 技能的全局唯一名称,一般为vendor.name,vendor不存在时默认为IFLYTEK提供的开放技能。
semantic Object 本次语义(包括历史继承过来的语义)结构化表示,各技能自定义
data Object 数据结构化表示,各技能自定义
answer Object 对结果内容的最简化文本/图片描述,各技能自定义
dialog_stat String 用于客户端判断是否使用信源返回数据
moreResults Object 在存在多个候选结果时,用于提供更多的结果描述

4.3.1 应答码

用于标识用户请求响应的状态,它包含用户操作成功或异常等几个方面的状态编号。当存在多个候选的响应结果时,每个响应结果内都必须包含相应的rc码,便于客户端对每个响应包进行识别和操作。

应答码 说明
"rc"
0 操作成功
1 输入异常
2 系统内部异常
3 业务操作失败,错误信息在error字段描述
4 文本没有匹配的技能场景,技能不理解或不能处理该文本

4.3.2 语义结构化表示

表示对用户文本的语义意图描述信息,通过该字段应用可以精确定位用户的意图,并获取具体的意图内容参数,在应用中实现对应的技能逻辑处理。

semantic是一个JSON数组,每个对象表示一种可能的语义理解方式,数组中每个成员对象说明如下。

字段名称 字段类型 是否必须 说明
"semantic"
intent String 技能中的意图
slots Object 参照后续不同技能的定义

slots是一个JSON数组,每个对象表示一个语义槽位信息,数组中的成员对象说明如下。

字段名称 字段类型 是否必须 说明
"slot"
name String 槽位名
value String 槽位值

4.3.3 结构化数据表示

除了返回对用户意图的描述,对于一些技能,也支持返回对用户文本的应答结果。该字段表示对应答结果的结构化描述信息,如果应用本身没有特定数据源,可以直接选择该结构化的结果进行解析和处理展现,无需处理语义信息。

字段名称 字段类型 是否必须 说明
"data"
header String 导语部分
result Object 结构化数据;如果没有查到数据,此字段不返回。参照后续不同技能的定义

4.3.4 简化图文结果表示

对于一些技能,支持直接返回一段文本应答结果,同时辅助一张图片和相关链接。应用可以无需解析和提取语义/结果的结构化数据信息,直接显示该字段的图文信息。同时用户可以选择通过开放平台编辑和上传/导入图文应答信息,快速自定义扩展应用交互。

字段名称 字段类型 是否必须 说明
"answer"
type String 显示的类型,通过这个类型,可以确定数据的返回内容和客户端的显示内容:
T:text数据
U:url数据
TU:text+url数据
IT:image+text数据
ITU:image+text+url数据
text String 通用的文字显示,属于text数据
imgUrl String 图片的链接地址,属于image数据
imgDesc String 图片的描述文字
url String url链接
urlDesc String url链接的描述文字
emotion String 回答的情绪,取值参见附录的情感标签对照表

4.3.5 moreResults结构表示

当用户的文本可能存在多个对应的意图技能时,应用可以选择返回多候选的应答结果,协议会通过moreResults字段来扩展后续的其他意图技能描述。moreResults是一个JSON数组,用户可以在开放平台配置是否允许多结果。(这里需要针对几个关键字段的特殊处理单独说明,如rc)

示例:

    {
        "answer" : {
            "text" : "你想做飞机还是火车?"
        },
        "rc" : 0,
        "semantic" : [
            {
                "intent" :  "QUERY",
                "slots" : [
                     ......
                ]
            }
        ],
        "service" : "flight",
        "text" : "我要去北京",
        "moreResults" : [
            {
                "text" : "我要去北京",
                "rc" : 0,
                "semantic" : [
                     ......
                ],
                "service" : "tran"
            }
        ]
    }

4.4 通用功能协议

本章描述了在各技能中相对通用的字段定义,在具体技能中如果引用相关字段将不再具体描述,直接参考相关章节。例如:在“航班”技能中需要定义“预定时间”,可以直接参考本章节中对“时间点”的定义,而不需要在技能中具体定义。

4.4.1 地点描述相关协议

地点的基础描述为基于行政区的地点定义,在此基础上包括扩展协议:表示道路、表示交叉路口、表示区域、表示位置点。

4.4.1.1 基础地点(表示行政区)的location

name字段名 是否必须 说明(value取值)
location.type 取LOC_BASIC
location.country 国别简称(参见附录的对照表)
location.province 省全称(包括直辖市、台)
location.provinceAddr 省简称
location.city 市全称(包括港澳)
location.cityAddr 市简称
location.area 县区
location.areaAddr 县区简称
location.country、location.province、location.city、location.area这4种元素必须至少出现一种

示例:合肥市包河区

         "slots": [
             {
                 "name": "location.area",
                 "value": "包河区"
             },
             {
                 "name": "location.areaAddr",
                 "value": "包河"
             },
             {
                 "name": "location.city",
                 "value": "合肥市"
             },
             {
                 "name": "location.cityAddr",
                 "value": "合肥"
             },
             {
                 "name": "location.type",
                 "value": "LOC_BASIC"
             }
         ]

4.4.1.2 表示道路的location

name字段名 是否必须 说明(value取值)
location.type 取LOC_STREET
location.country 国别简称(参见附录的对照表)
location.province 省全称(包括直辖市、台)
location.provinceAddr 省简称
location.city 市全称(包括港澳), CURRENT_CITY代表当前城市
location.cityAddr 市简称
location.area 县区
location.areaAddr 县区简称
location.street 道路名称
city、street必选,其他元素可选,当用户没有输入城市,city为”CURRENT_CITY”

示例:合肥市长江西路

         "slots": [
             {
                 "name": "location. street",
                 "value": "长江西路"
             },
             {
                 "name": "location.city",
                 "value": "合肥市"
             },
             {
                 "name": "location.cityAddr",
                 "value": "合肥"
             },
             {
                 "name": "location.type",
                 "value": " LOC_STREET "
             }
         ]

4.4.1.3 表示交叉路口的location

name字段名 是否必须 说明(value取值)
location.type 取LOC_CROSS
location.country 国别简称(参见附录的对照表)
location.province 省全称(包括直辖市、台)
location.provinceAddr 省简称
location.city 市全称(包括港澳), CURRENT_CITY代表当前城市
location.cityAddr 市简称
location.area 县区
location.areaAddr 县区简称
location.street 道路名称
location.streets 交口的另一道路名称
city、street必选,其他元素可选,当用户没有输入城市而又没有上传所在城市信息,city为”CURRENT_CITY”

示例:合肥市望江西路和永和路交口

         "slots": [
             {
                 "name": "location. street",
                 "value": "望江西路"
             },
             {
                 "name": "location. streets",
                 "value": "永和路"
             },
             {
                 "name": "location.city",
                 "value": "合肥市"
             },
             {
                 "name": "location.cityAddr",
                 "value": "合肥"
             },
             {
                 "name": "location.type",
                 "value": " LOC_ CROSS "
             }
         ]

4.4.1.4 表示区域的location

name字段名 是否必须 说明(value取值)
location.type 取LOC_REGION
location.country 国别简称(参见附录的对照表)
location.province 省全称(包括直辖市、台)
location.provinceAddr 省简称
location.city 市全称(包括港澳), CURRENT_CITY代表当前城市
location.cityAddr 市简称
location.area 县区
location.areaAddr 县区简称
location.street 道路名称
location.region 区域名称
city、region必选,其他元素可选,当用户没有输入城市而又没有上传所在城市信息,比如“西直门”,city为“CURRENT_CITY”

示例:合肥市三里庵

         "slots": [
             {
                 "name": "location. region",
                 "value": "三里庵"
             },
             {
                 "name": "location.city",
                 "value": "合肥市"
             },
             {
                 "name": "location.cityAddr",
                 "value": "合肥"
             },
             {
                 "name": "location.type",
                 "value": " LOC_ REGION"
             }
         ]

4.4.1.5 表示位置点的location

name字段名 是否必须 说明(value取值)
location.type 取LOC_POI
location.country 国别简称(参见附录的对照表)
location.province 省全称(包括直辖市、台)
location.provinceAddr 省简称
location.city 市全称(包括港澳), CURRENT_CITY代表当前城市
location.cityAddr 市简称
location.area 县区
location.areaAddr 县区简称
location.street 道路名称
location.region 区域名称
location.poi 机构等名称,CURRENT_POI表示当前地点
city、poi必选,其他元素可选,当用户没有输入城市而又没有上传所在城市信息, city为“CURRENT_CITY”

示例:合肥市三里庵国购广场

         "slots": [
             {
                 "name": "location. region",
                 "value": "三里庵"
             },
             {
                 "name": "location. poi",
                 "value": "国购广场"
             },
             {
                 "name": "location.city",
                 "value": "合肥市"
             },
             {
                 "name": "location.cityAddr",
                 "value": "合肥"
             },
             {
                 "name": "location.type",
                 "value": " LOC_POI"
             }
         ]

4.4.2 时间描述相关协议

时间描述的基础是描述了时间点的协议,在此基础上包括扩展协议:时间段协议、不同时间点、无法解析的时间说法。

slots中表示时间协议字段如下:

字段名称 说明
name 固定为datetime
value 原始输入中匹配上的关于时间的文本
normValue JSON String类型,为日期的归一化格式表示

日期归一化格式说明如下:

字段名称 说明
datetime 开放给开发者的使用的时间协议,用户可以根据该协议字符计算时间
suggestDatetime 推荐时间供开发者选择使用

4.4.2.1 基础描述(表示时间点)的datetime

采用[LC] [YY-MM-DD]T[hh:mm:ss][AM/PM]的格式表示基本时间。

其中:

LC: 表示阴历

YY-MM-DD: 表示年-月-日

T:标识后面为时间字段

hh:mm:ss: 表示时:分:秒

AM/PM: 表示上午/下午

支持说法范围为:基本时间说法、日期、时间、日期+时间、节日、阴历时间等。

示例: 明天下午三点

         {
             "name": "datetime",
             "value": "明天下午3点",
             "normValue": "{\"datetime\":\"2017-06-07T15:00:00\",\"suggestDatetime\":\"2017-06-07T15:00:00\"}"
         }

示例: 后天下午

         {
             "name": "datetime",
             "value": "后天下午",
             "normValue": "{\"datetime\":\"2017-06-09TPM\"}"
         }

示例: 2017年中秋节

         {
             "name": "datetime",
             "value": "2017年中秋节",
             "normValue":"{\"datetime\":\"LC 2017-08-15\",\"suggestDatetime\":\"2017-10-04\"}"
         }

4.4.2.2 表示时间段的datetime

采用 ”基础时间”/”基础时间” 方式表示时间段。

示例: 明天下午3点到5点

         {
             "name": "datetime",
             "value": "明天下午3点到5点",
             "normValue":"{
                    \"datetime\":\"2017-06-08T15:00:00/2017-06-08T17:00:00\",
                    \"suggestDatetime\":\"2017-06-08T15:00:00/2017-06-08T17:00:00\
              "}"
         }

示例: 下周三到周日

         {
             "name": "datetime",
             "value": "下周三到下周日",
             "normValue":"{\"datetime\":\"2017-06-14/2017-06-11\",\"suggestDatetime\":\"2017-06-14/2017-06-18\"}"
         }

5 主要概念

5.1 技能

AIUI 开放平台的技能分为开放技能自定义技能,其中开放技能由科大讯飞提供,涵盖天气,股票,闹钟,智能家居等生活常用情景,技能用于完成一个或者一组特定意图。一个意图又包含若干句语料。语料为交互的核心内容。

按照粒度从大到小划分:应用>技能>意图>语料

以智能音箱为例,音箱可以拥有若干个技能,比如天气、音乐、空调以及星座。针对星座这个技能,存在幸运数字,幸运颜色和今日运势等意图。针对幸运数字又有若干种问法,例如:今天射手座的幸运数字射手座今天的幸运数字是什么

5.1.1 入口意图与对话意图的区别

如下图所示的一个星座技能,当用户想要询问明天的幸运颜色时,有两种提问方式:
方式1 单轮对话
提问:明天射手座的幸运颜色是什么
方式2 多轮对话
提问:射手座的幸运颜色是什么
反问:您想问哪一天
提问:明天

意图类型说明1.png 意图类型说明2.png

在上图实例中,第三个意图 time 没有单独存在的意义,只有当前对话的上下文环境是星座技能时,系统才需要对其作出语义理解。 因此我们将第一个和第二个意图设置为入口意图,即通过这两个意图的语料可以进入星座技能,而将第三个意图设置为对话意图,只有当通过其他意图进入星座技能的上下文环境时,才能生效。

注:多轮对话的功能即将在技能后处理中开通,敬请期待。

5.2 语料

开发者在语料中尽可能多的覆盖用户可能的说法,AIUI 引擎匹配到语料后,会返回给开发者对应的所属的意图以及实体槽信息。

5.2.1 模糊匹配

当用户勾选了模糊匹配时,AIUI 引擎会在用户语料的基础上进行训练,以覆盖更多的说法。开发者提供的语料越丰富,模型效果越好。其中 AIUI 可以覆盖以下情况:

  • 语气助词、礼貌性用语等与语义无关词汇的冗余或缺失以及口语化的表示,不会影响匹配效果,如:“请问一下空调什么价格”、“空调什么价格呀”、“空调什么价格”、“空调怎么卖”四者语义匹配;
  • 通用领域的近义词,如:“出售”,“卖”,“售卖”三个词词义一致。 AIUI 后续迭代过程中,我们会持续拓展通用和垂直领域的同义词并迭代更新模型来优化方案,以达到更好的理解效果。

5.2.2 可选符

语料中的大括号{}代表实体,中括号[]代表可选符,小括号()代表必选符。 大括号:打电话给{contact}

中括号:帮我呼叫张三[的电话|的电话号码|的手机] 等同于:帮我呼叫张三、帮我呼叫张三的电话、帮我呼叫张三的电话号码、帮我呼叫张三的手机

小括号:帮我(呼叫|拨打)张三的电话号码 等同于:帮我呼叫张三的电话号码、帮我拨打张三的电话

一句语料中只允许出现一个中括号或者小括号。

√ [{time}]{city}的天气
X (帮我|请帮我)呼叫张三(的手机号|的号码)

此外,如需在语料中实现通配效果,请参考通配实体文档。

5.3 实体

为了开发者更好的理解实体的概念,本文档将结合实例为开发者详细介绍实体的概念以及各类动态实体资源的使用场景。

5.3.1 静态实体

用例1:

以天气查询的 App 为例,开发者期望用户的交互方式为:

明天合肥天气怎么样

明天厦门会下雨吗

我们可以把以上两句话抽象为一个自定义技能,其中语料如下:

{time} {localtion} 天气怎么样

{time} {localtion} 会下雨吗

{time}{location}分别包含:

time 实体 location 实体
今天 北京
明天 上海
后天 合肥
周一 厦门
周二 武汉
…… ……

对于静态实体,开发者任意一款 App 添加了静态实体均可生效,生效时间为永久。为了方便开发者,讯飞开放平台已经为开发者内置了"数字","城市","歌曲"等三十多个常用实体,开发者可以直接调用。

静态实体.jpg

5.3.2 动态实体

静态实体的作用范围很大,但当开发者遇到以下几种用例时可能不能满足,为此我们推出了动态实体,满足开发者各终端的实体需要差异化设置时的需求。

应用级

应用级.jpg

用例2:

以开发两款百科 App 为例,分别是《水浒传百科》和《西游记百科》,开发者期望用户的交互方式为:

我想听李逵的故事

介绍一下孙悟空

我们可以把以上两句话抽象为一个自定义技能,其中语料如下:

我想听{name}的故事

介绍一下{name}

《水浒传百科》和《西游记百科》两个 App 均添加了这个技能,但是这两个 App 的实体并不相同。{name} 内容分别如下:

水浒传 name 实体 西游记 name 实体
宋江 唐僧
鲁智深 孙悟空
林冲 猪八戒
武松 沙僧
李逵 太上老君
…… ……

为了实现这个目标,我们提供了动态实体(应用级)动态实体(应用级)可以在实体名相同的情况下,为每个 appid 设置不同的实体副本。

动态实体(应用级)作用域为 appid,生效时间为永久。

用户级

用户级.jpg

用例3:

以开发一款电话 App 为例, 开发者期望用户的提问方式为:

打电话给张三

呼叫李四

我们可以把以上两句话抽象为一个自定义技能,其中语料如下:

打电话给{contacts}

呼叫{contacts}

由于每个用户的联系人名称都不一样,因此无法使用静态实体。为此 AIUI 的 SDK 中,为开发者提供了相应的 API 接口,开发者可以针对每个用户维护一个实体副本。动态实体(用户级)只对特定用户生效,生效时间为永久。

自定义级

自定义级.jpg

用例4:

以开发一个全国连锁餐厅点餐 App 为例, 开发者期待用户的交互方式为:

我想吃杭椒牛柳

点一份宫保鸡丁

我们将其抽象为一个自定义技能,其中语料如下:

我想吃{dish}

点一份{dish}

但是由于该连锁餐厅全国不同省份的菜单不一样,每个省份有若干台点餐终端,但是实体不能通用。

为了解决这个问题,我们引入了动态实体(自定义级)

我们为这款点餐 App 新建了一个动态实体命名为" dish",同时在这个实体下创建两个资源,分别是"dish_general" 和"dish_specail",其中 "dish_general" 的维度为应用级," dish_specail" 的维度为自定义,我们把这个自定义的维度命名为"province"。在控制台的设置如下:

WX20170811-154913。png

如图所示,开发者可以为一个动态实体,设置两个维度的资源。

其中 dish_general 中,开发者可以通过 API上传全国通用的菜单。

针对 dish_special, 开发者可以通过维度名 province 上传各个省份的菜单,例如 Anhui,Beijing,Fujian 等,具体操作请参考 SDK 文档。

使用动态实体(自定义级)开发者可以自定义分组,实体设置成功后,只对属于特定分组的终端生效。

5.3.3 所见即可说

用例5:

假设开发者需要在电视上开发一款菜谱 App, 开发者期望用户的交互方式为:

我想做徽菜

下一页

换一批

随即电视上显示出四道徽菜的图片和文字,分别如下:

此时电视显示的菜谱
臭鲑鱼
鸡汁腊鱼
清蒸石鸡
问政山笋

用户接下来可能会说:

臭鲑鱼怎么做

我们将其抽象为一个自定义技能,其中语料如下:

{name}怎么做

由于用户不确定的操作和意图,每次电视上显示的菜谱名称均不相同,为了使得界面上向用户展示的信息,用户都可以语音交互的方式控制,我们选择使用动态实体(所见即可说)所见即可说的业务流程如下,作用域为当前用户,作用时间为当前会话,会话结束后,所见即可说实体立刻失效:

客户端获取信源信息
整理信源中的关键
调用所见即可说API接口上传数据
用户语音交互
会话结束失效

5.3.4 通配实体

开放实体中包含一种特殊的实体,称之为通配实体,用于配置不能穷举的技能语义槽。
如在搜索技能中,搜索 {chinaCity} 与搜索 {something},两者不同的是:chinaCity(中国城市)可以穷举,而 something 不可以穷举。因此在搜索 {something} 时,推荐使用通配实体。
通配实体可以匹配任意的1~20个字符。
注意:因通配实体的命中率过高,使用通配实体可能会降低其它意图和技能的命中概率,从而造成语义结果与预期不符。因此,在实体可以穷举时,请勿使用通配实体。

举例:

语料:提醒我 {time} 在 {location} 开会
例句:提醒我下午三点在A1楼1407开会
解析结果如下:
time: 15:00
wildcard: A1楼1407

操作步骤:

1. 填写基本信息

填写基本信息.png

2. 选择通配实体 wildcard

选择通配实体 wildcard.png

3. 输入最大最小限制,中英文数字均计为一个字符

字符限制.png

5.3.5 总结

静态实体 动态实体(应用级) 动态实体(用户级) 动态实体(自定义级) 动态实体(所见即可说)
作用域 ALL APPID 特定用户 某些用户 特定用户
作用时间 永久 永久 永久 永久 会话结束失效
SDK 是否提供修改接口 不提供 提供 提供 提供 提供

5.3.6 名词解释

实体名:

实体名称, namespace 下唯一

资源名:

实体下的资源名称,一个实体可以拥有最多五个资源,注意资源名称同样在 namespace 下唯一,推荐使用 实体名_资源名的方式命名。

维度:

资源的作用域

维度名:

仅自定义级的维度名需要开发者手动填写,应用级默认为 appid, 用户级默认为 userid。

主字段,从字段:

资源的存储路径,分为主字段和从字段,用于描述应用上传到云端的数据如何被AIUI抽取。例如上传联系人数据:

{"name":"刘德华","alias":"华仔"}

在这个例子中,主字段取值为“name”,从字段取值为“alias”。当用户说“打电话给华仔”,AIUI理解出来“华仔”是“刘德华”,会给出“操作:打电话,联系人:刘德华”的语义。从字段可以设置多个。

实体扩展:

对实体主名的扩展方式,例如针对联系人“李雪健老师”,用户说“打电话给李雪健”、“打电话给雪健老师”、“打电话给李老师”,均可给出“李雪健老师”的语义信息。扩展方式包括人名和地名的扩展(默认为不扩展),是专门对人名和地名的文本进行特殊的处理,来更好的提升语义理解的效果。

6 资源限制

在【我的技能】中,针对用户下每种资源的创建,存在数量上的限制,具体如下表所示:

开发版 高级版
技能 技能个数 10个 20个
一个技能下的意图数 20个 40个
一个意图下的提问语料数 100个 200个
一个技能下的槽位数 30个 60个
一个意图下的槽位数 20个 40个
问答库 问答库个数 10个 20个
一个问答对问题数 20个 40个
一个问答对答案数 10个 20个
一个问答库下的问答对数 普通问答对:10000个 普通问答对:20000个
问答库导入的文件大小/问答对数 文件大小:<5M 文件大小:<10M
问答对数:10000个 问答对数:20000个
问答库导入/导出次数 导入:10次/天 导入:30次/天
导出:10次/天 导出:30次/天
实体 实体个数 20个 40个
一个词条类实体下的词条数 10000个 20000个
实体导入的文件大小 <5M <10M
实体导入/导出次数 导入:10次/天 导入:30次/天
导出:10次/天 导出:30次/天
一个动态实体下的资源数 5个 5个

* 高级版可以通过购买 WebAPI 流量包的方式获得。SDK 用户可以联系商务提供。

如果当前限额不能满足您的需求,请提交工单进行商务申请。

7 讯飞魔飞智能麦克风

7.1 概述

讯飞魔飞SDK是与讯飞魔飞智能麦克风通讯的桥梁。

通过设备认证SDK,开发者可以完成注册、登录、注销、修改密码、找回密码、与讯飞魔飞智能麦克风设备的绑定,解绑,数据传递,控制等功能。

7.2 准备

7.2.1 获取安全码

安全码的组成规则为:包名+Android签名证书的SHA1值,例如:

包名:com.iflytek.morfei

SHA1:BB:0D:AC:74:D3:21:E1:43:67:71:9B:62:91:AF:A1:66:6E:44:5D:75

Android应用获取包名(packagename)

1、使用 Eclipse 开发

包名是Android应用程序本身在AndroidManifest.xml 中定义的名称,例如:1

2、使用 Android Studio 开发

包名需要在文件AndroidManifest.xml中查询 package,例如:2

Android签名证书的SHA1值获取方式:

第1步:运行CMD进入控制台

3

第2步:输入keytool -list -v -keystore E:/morfei.keystore,E:/morfei.keystore为开发者生成的签名证书的绝对路径,会得到三种指纹证书,选取SHA1类型的证书,其中keytool为jdk自带工具,例如:

45

安全码申请

登录http://aiui.xfyun.cn/,点击我的应用,点击安全码,如下图所示6

7.2.2 安全码集成

将生成的安全码添加到AndroidManifest中

7

7.2.3 权限

SDK完成功能需要联网权限,故集成是需要开发者在Manifest中声明如下权限:

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.CAMERA" />

7.2.4 依赖

DeviceAuth依赖如下:

compile 'com.squareup.retrofit2:retrofit:2.2.0'
compile 'com.squareup.retrofit2:converter-gson:2.2.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.2.2'

7.3 接口说明

SDK中主要操作类是DeviceAuthManager和Device。

7.3.1 DeviceAuthManager

DeviceAuthManager是对设备进行绑定、解绑、查找设备等操作的入口类,包含如下接口:

createDeviceAuthManager(Context context, AuthListener listener) //创建实例
void init(Map params) //初始化
void registerListener(AuthListener listener) //注册事件回调
void sendRequest(AuthRequest request) //发送请求
Device lookupDevice(String deviceID) //查找设备

通过调用sendRequest发送对应的请求消息,通过注册的AuthListener接收回复消息。

AuthListener定义如下:

interface AuthListener {
void onResponse(AuthResponse response);
}

7.3.2 Device

Device是对单个讯飞魔飞智能麦克风设备进行设备交互,数据传递的入口类,包含如下接口:

registerListener(DeviceListener listener)
void sendMessage(DeviceMessage message)
String getDeviceID()
BindStatus getBindStatus()

与DeviceAuthManager类似,通过DeviceListener接收设备的事件,通过sendMessage发送消息到设备。

DeviceListener定义如下:

interface DeviceListener {
void onEvent(DeviceEvent event);
}

7.4 操作

7.4.1 初始化

调用DeviceAuthManager的init(Map params)方法完成初始化操作,params需要包含AppID信息和AppKey信息,key分别为appid,appkey。

示例如下:

initParams.put("appid", "11111");
initParams.put("appkey", "abcde");
mDeviceAuthManager.init(initParams);

7.4.2 登录

通过DeviceAuthManager发送登录请求,请求构造示例如下:

AuthRequest authReq = new AuthRequest(AuthConstant.TYPE_REQUEST_THDLOGIN);
authReq.put("src", src);// 第三方云简称,值唯一
authReq.put("uid", uid);// 第三方云用户id或账号名
DeviceAuthManager.getAuthManager().sendRequest(authReq);

登录的结果会通过AuthListener回调,解析示例如下:

public void onResponse(AuthResponse response) {
switch (response.getResponseType()){
case AuthConstant.TYPE_RESPONSE_THDLOGIN:
boolean success = Boolean.valueOf(response.get(AuthConstant.KEY_SUCCESS));
String errorTip = response.get(AuthConstant.KEY_ERROR);
break;
}
}

7.4.3 注销

通过DeviceAuthManager发送注销请求,请求构造示例如下:

AuthRequest authReq = new AuthRequest(AuthConstant.TYPE_REQUEST_LOGOUT);
DeviceAuthManager.getAuthManager().sendRequest(authReq);

注销的结果会通过AuthListener回调,解析示例如下:

public void onResponse(AuthResponse response) {
switch (response.getResponseType()){
case AuthConstant.TYPE_RESPONSE_LOGOUT:
break;
}
}

7.4.4 刷新设备列表

通过DeviceAuthManager发送刷新设备列表请求,请求构造示例如下:

AuthRequest syncReqeust = new AuthRequest(AuthConstant.TYPE_REQUEST_SYNC_DEVICES);
mAuthManager.sendRequest(syncReqeust);

设备列表刷新的结果会通过AuthListener回调,解析示例如下:

public void onResponse(AuthResponse response) {
String deviceID = response.get(AuthConstant.KEY_DEVICE_ID);
switch (response.getResponseType()){
case AuthConstant.TYPE_RESPONSE_NEW_DEVICE:
//通过deviceID查找设备
Device device = mAuthManager.lookupDevice(deviceID);
break;
case AuthConstant.TYPE_RESPONSE_SYNC_FINISH:
boolean success = Boolean.valueOf(response.get(AuthConstant.KEY_SUCCESS));
String errorTip = response.get(AuthConstant.KEY_ERROR);
break;
}
}

7.4.5 绑定

通过DeviceAuthManager发送绑定请求,请求构造示例如下:

AuthRequest bindReq = new AuthRequest(AuthConstant.TYPE_REQUEST_BIND);
bindReq.put(AuthConstant.KEY_DEVICE_ID, mBindingDeviceID);//绑定的设备ID
bindReq.put(AuthConstant.KEY_QRCODE, qrcode); //绑定WIFIMIC设备上二维码信息
mAuthManager.sendRequest(bindReq);

绑定的结果通过AuthListener的TYPE_RESPONSE_BIND解析,示例如下:

public void onResponse(AuthResponse response) {
String deviceID = response.get(AuthConstant.KEY_DEVICE_ID);
switch (response.getResponseType()){
case AuthConstant.TYPE_RESPONSE_BIND:
boolean success = response.get(AuthConstant.KEY_SUCCESS);
String errorTip = response.get(AuthConstant.KEY_ERROR);
break;
}
}

7.4.6 解绑

通过DeviceAuthManager发送解绑请求,请求构造示例如下:

AuthRequest unbindReq = new AuthRequest(AuthConstant.TYPE_REQUEST_UNBIND);
unbindReq.put(AuthConstant.KEY_DEVICE_ID, device.getDeviceID());//解绑设备ID
mAuthManager.sendRequest(unbindReq);

绑定的结果通过AuthListener的TYPE_RESPONSE_UNBIND解析,示例如下:

public void onResponse(AuthResponse response) {
String deviceID = response.get(AuthConstant.KEY_DEVICE_ID);
switch (response.getResponseType()){
case AuthConstant.TYPE_RESPONSE_UNBIND:
boolean success = response.get(AuthConstant.KEY_SUCCESS);
String errorTip = response.get(AuthConstant.KEY_ERROR);
break;
}
}

7.4.7 设备操作

通过Device注册DeviceListener接收设备唤醒等消息,示例如下:

public void onEvent(final DeviceEvent event) {
switch (event.getEventType()){
//唤醒
case DeviceConstant.EVENT_DEVICE_WAKEUP:
break;
//设备断开
case DeviceConstant.EVENT_DEVICE_DISCONNECT:
break;
}
}

7.4.8 获取蓝牙列表

通过Device发送获取蓝牙列表请求,请求构造示例如下:

DeviceMessage deviceMessage = new DeviceMessage(DeviceConstant.TYPE_GET_BT_DEVICES_REQUEST, 0, 0, 0, 0);
device.sendMessage(deviceMessage);

蓝牙列表的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_GET_BT_DEVICES_RESPONSE:
String response = message.getString("bluetoothDevices");
break;
}
}

7.4.9 连接蓝牙

通过Device发送连接蓝牙请求,请求构造示例如下:

DeviceMessage deviceMessage = new DeviceMessage(DeviceConstant.TYPE_CONN_BT_DEVICES_REQUEST, 0, 0, 0, 0);
deviceMessage.put("mac", mac);
device.sendMessage(deviceMessage);

连接蓝牙的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_CONN_BT_DEVICES_RESPONSE:
int arg1 = message.getArg1();
if (arg1 == 0) {
//连接成功
}
break;
}
}

7.4.10 断开蓝牙连接

通过Device发送断开蓝牙连接请求,请求构造示例如下:

DeviceMessage deviceMessage = new DeviceMessage(DeviceConstant.TYPE_UNCONN_BT_DEVICES_REQUEST, 0, 0, 0, 0);
deviceMessage.put("mac", mac);
device.sendMessage(deviceMessage);

断开蓝牙连接的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_UNCONN_BT_DEVICES_RESPONSE:
int _arg1 = message.getArg1();
if (_arg1 == 0) {
//断开连接成功
}
break;
}
}

7.4.11 获取设备连接状态

通过Device发送获取设备状态请求,请求构造示例如下:

DeviceMessage deviceMessage = new DeviceMessage(DeviceConstant.TYPE_GET_STATE_REQUEST, 0, 0, 0, 0);
device.sendMessage(deviceMessage);

获取设备状态的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_GET_STATE_RESPONSE:
int state = message.getInt("state");
// state 2 休眠 3 唤醒
break;
}
}

7.4.12 OTA升级检查

通过Device发送ota升级检查请求,请求构造示例如下:

DeviceMessage deviceMessage = new DeviceMessage(DeviceConstant.TYPE_OTA_UPDATE_CHECKER_REQUEST, 0, 0, 0, 0);
deviceMessage.put("projectId", projectId);
device.sendMessage(deviceMessage);

ota升级检查的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_OTA_UPDATE_CHECKER_RESPONSE:
String checkResponse = message.getString("checkResponse");
// 0:不需要更新 1:有新版本,已经下载过了,直接安装 2:有新版本,需要下载 3:正在下载 // 4:正在安装
break;
}
}

7.4.13 OTA升级下载

通过Device发送ota升级下载请求,请求构造示例如下:

DeviceMessage deviceMessage = new DeviceMessage(DeviceConstant.TYPE_OTA_UPDATE_DOWNLOAD_REQUEST, 0, 0, 0, 0);
device.sendMessage(deviceMessage);

ota升级下载的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_OTA_UPDATE_DOWNLOAD_RESPONSE:
int progress = message.getInt("progress");
// progress 下载进度
break;
}
}

7.4.14 OTA升级下载完成

ota升级下载完成的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_OTA_UPDATE_DOWNLOADCOMPLETE_RESPONSE:
// 下载完成
break;
}
}

7.4.15 OTA升级安装

通过Device发送ota升级安装请求,请求构造示例如下:

DeviceMessage deviceMessage = new DeviceMessage(DeviceConstant.TYPE_OTA_UPDATE_INSTALL_REQUEST, 0, 0, 0, 0);
device.sendMessage(deviceMessage);

ota升级安装的结果通过DeviceListener回调,示例如下:

public void onEvent(DeviceEvent event) {
Message message = event.getImpl();
switch (event.getEventType()){
case DeviceConstant.TYPE_OTA_UPDATE_INSTALL_RESPONSE:
String isSuccess = message.getString("isSuccess");
// isSuccess 0 安装成功 1 安装失败
break;
}
}

7.5 注意事项

7.5.1 SERVICE_BIND_SUCCESS

DeviceAuthSDK通过与AuthService通讯工作的,所以程序必须在AuthListener接收到TYPE_RESPONSE_SERVICE_BIND_SUCCESS之后,
才能有登录,解绑等操作。

AuthListener在接收到TYPE_RESPONSE_SERVICE_BIND_DIED之后,说明与AuthService的连接断开,
必须重新创建新的DeviceAuthManager实例才能继续操作。

7.5.2 错误码描述

错误码 错误码err信息
10107 APPID_INVALID
10108 PARAM_LOST
10109 CHECK_SIGNATURE_FAILED
10110 TOKEN_INVALID
10111 TOKEN_EXPIRED
10112 CHECK_FAILDED_ERROR
10113 MOBILE_INVAILED_ERROR
10114 SMS_CODE_INVAILED_ERROR
10115 SMS_CODE_EXPIRED_ERROR
10116 MOBILE_REGISTER_REPEAT_ERROR
10117 MOBILE_UNREGISTERED_ERROR
10118 REFRESH_USER_INFO_FAILED
10119 REQUEST_MONGODB_FAILED
10120 READ_HTTP_BODY_FAILED
10121 UNMARSHAL_HTTPBODY_FAILED
10122 PARAM_INVALID
10123 REQUEST_WEBAUTH_ERROR
10124 WEBAUTH_ERROR
10125 REQUEST_MYSQL_ERROR
10126 APP_LOGOUT_FAILDED_ERROR
10127 APP_LOGIN_FAILDED_ERROR
10128 REFRESH_PWD_FAILDED_ERROR
10129 REFISTER_FAILDED_ERROR
10130 REQUEST_SMS_CHECK_ERROR
10131 QUERY_FAILED_ERROR
10132 APPKEY_INVAILED_FAILED
10133 UPDATE_SMSCODE_FAILED
10134 请求版本更新信息出错
10135 安装包不存在
10136 安装包出错