1. 概述

本文旨在向开发者介绍灵云SDK的基本概念和使用步骤,便于开发者快速集成灵云SDK到自身的应用中。

2. 名词解释

2.1 系统模块

灵云系统模块提供统一的配置管理、授权管理、本地资源管理等通用操作,具体包含以下功能:

功能名 描述
初始化/终止灵云系统 通过hci_inithci_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_grouphci_delete_grouphci_get_grouplist 实现
管理组中的用户 通过 hci_add_userhci_remove_userhci_get_userlist实现
设置当前用户 通过 hci_set_current_userid 实现
删除用户 hci_delete_userhci_delete_model
释放数据模型 hci_free_group_listhci_free_user_list

说明:

  • hci_add_userHciCloudUser.hciAddUser)函数含有创建用户的功能,所以没有专门的创建用户API

2.3 其他内容

能力API

提供各种不同的智能人机交互(HCI)技术的操作,如图像识别、语音合成等

扩展API

提供构建在灵云能力 API 之上的,更为简单方便的调用接口,一般和硬件设备结合,隐藏具体设备操作

云端能力

由灵云服务器来提供运算或识别结果的运行模式

本地能力

通过本地运算来得到结果的运行模式

3. 使用灵云 SDK

使用灵云 SDK 的步骤如下图: image

下面展开讲述这个过程。

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, 应该如何解决? 出现此问题,一般由两种原因造成。
    1. 工程文件里引入了中文路径,导致SDK启动时,读写对应的日志路径报错。
    2. 日志文件定义的路径由于权限问题不可读写,比如在 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,代表执行成功,请您继续后续的集成。

results matching ""

    No results matching ""