1. 概述
本文旨在向开发者介绍灵云SDK的基本概念和使用步骤,便于开发者快速集成灵云SDK到自身的应用中。
2. 名词解释
2.1 系统模块
灵云系统模块提供统一的配置管理、授权管理、本地资源管理等通用操作,具体包含以下功能:
功能名 | 描述 |
---|---|
初始化/终止灵云系统 | 通过hci_init 、hci_release 等函数实现。在使用灵云各项能力之前,都必须使用 hci_init() 函数进行灵云系统的初始化。使用完毕, 需要使用 hci_release() 进行释放。 |
获取授权文件 | 授权文件中规定了此应用可以使用的灵云能力, 以及到期的时间。可以通过 hci_check_auth() 函数更新授权文件。 |
获取授权过期时间 | 通过 hci_get_auth_expire_time() 获得。 |
获取可用能力列表 | 通过 hci_get_capability_list() 获得当前授权文件中可用的能力列表,以及每种能力的一些属性。 |
获得 SDK 版本 | 通过hci_get_sdk_version() 获得 |
上传历史数据 | 当采用本地识别能力时,灵云 SDK 会将用户的请求数据(包括用户的确认结果)缓存在本地, 开发者可以将这些数据发送到云端(通过hci_upload_user_history ),来帮助灵云学习用户的使用习惯,以便建立针对此用户的个性化模型。 |
注:上述说明中的函数均来自 C/C++ 版,其他语言中会由于语言的原因有不一样的地方。
2.2 用户模块
灵云 SDK 提供了一套机制将开发者自身的信息绑定到灵云平台上来。一方面用户信息可以应用在 VPR, FRP, AFR 等生物特征的识别上,另一方面可以在多个设备上使用同一个用户进行访问,对请求进行关联。用户和用户组的具体作用有:
- 通过
hci_set_current_userid
函数来指定当前用户,从此收集的用户行为数据便和特定用户相关联,以便灵云平台整理用户习惯,提供更人性化的服务 - 当进行 VPR, FRP, AFR 等识别时,需要通过用户组来指定识别用户的范围
功能名 | 描述 |
---|---|
管理用户组 | 通过 hci_create_group 、hci_delete_group 、hci_get_grouplist 实现 |
管理组中的用户 | 通过 hci_add_user 、hci_remove_user 、hci_get_userlist 实现 |
设置当前用户 | 通过 hci_set_current_userid 实现 |
删除用户 | hci_delete_user 、hci_delete_model |
释放数据模型 | hci_free_group_list 、hci_free_user_list |
说明:
hci_add_user
(HciCloudUser.hciAddUser
)函数含有创建用户的功能,所以没有专门的创建用户API
2.3 其他内容
能力API
提供各种不同的智能人机交互(HCI)技术的操作,如图像识别、语音合成等
扩展API
提供构建在灵云能力 API 之上的,更为简单方便的调用接口,一般和硬件设备结合,隐藏具体设备操作
云端能力
由灵云服务器来提供运算或识别结果的运行模式
本地能力
通过本地运算来得到结果的运行模式
3. 使用灵云 SDK
使用灵云 SDK 的步骤如下图:
下面展开讲述这个过程。
3.1 添加安卓用户权限
在Android应用中,需要启用某些用户权限才能正常使用灵云SDK。在工程 AndroidManifest.xml
文件中添加如下权限:
<!—通常需要设置一些sd卡路径(例如日志路径)为可写,因此需要能够写外部存储 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!—以下访问网络的权限均需要打开-->
<!--连接网络权限,用于执行云端能力 -->
<uses-permission android:name="android.permission.INTERNET" />
<!--读取网络信息状态 -->
<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"/>
3.2 初始化灵云系统
Android代码
import com.sinovoice.hcicloudsdk.api.HciCloudSys; // ......... HciCloudSys.hciInit( "developerKey=01234567890, appKey=1234abcd,cloudUrl=api.hcicloud.com:8888, authPath=/storage/emulated/0/myApp/auth, logFileSize=500,logLevel=5, logFilePath=/storage/emulated/0/myApp/log,logFileCount=10", context);
C++代码
#include "hci_sys.h" // ......... char * pszConfig = "developerKey=01234567890,appKey=1234abcd, \ cloudUrl=http://api.hcicloud.com:8888, \ authPath=document, \ logFileSize=500,logLevel=5, \ logFilePath=document/log/,logFileCount=10"; HCI_ERR_CODE errCode = hci_init(pszConfig); if (errCode != HCI_ERR_NONE) { // 失败处理 }
iOS代码
HCI_ERR_CODE errCode = HCI_ERR_NONE; // appkey, developerKey, cloudUrl, authPath为必填项。 // 其他可配置信息请查询灵云SDK开发手册hci_init函数说明。 NSString *appkey = @""; // 开发者社区申请所得 NSString *developerKey = @""; // 开发者社区申请所得 NSString *cloudUrl = @""; // 开发者社区申请所得 NSString *authPath = @""; // 授权文件所在路径,一般设置为沙盒 Document 路径 NSString *config = [NSString stringWithFormat: @"appkey=%@,developerKey=%@,cloudUrl=%@,authPath=%@", appkey, developerKey, cloudUrl, authPath]; errCode = hci_init(config.UTF8String); if (errCode != HCI_ERR_NONE && errCode != HCI_ERR_SYS_ALREADY_INIT) { NSLog(@"hci_init failed, error: %@", errCode); } else { NSLog(@"hci_init success"); }
在灵云 SDK 中,配置以字符串的形式提供,组织成“字段=值”的形式,多个字段间以逗号隔开。字段名不区分大小写。初始化函数常用配置内容如下表
字段 | 取值或示例 | 含义 | 详细说明 |
---|---|---|---|
developerKey | 字符串 | 开发者秘钥,必填 | 由灵云开发者社区提供 |
appKey | 字符串 | 应用秘钥,必填 | 由灵云开发者社区提供 |
cloudUrl | 字符串,如“api.hcicloud.com:8888” | 灵云服务器url,必填 | 由捷通华声提供。即使只使用本地的端能力,也需要这个地址去获取授权文件 |
authPath | 字符串,如:./auth/ | 授权文件存放路径,必填 | 用户必须保证此目录具有可读可写权限 |
udidType | 字符串 | 获取设备唯一ID的方式,选填 | 不同的平台有不同的选项,如果不设置此项就按照默认的方式处理。 |
logFilePath | 字符串,如:./log/ | 日志文件存放路径,选填 | 如果不设置或设置为空,就不生成日志 |
logFileSize | 正整数 | 日志文件大小(以K为单位),选填 | 默认32 |
logFileCount | 正整数 | 保存日志文件数目,选填 | 默认5 |
logLevel | 正整数 | 日志等级,选填 | 5为最详细,1为最粗略,默认1 |
对于 java 代码,SDK还提供了InitParam类来协助用户构造配置字符串:
InitParam initparam = new InitParam();
initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, "/storage/emulated/0/myApp/auth");
initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, "/api.hcicloud.com:8888");
// ..............
String strConfig = initParam.getStringConfig();
3.3 获取授权
在初次使用灵云系统时,灵云系统初始化函数会下载并保存授权文件到本地。以后系统模块使用会直接使用此文件验证授权, 不需要再到云端下载。但授权文件都有一个过期时间,一旦过期了,在一周的宽限期内,仍可以继续使用相应能力;但超出宽限期,将无法再使用相应的能力。因此在过期时间到了之后必须及时到云端更新授权文件。建议用户在灵云初始化之后添加检查并更新授权文件的逻辑,示例如下:
Android代码
private int checkAuthAndUpdateAuth() { // 获取系统授权到期时间 int initResult; AuthExpireTime objExpireTime = new AuthExpireTime(); initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime); if (initResult == HciErrorCode.HCI_ERR_NONE) { // 显示授权日期,如用户不需要关注该值,此处代码可忽略 Date date = new Date(objExpireTime.getExpireTime() * 1000); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA); Log.i(TAG, "expire time: " + sdf.format(date)); if (objExpireTime.getExpireTime() * 1000 > System .currentTimeMillis()) { // 已经成功获取了授权,并且距离授权到期有充足的时间(>7天) Log.i(TAG, "checkAuth success"); return initResult; } } // 获取过期时间失败或者已经过期,重新获取授权文件 initResult = HciCloudSys.hciCheckAuth(); if (initResult == HciErrorCode.HCI_ERR_NONE) { Log.i(TAG, "checkAuth success"); return initResult; } else { Log.e(TAG, "checkAuth failed: " + initResult); return initResult; } }
C++代码
int checkAuthAndUpdateAuth() { int64 expire_time; int64 current_time = (int64)time( NULL ); HCI_ERR_CODE err_code = hci_get_auth_expire_time( &expire_time ); if( err_code == HCI_ERR_NONE ) { // 获取成功则判断是否过期 if( expire_time > current_time ) { // 没有过期 printf( "auth can use continue\n" ); return true; } } // 获取过期时间失败或已经过期,手动调用更新授权 err_code = hci_check_auth(); if( err_code == HCI_ERR_NONE ) { //更新成功 printf( "check auth success \n" ); return true; } else { //更新失败 printf( "check auth return (%d:%s)\n", err_code ,hci_get_error_info(err_code)); return false; } }
iOS代码
// 获取过期时间 int64 expireTime; int64 currentTime = (int64)time(NULL); HCI_ERR_CODE errCode = hci_get_auth_expire_time(&expireTime); if (errCode == HCI_ERR_NONE) { if (expireTime < currentTime) { errCode = hci_check_auth(); if(errCode == HCI_ERR_NONE){ NSLog(@"check auth success"); return YES; }else{ NSLog(@"check auth failed, error: %@", errCode); return NO; } }else{ //没有过期 NSLog(@"auth can use continue"); return YES; } } //读取授权文件出现错误 else if(errCode == HCI_ERR_SYS_AUTHFILE_INVALID){ errCode = hci_check_auth(); if(errCode == HCI_ERR_NONE){ NSLog(@"check auth success"); return YES; }else{ NSLog(@"check auth failed, error: %@", errCode); return NO; } }else{ NSLog(@"check auth failed, error: %@", errCode); return NO; }
3.4 设置当前用户(可选)
设置了当前用户,就可以让每次请求和具体用户相关,这样在不同的设备上就可以考虑共享用户。关于用户相关接口参见 用户模块。
Android代码
HciCloudUser.hciSetCurrentUser("user1");
C++代码
hci_set_current_userid("user1");
iOS代码
hci_set_current_userid("user1");
3.5 初始化灵云能力
初始化能力API的形式为hci+能力名字+Init,例如:
Android代码
HciCloudAsr.hciAsrInit(); HciCloudTts.hciTtsInit();
C++代码
hci_asr_init(); hci_tts_init();
iOS代码
hci_asr_init(); hci_tts_init();
SDK会在这类函数的运行过程中检查能力是否被授权使用,加载相应的动态库和资源文件。如果我们使用的是本地能力,需要使用 dataPath 配置项指定本地资源(模型库文件)所在的路径。 这样系统会检查一下所用到的本地能力的资源是否完整可用。
3.6 开启灵云会话(Session)
创建 Session 的API的形式为hci+能力名字+SessionStart。以 TTS 为例,创建 Session 的代码如下:
Android代码
TtsConfig sessionConfig = new TtsConfig(); sessionConfig.addParam(TtsConfig.SessionConfig.PARAM_KEY_CAP_KEY, “tts.cloud.xixi”); Session session = new Session(); int errCode = HciCloudTts.hciTtsSessionStart(sessionConfig.getStringConfig(), session); if (HciErrorCode.HCI_ERR_NONE != errCode) { ShowMessage("hciTtsSessionStart error:" + HciCloudSys.hciGetErrorInfo(errCode)); return; }
C++代码
HCI_ERR_CODE err_code = HCI_ERR_NONE; string session_config = "capkey=tts.cloud.xixi"; int session_id = -1; err_code = hci_tts_session_start( session_config.c_str(), &session_id ); if( err_code != HCI_ERR_NONE ) { printf("hci_tts_session_start return (%d:%s) \n",err_code,hci_get_error_info(err_code)); return; }
iOS代码
HCI_ERR_CODE err_code = HCI_ERR_NONE; NSString *session_config = @"capkey=tts.cloud.xixi"; int session_id = -1; err_code = hci_tts_session_start( session_config.UTF8String, &session_id ); if( err_code != HCI_ERR_NONE ) { NSLog(@"hci_tts_session_start return (%d:%s) \n",err_code,hci_get_error_info(err_code)); return; }
3.7 使用灵云能力
灵云能力 API 命名方式是hci+能力名字+行为名字,如hciTtsSynth
(语音合成), hciHwrRecog
(手写识别)、hciHwrAssociateWords
(获取联想词);无论哪种 API,第一个参数必然是上一节创建出来的 Session,例如:
Android代码
HciCloudTts.hciTtsSynthEx(session, synthData, "", mTtsSynthCallback); HciCloudAsr.hciAsrRecog(session, voiceData, "encode=opus", "", recogResult);
C++代码
hci_tts_synth( nSessionId, (char*)synthData, NULL, TtsSynthCallbackFunction, userData ); hci_asr_recog( nSessionId, voiceData, voiceDataSize, NULL, NULL, &asrResult );
iOS代码
hci_tts_synth( nSessionId, (char*)synthData, NULL, TtsSynthCallbackFunction, userData ); hci_asr_recog( nSessionId, voiceData, voiceDataSize, NULL, NULL, &asrResult );
3.8 关闭灵云会话
会话使用完后要释放会话。释放会话的API形式是hci+能力名+SessionStop(Session session),例如:
Android代码
HciCloudAsr.hciAsrSessionStop(session); HciCloudTts.hciTtsSessionStop(session);
C++代码
hci_asr_session_stop(session); hci_tts_session_stop(session);
iOS代码
hci_asr_session_stop(session); hci_tts_session_stop(session);
3.9 终止灵云能力
当不再使用灵云能力时,调用能力反初始化 API 来释放其资源。反初始化 API 的形式是hc+能力名+Release(),例如:
Android代码
HciCloudAsr.hciAsrRelease(); HciCloudTts.hciTtsRelease();
C++代码
hci_asr_release(); hci_tts_release();
iOS代码
hci_asr_release(); hci_tts_release();
3.10 终止灵云系统
Android代码
HciCloudSys.hciRelease();
C++代码
hci_release();
iOS代码
hci_release();
3.11 上传历史数据
上传历史数据可以帮助灵云平台收集用户的使用习惯,建立针对此用户的个性化模型,提高用户体验。
Android代码
HciCloudSys.hciUploadUserHistory();
C++代码
hci_upload_user_history();
iOS代码
hci_upload_user_history();
4 FAQ
- Q: 我运行你们的 SDK 报 19 号错误:START LOG FAILED, 应该如何解决?
出现此问题,一般由两种原因造成。
- 工程文件里引入了中文路径,导致SDK启动时,读写对应的日志路径报错。
- 日志文件定义的路径由于权限问题不可读写,比如在 Android 平台上运行时,没有 WRITE_EXTERNAL_STORAGE的权限。
Q: 我运行你们的 SDK 报 23 号错误:LOAD_FUNCTION_FROM_DLL FAILED,应该如何解决? 这种情况,通常是由于缺库。最常见的场景是使用本地能力的 capkey,如
tts.local.synth
,asr.local.grammar.v4
等,没有将库文件对应组入(我们 SDK 示例程序,与 example 同层有全套库文件,示例程序内默认只组入了云端库),将相关库补齐即可使用。此外,由于 OCR,VPR 等能力引用了第三方的 OPENCV, MKL 库,因此如果第三方库没有拷入,也会导致此问题。Q: 我运行你们的 SDK 报 14 号错误:LOCAL_RES_MISSING,应该如何解决? 本地能力常会遇到此问题,此问题是由于没有组入对应的本地资源文件。请在我们开发者社区下载需求的本地资源(如 TTS 音库,OCR 本地模板、ASR 本地模型)等,并将资源文件组入代码 datapath 指定路径,然后再次尝试运行程序。
Q: 我运行你们的 SDK 报 11 号错误:SERVICE_RESPONSE_FAILED ,应该如何解决? 此问题原因较为复杂,可能是传入的参数问题与服务器不匹配,如调用私有云时,没有传入 property 等配置项。也可能是服务端内部的返回原因,请联系技术支持排查。
Q: 我运行你们的 SDK 报 3 号错误:CONFIG_INVALID,应该如何解决? 出现此问题,应该详细检查所有接口传入的配置串。目前经常发现的问题是,用户使用我们单能力的 SDK,如 TTS SDK,然后在其中传入了 ASR,OCR,HWR 等能力的 capkey,就会返回此问题。请联系技术支持详细排查。
Q: 我运行你们的SDK报 7 号错误:CONFIG_UNSUPPORT ,应该如何解决? 与 号错误类似,还是配置串问题,7 号错误原因为传入了不支持的配置串。请仔细检查各接口传入的所有配置串,并联系技术支持排查。
Q: 我运行你们的SDK报 9 号错误: SERVICE_TIMEOUT ,应该如何解决? 这个是因为您请求我们服务器到返回结果的时间,超过了上限。请检查网络环境相关的原因,并协助提供日志。
Q: 我运行你们的 SDK 报 5 号错误: CAPKEY_NOT_MATCH ,应该如何解决? 这个是因为您在能力初始化时,传入的 capkey 和引擎不匹配。比如您使用的是 ASR SDK,但是传入了 TTS 的 capkey,就会报这个错误。请确认 SDK 和需要运行的能力是相互匹配的。
Q: 我运行你们的 SDK 报 16 号错误: SESSION_INVALID ,应该如何解决? 这个需要检查详细的代码调用过程,调用每个能力核心接口时,都是需要传入
sessionid
的,如果在sessionstart
的时候,已经发生了错误,或者使用的id,并不是sessionstart
时候创建的,就会返回此错误,请联系技术支持排查。Q: 我运行你们的 SDK 报 0 号错误: ERROR NONE,应该如何解决? SDK 报 0 号错误, ERROR NONE,代表执行成功,请您继续后续的集成。