1. 概述
键盘输入(Keyboard),简称KB,在最少输入、最大时间内输入理想的文本。支持中文,外文,韩文,日文等识别,同时支持多种键盘(T9,Qwerty以及容错键盘)以及多种输入模式(拼音,五笔,笔画等)。
本文档旨在讲解如何快速地集成灵云KB功能到开发者应用中。关于各服务接口更详细的说明,请参考灵云SDK开发手册。在集成过程中如有疑问,可登录灵云开发者论坛,查找答案或与其他开发者交流。
1.1 概念解释
对指南中涉及的名词作简要描述,使开发者在阅读开发指南时,对此有一些大致的了解和预备知识的了解。 如:
名称 | 说明 |
---|---|
Session | Session用来标记一个能力运行过程的上下文。一个应用最多可同时创建的Session数受到授权的限制 |
本地能力 | 通过本地运算来得到识别结果的方式。使用本地能力需要加上hci_kb_local_recog模块和本地资源文件(目前KB只提供本地能力) |
音节容错 | 中文识别支持音节容错设置,即可以将容易混淆的音节进行设置,以此提高输入的识别率。 |
1.2 能力定义(capkey)
capkey | 所需本地资源文件 |
---|---|
kb.local.recog | kb.dic kb.conf |
1.3 识别流程
2. 能力使用说明
2.1 准备工作
下载键盘输入SDK并解压缩。
请下载相应资源包并解压缩。
2.2 使用Android版SDK
2.2.1 库目录文件介绍
jar包文件
- hcicloud-5.0.jar
必选模块
- libhci_curl.so
- libhci_sys.so
- libhci_sys_jni.so
- libhci_kb.so
- libhci_kb_jni.so
- libstlport_shared.so
本地识别
- libhci_kb_local_recog.so
2.2.2 添加用户权限
在工程 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"/>
<!--以下访问权限可选-->
<!--手机定位信息-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
2.3 使用C++版SDK
必选模块
- libhci_curl.dll
- hci_sys.dll
- hci_kb.dll
本地识别
- hci_kb_local_recog.dll
2.4 使用iOS版SDK
必选模块
- libcurl_device_simulator_iOS5.1.1.a
- libhci_sys_device_simulator_iOS5.1.1.a
- libhci_kb_device_simulator_iOS5.1.1.a
本地识别
- libhci_kb_local_recog_device_simulator_iOS5.1.1.a
适配器选择(只选其一)
- libhci_kb_only_local_adapter_device_simulator_iOS5.1.1.a(只使用本地能力)
3. 能力集成说明
本章节主要讲述KB能力的集成过程,开发者可根据本章内容完成KB能力的简单调用。本章节以本地识别为例,讲述KB能力的集成调用流程,调用顺序参考识别流程。
3.1 通用模块初始化
在调用KB能力之前,需要初始化灵云SDK的通用模块。详见灵云SDK开发手册
Android示例代码
// 创建初始化参数辅助类
InitParam initparam = new InitParam();
// 授权文件所在路径,此项必填
String authDirPath = context.getFilesDir().getAbsolutePath();;
initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);
// 灵云云服务的接口地址,此项必填
initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, "http://api.hcicloud.com:8888");
// 开发者密钥,此项必填,由捷通华声提供
initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, "01234567890");
// 应用程序序号,此项必填,由捷通华声提供
initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, "1234abcd");
// 日志的路径,可选,如果不传或者为空则不生成日志
String logDirPath = "/storage/emulated/0/sinovoice/com.sinovoice.example/log";
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logDirPath);
//日志等级,0=无,1=错误,2=警告,3=信息,4=细节,5=调试
//SDK将输出小于等于logLevel的日志信息
initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");
// 灵云系统初始化
// 第二个参数在Android平台下,必须为当前的Context
int errCode = HciCloudSys.hciInit(initparam.getStringConfig(), this);
if(errCode != HciErrorCode.HCI_ERR_NONE) {
// "系统初始化失败"
return;
}
C++示例代码
HCI_ERR_CODE err_code = HCI_ERR_NONE;
//配置串是由"字段=值"的形式给出的一个字符串,多个字段之间以','隔开。字段名不分大小写。
string init_config = "";
//灵云应用序号
init_config += "appKey=1234abcd";
//灵云开发者密钥
init_config += ",developerKey=1234567890";
//灵云云服务的接口地址
init_config += ",cloudUrl=http://api.hcicloud.com:8888";
//授权文件所在路径,保证可写
init_config += ",authpath=../../bin";
//日志的路径
init_config += ",logfilepath=../../bin";
//日志的等级
init_config += ",loglevel=5";
//日志文件的大小
init_config += ",logfilesize=512";
//其他配置使用默认值,不再添加,如果想设置可以参考开发手册
err_code = hci_init( init_config.c_str() );
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: %d", errCode);
} else {
NSLog(@"hci_init success");
}
常见errcode,详见灵云SDK开发手册
3.2 授权检测
在初始化灵云SDK的通用模块后,还需要调用授权检测函数获取云端授权。
在初始化灵云SDK的通用模块后,还需要调用授权检测函数获取云端授权。
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()) {
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++示例代码
//获取过期时间
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)\n", 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.3 KB初始化
Android示例代码
// 创建初始化参数辅助类
KbInitParam initParam = new KbInitParam();
// 设置本地资源库的路径
initParam.addParam(KbInitParam.PARAM_KEY_DATA_PATH,
"/storage/emulated/0/sinovoice/com.sinovoice.example/data");
// 使用本地识别能力
initParam.addParam(KbInitParam.PARAM_KEY_INIT_CAP_KEYS, "kb.local.recog");
// 初始化KB能力
errCode = HciCloudKb.hciKbInit(initParam.getStringConfig());
C++示例代码
char * pszHwrInitConfig = "dataPath=../../data,initCapKeys=kb.local.recog";
errCode = hci_kb_init(pszHwrInitConfig);
if (err_code != HCI_ERR_NONE)
{
printf("hci_kb_init return (%d) \n",err_code);
return;
}
printf( "hci_kb_init success\n" );
iOS示例代码
//本地能力所需本地资源所在路径
NSString *dataPath = [[NSBundle mainBundle] pathForResource:@"data" ofType:Nil];
//initCapKeys为必填项。其他可配置信息请查询开发手册hci_kb_init函数说明。
//键盘输入(KB)所需使用的能力列表,可以包含多种能力,用';'分号隔开
NSString *initCapKeys = @"kb.local.recog";
NSString *config = [NSString stringWithFormat:@"initCapKeys = %@,dataPath = %@",
initCapKeys,dataPath];
HCI_ERR_CODE errCode = HCI_ERR_NONE;
errCode = hci_kb_init(config.UTF8String);
if (errCode != HCI_ERR_NONE){
NSLog(@"hci_kb_init failed, error:%@", errCode);
eturn NO;
}
NSLog(@"hci_kb_init success");
return YES;
常见errcode,详见灵云SDK开发手册 对于使用本地多能力时,可以使用initCapKeys传入需要使用的所有能力,以';'隔开。 initCapKeys的作用是告知SDK,需要预先准备哪些能力并提前加载对应的库资源,提高执行效率。
以HWR能力为例:
Android示例代码
initParam.addParam(HwrInitParam.PARAM_KEY_INIT_CAP_KEYS,
"hwr.local.letter;hwr.local.freestylus;hwr.local.associateword");
C++示例代码
//HWR 初始化
string hwr_init_config = "dataPath=";
hwr_init_config += data_path;
hwr_init_config += ",initCapkeys=";
hwr_init_config += "hwr.local.letter;hwr.local.freestylus;hwr.local.associateword";
iOS示例代码
//本地能力所需本地资源所在路径
NSString *dataPath = [[NSBundle mainBundle] pathForResource:@"data" ofType:Nil];
//initCapKeys为必填项。其他可配置信息请查询开发手册hci_hwr_init函数说明。
NSString *initCapKeys = @"hwr.local.letter;hwr.local.freestylus;hwr.local.associateword";
NSString *config = [NSString stringWithFormat:@"initCapKeys = %@,dataPath = %@",
initCapKeys,dataPath];
3.4 开启会话(session)
KB 是通过会话(session)来管理识别过程的。在KB能力初始化成功之后,需要通过开启识别会话来完成识别。详见灵云SDK开发手册
Android示例代码
Session session = new Session();
KbConfig sessionConfig = new KbConfig();
sessionConfig.addParam(KbConfig.SessionConfig.PARAM_KEY_CAP_KEY, "kb.local.recog");
// 开启会话
errCode = HciCloudKb.hciKbSessionStart(sessionConfig.getStringConfig(), session);
C++示例代码
int nSessionId = 0;
char * pszSessionConfig = "capKey=kb.local.recog";
errCode = hci_kb_session_start(pszSessionConfig, &nSessionId);
if( err_code != HCI_ERR_NONE )
{
printf( "hci_kb_session_start return (%d)\n", err_code);
return false;
}
iOS示例代码
// 开启session
HCI_ERR_CODE errCode = HCI_ERR_NONE;
NSString *config = @"capKey=kb.local.recog";
int sessionID; // 开启会话成功后,会返回的会话ID
errCode = hci_kb_session_start(config.UTF8String, &sessionID);
if (errCode != HCI_ERR_NONE){
NSLog(@"hci_kb_session_start failed, error:%@", errCode);
return NO;
}
NSLog(@"hci_kb_session_start success");
return YES;
3.5 输入识别
在启动会话(session)成功后,即可可以进行 KB的输入识别。配置参数详见灵云SDK开发手册
Android示例代码
KbConfig recogConfig = new KbConfig();
//设置输入模式,以"inputMode=pinyin"中文输入模式为例
recogConfig.addParam(KbConfig.InputConfig.PARAM_KEY_INPUT_MODE, "pinyin");
KbQueryInfo queryInfo = new KbQueryInfo();
KbRecogResult recogResult = new KbRecogResult();
//设置查询内容
queryInfo.setQuery("nichidaolema");
queryInfo.setSlideInfoItemCount(0);
queryInfo.setSlideInfoItemList(null);
queryInfo.setSelectedItemCount(0);
queryInfo.setQuerySelectedItemList(null);
errCode = HciCloudKb.hciKbRecog(session,
recogConfig.getStringConfig(),
queryInfo,
recogResult);
if (errCode == HciErrorCode.HCI_ERR_NONE)
{
ShowMessage("hciKbRecog success");
//输出识别结果
PrintKbResult(recogResult);
}
C++示例代码
//nSessionId :会话标识
char *gbk = "ad";
unsigned char *utf8;
GBKToUTF8((unsigned char*)gbk,&utf8);
KB_QUERY_INFO queryInfo;
KB_RECOG_RESULT result;
queryInfo.pszQuery = (char*)utf8;
queryInfo.uiSlideInfoItemCount = 0;
queryInfo.psSlideInfoItemList = NULL;
queryInfo.uiSelectedItemCount = 0;
queryInfo.psSelectedItemList = NULL;
errCode = hci_kb_recog(nSessionId,"inputmode=pinyin",&queryInfo,&result);
free(utf8);
if( errCode != HCI_ERR_NONE )
{
printf( "hci_kb_recog ret:%d\n",errCode);
return;
}
//输出识别结果
PrintKbResult(result);
iOS示例代码
NSString *text = @"ab";
NSString *pszRecogConfig = @"inputmode=cangjie";
HCI_ERR_CODE errCode = HCI_ERR_NONE;
KB_QUERY_INFO queryInfo;
KB_RECOG_RESULT result;
queryInfo.pszQuery = (char*)text.UTF8String;
queryInfo.uiSlideInfoItemCount = 0;
queryInfo.psSlideInfoItemList = NULL;
queryInfo.uiSelectedItemCount = 0;
queryInfo.psSelectedItemList = NULL;
errCode = hci_kb_recog(nSessionId,pszRecogConfig.UTF8String,&queryInfo,&result);
if( errCode != HCI_ERR_NONE )
{
NSLog(@"hci_kb_recog ret:%d",errCode);
return;
}
NSLog(@"hci_kb_recog success");
KB_CONFIRM_RESULT confirm;
confirm.pszResult = result.psResultItemList[0].pszResult;
hci_kb_confirm(nSessionId,&confirm);
//获取多页结果
while (bReturnAll && result.bMore)
{
hci_kb_free_recog_result(&result);
errCode = hci_kb_recog(nSessionId,pszRecogConfig,NULL,&result);
if( errCode != HCI_ERR_NONE )
{
NSLog(@"hci_kb_recog ret:%d",errCode);
return;
}
NSLog(@"hci_kb_recog success");
}
hci_kb_free_recog_result(&result);
常见errcode,详见灵云SDK开发手册
3.6 结束识别
最后我们需要反初始化,依次关闭会话,终止KB能力,关闭灵云系统。
Android示例代码
//关闭KB识别会话
errCode = HciCloudKb.hciKbSessionStop(session);
//终止KB能力
errCode = HciCloudKb.hciKbRelease();
//终止灵云系统
errCode = HciCloudSys.hciRelease();
C++示例代码
//关闭KB识别会话
errCode = hci_kb_session_stop(nSessionId);
//终止KB能力
errCode = hci_kb_release();
//终止灵云系统
errCode = hci_release();
iOS示例代码
//关闭KB识别会话
errCode = hci_kb_session_stop(nSessionId);
//终止KB能力
errCode = hci_kb_release();
//终止灵云系统
errCode = hci_release();
常见errcode,详见灵云SDK开发手册
4. FAQ
Q: 请问你的手写SDK怎么使用手写的UI界面? A: 我们SDK不包含手写界面,键盘和手写都是在对应平台的UI层自己实现,将用户笔迹收集为我们需要的格式传入给HWR引擎即可。(格式要求,每一笔抬笔在数组末尾添加-1,0,一次书写完毕在结尾添加-1,0,-1,-1示例代码中有点集测试数据)
Q: 手写SDK怎么支持识别繁体字? A: 在传入识别接口的参数串中设置recogRange=GBK就可以识别繁体字,但同时所使用的本地资源文件中letter.conf文件描述描述中须有recogRange=gbk,可参考下一条FAQ。
Q: 为什么我用你们的HWRSDK不能识别出芃祎赟喆等字呢?
A: 不能识别出这几个字是字典的是比范围过小,HWR识别范围在资源文件letter.conf中有描述,能识别这几个字的的字典识别范围应该为:language:chinese :recogRange:gb+gbk+big5_5401+big5该资源位于:hwr.local.freestylus/Chinese/GBK目录下
Q: 怎么调整候选词的频率? A: 使用:hciKbUdbCommit(Session session, StringstrConfig, KbUdbItemInfo udbItemInfo)添加用户自定义词这个接口来调整词频,将拼音和文字保存到udbItemInfo在传入接口即可调节词频。
Q: 怎么保存自造词? A: 保存自造词的接口为hciKbUdbCommit(Session session,String strConfig, KbUdbItemInfo udbItemInfo)将自造词和自造词对应的拼音保存到udbItemInfo在传入接口即可保存自造词,保存后会在授权路径生成cn.wa.user.dct ,en.wa.user.dct,kb.local.recog文件,使用方法参考相关开发指南。