灵云语法识别
源碼
GitHub
在線語(yǔ)法識(shí)別
SDK下載
靈云SDK下載
SDK集成
下載SDK以后,將jar和so導(dǎo)入工程
權(quán)限
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />封裝
靈云配置類
package kong.qingwei.kqwhcidemo;/*** Created by kqw on 2016/8/12.* 靈云配置信息*/ public final class ConfigUtil {/*** 靈云APP_KEY*/public static final String APP_KEY = "3d5d5466";/*** 開(kāi)發(fā)者密鑰*/public static final String DEVELOPER_KEY = "eca643ff7b3c758745d7cf516e808d34";/*** 靈云云服務(wù)的接口地址*/public static final String CLOUD_URL = "test.api.hcicloud.com:8888";/*** 需要運(yùn)行的靈云能力*/// 離線語(yǔ)音合成public static final String CAP_KEY_TTS_LOCAL = "tts.local.synth";// 云端語(yǔ)音合成public static final String CAP_KEY_TTS_CLOUD = "tts.cloud.wangjing";// 云端語(yǔ)義識(shí)別public static final String CAP_KEY_NUL_CLOUD = "nlu.cloud";// 云端自由說(shuō)public static final String CAP_KEY_ASR_CLOUD_FREETALK = "asr.cloud.freetalk";// 離線自由說(shuō)public static final String CAP_KEY_ASR_LOCAL_FREETALK = "asr.local.freetalk";// 云端語(yǔ)音識(shí)別+語(yǔ)義public static final String CAP_KEY_ASR_CLOUD_DIALOG = "asr.cloud.dialog";// 離線命令詞public static final String CAP_KEY_ASR_LOCAL_GRAMMAR = "asr.local.grammar.v4";// 在線命令詞public static final String CAP_KEY_ASR_CLOUD_GRAMMAR = "asr.cloud.grammar"; }初始化靈云語(yǔ)音能力的工具類
package kong.qingwei.kqwhcidemo;import android.app.Activity; import android.os.Environment; import android.util.Log; import android.widget.Toast;import com.sinovoice.hcicloudsdk.api.HciCloudSys; import com.sinovoice.hcicloudsdk.common.AuthExpireTime; import com.sinovoice.hcicloudsdk.common.HciErrorCode; import com.sinovoice.hcicloudsdk.common.InitParam;import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale;/*** Created by kqw on 2016/8/12.* 初始化靈云語(yǔ)音*/ public class HciUtil {private static final String TAG = "HciUtil";private Activity mActivity;private final String mConfigStr;public HciUtil(Activity activity) {mActivity = activity;// 加載信息,返回InitParam, 獲得配置參數(shù)的字符串InitParam initParam = getInitParam();mConfigStr = initParam.getStringConfig();}public boolean initHci() {// 初始化int errCode = HciCloudSys.hciInit(mConfigStr, mActivity);if (errCode != HciErrorCode.HCI_ERR_NONE && errCode != HciErrorCode.HCI_ERR_SYS_ALREADY_INIT) {Toast.makeText(mActivity, "hciInit error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();return false;}// 獲取授權(quán)/更新授權(quán)文件 :errCode = checkAuthAndUpdateAuth();if (errCode != HciErrorCode.HCI_ERR_NONE) {// 由于系統(tǒng)已經(jīng)初始化成功,在結(jié)束前需要調(diào)用方法hciRelease()進(jìn)行系統(tǒng)的反初始化Toast.makeText(mActivity, "CheckAuthAndUpdateAuth error: " + HciCloudSys.hciGetErrorInfo(errCode), Toast.LENGTH_SHORT).show();HciCloudSys.hciRelease();return false;}return true;}/*** 釋放*/public void hciRelease(){HciCloudSys.hciRelease();}/*** 加載初始化信息** @return 系統(tǒng)初始化參數(shù)*/private InitParam getInitParam() {String authDirPath = mActivity.getFilesDir().getAbsolutePath();// 前置條件:無(wú)InitParam initparam = new InitParam();// 授權(quán)文件所在路徑,此項(xiàng)必填initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTH_PATH, authDirPath);// 是否自動(dòng)訪問(wèn)云授權(quán),詳見(jiàn) 獲取授權(quán)/更新授權(quán)文件處注釋initparam.addParam(InitParam.AuthParam.PARAM_KEY_AUTO_CLOUD_AUTH, "no");// 靈云云服務(wù)的接口地址,此項(xiàng)必填initparam.addParam(InitParam.AuthParam.PARAM_KEY_CLOUD_URL, ConfigUtil.CLOUD_URL);// 開(kāi)發(fā)者Key,此項(xiàng)必填,由捷通華聲提供initparam.addParam(InitParam.AuthParam.PARAM_KEY_DEVELOPER_KEY, ConfigUtil.DEVELOPER_KEY);// 應(yīng)用Key,此項(xiàng)必填,由捷通華聲提供initparam.addParam(InitParam.AuthParam.PARAM_KEY_APP_KEY, ConfigUtil.APP_KEY);// 配置日志參數(shù)String sdcardState = Environment.getExternalStorageState();if (Environment.MEDIA_MOUNTED.equals(sdcardState)) {String sdPath = Environment.getExternalStorageDirectory().getAbsolutePath();String packageName = mActivity.getPackageName();String logPath = sdPath + File.separator + "sinovoice" + File.separator + packageName + File.separator + "log" + File.separator;// 日志文件地址File fileDir = new File(logPath);if (!fileDir.exists()) {fileDir.mkdirs();}// 日志的路徑,可選,如果不傳或者為空則不生成日志initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_PATH, logPath);// 日志數(shù)目,默認(rèn)保留多少個(gè)日志文件,超過(guò)則覆蓋最舊的日志initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_COUNT, "5");// 日志大小,默認(rèn)一個(gè)日志文件寫(xiě)多大,單位為Kinitparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_FILE_SIZE, "1024");// 日志等級(jí),0=無(wú),1=錯(cuò)誤,2=警告,3=信息,4=細(xì)節(jié),5=調(diào)試,SDK將輸出小于等于logLevel的日志信息initparam.addParam(InitParam.LogParam.PARAM_KEY_LOG_LEVEL, "5");}return initparam;}/*** 獲取授權(quán)** @return 授權(quán)結(jié)果*/private int checkAuthAndUpdateAuth() {// 獲取系統(tǒng)授權(quán)到期時(shí)間int initResult;AuthExpireTime objExpireTime = new AuthExpireTime();initResult = HciCloudSys.hciGetAuthExpireTime(objExpireTime);if (initResult == HciErrorCode.HCI_ERR_NONE) {// 顯示授權(quán)日期,如用戶不需要關(guān)注該值,此處代碼可忽略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()) {// 已經(jīng)成功獲取了授權(quán),并且距離授權(quán)到期有充足的時(shí)間(>7天)Log.i(TAG, "checkAuth success");return initResult;}}// 獲取過(guò)期時(shí)間失敗或者已經(jīng)過(guò)期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;}} }語(yǔ)法識(shí)別的類
和之前的語(yǔ)音識(shí)別一樣,只不過(guò)配置了語(yǔ)法
在原來(lái)的基礎(chǔ)上添加了initGrammar方法
package kong.qingwei.kqwhcidemo;import android.app.Activity; import android.util.Log;import com.sinovoice.hcicloudsdk.android.asr.recorder.ASRRecorder; import com.sinovoice.hcicloudsdk.common.asr.AsrConfig; import com.sinovoice.hcicloudsdk.common.asr.AsrGrammarId; import com.sinovoice.hcicloudsdk.common.asr.AsrInitParam; import com.sinovoice.hcicloudsdk.common.asr.AsrRecogResult; import com.sinovoice.hcicloudsdk.recorder.ASRCommonRecorder; import com.sinovoice.hcicloudsdk.recorder.ASRRecorderListener; import com.sinovoice.hcicloudsdk.recorder.RecorderEvent;import java.io.IOException; import java.io.InputStream;/*** Created by kqw on 2016/8/15.* 語(yǔ)音識(shí)別類*/ public class AsrUtil {private static final String TAG = "AsrUtil";private Activity mActivity;private ASRRecorder mAsrRecorder;private AsrConfig asrConfig;private OnAsrRecogListener mOnAsrRecogListener;private String mGrammar = null;private String mCapKey = ConfigUtil.CAP_KEY_ASR_CLOUD_GRAMMAR;public AsrUtil(Activity activity) {mActivity = activity;initAsr();initGrammar(mCapKey);}/*** 初始化語(yǔ)音識(shí)別*/private void initAsr() {Log.i(TAG, "initAsr: ");// 初始化錄音機(jī)mAsrRecorder = new ASRRecorder();// 配置初始化參數(shù)AsrInitParam asrInitParam = new AsrInitParam();String dataPath = mActivity.getFilesDir().getPath().replace("files", "lib");asrInitParam.addParam(AsrInitParam.PARAM_KEY_INIT_CAP_KEYS, mCapKey);asrInitParam.addParam(AsrInitParam.PARAM_KEY_DATA_PATH, dataPath);asrInitParam.addParam(AsrInitParam.PARAM_KEY_FILE_FLAG, AsrInitParam.VALUE_OF_PARAM_FILE_FLAG_ANDROID_SO);Log.v(TAG, "init parameters:" + asrInitParam.getStringConfig());// 設(shè)置初始化參數(shù)mAsrRecorder.init(asrInitParam.getStringConfig(), new ASRResultProcess());// 配置識(shí)別參數(shù)asrConfig = new AsrConfig();// PARAM_KEY_CAP_KEY 設(shè)置使用的能力asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_CAP_KEY, mCapKey);// PARAM_KEY_AUDIO_FORMAT 音頻格式根據(jù)不同的能力使用不用的音頻格式asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_AUDIO_FORMAT, AsrConfig.AudioConfig.VALUE_OF_PARAM_AUDIO_FORMAT_PCM_16K16BIT);// PARAM_KEY_ENCODE 音頻編碼壓縮格式,使用OPUS可以有效減小數(shù)據(jù)流量asrConfig.addParam(AsrConfig.AudioConfig.PARAM_KEY_ENCODE, AsrConfig.AudioConfig.VALUE_OF_PARAM_ENCODE_SPEEX);// 其他配置,此處可以全部選取缺省值asrConfig.addParam("intention", "weather");}/*** 初始化語(yǔ)法** @param capKey CapKey*/public void initGrammar(String capKey) {// 語(yǔ)法相關(guān)的配置,若使用自由說(shuō)能力可以不必配置該項(xiàng)if (capKey.contains("local.grammar")) {mGrammar = loadGrammar("stock_10001.gram");// 加載本地語(yǔ)法獲取語(yǔ)法IDAsrGrammarId id = new AsrGrammarId();ASRCommonRecorder.loadGrammar("capkey=" + capKey + ",grammarType=jsgf", mGrammar, id);Log.d(TAG, "grammarid=" + id);// PARAM_KEY_GRAMMAR_TYPE 語(yǔ)法類型,使用自由說(shuō)能力時(shí),忽略以下此參數(shù)asrConfig.addParam(AsrConfig.GrammarConfig.PARAM_KEY_GRAMMAR_TYPE, AsrConfig.GrammarConfig.VALUE_OF_PARAM_GRAMMAR_TYPE_ID);asrConfig.addParam(AsrConfig.GrammarConfig.PARAM_KEY_GRAMMAR_ID, "" + id.getGrammarId());} else if (capKey.contains("cloud.grammar")) {mGrammar = loadGrammar("stock_10001.gram");// PARAM_KEY_GRAMMAR_TYPE 語(yǔ)法類型,使用自由說(shuō)能力時(shí),忽略以下此參數(shù)asrConfig.addParam(AsrConfig.GrammarConfig.PARAM_KEY_GRAMMAR_TYPE, AsrConfig.GrammarConfig.VALUE_OF_PARAM_GRAMMAR_TYPE_JSGF);}}/*** 開(kāi)始語(yǔ)音識(shí)別*/public void start(OnAsrRecogListener listener) {mOnAsrRecogListener = listener;if (mAsrRecorder.getRecorderState() == ASRRecorder.RECORDER_STATE_IDLE) {asrConfig.addParam(AsrConfig.SessionConfig.PARAM_KEY_REALTIME, "no");mAsrRecorder.start(asrConfig.getStringConfig(), mGrammar);} else {Log.i(TAG, "start: 錄音機(jī)未處于空閑狀態(tài),請(qǐng)稍等");}}private class ASRResultProcess implements ASRRecorderListener {@Overridepublic void onRecorderEventError(RecorderEvent event, int errorCode) {Log.i(TAG, "onRecorderEventError: errorCode = " + errorCode);if (null != mOnAsrRecogListener) {mOnAsrRecogListener.onError(errorCode);}}@Overridepublic void onRecorderEventRecogFinsh(RecorderEvent recorderEvent, final AsrRecogResult arg1) {if (recorderEvent == RecorderEvent.RECORDER_EVENT_RECOGNIZE_COMPLETE) {Log.i(TAG, "onRecorderEventRecogFinsh: 識(shí)別結(jié)束");}if (null != mOnAsrRecogListener) {mActivity.runOnUiThread(new Runnable() {@Overridepublic void run() {mOnAsrRecogListener.onAsrRecogResult(arg1);}});}}@Overridepublic void onRecorderEventStateChange(RecorderEvent recorderEvent) {if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECORD) {Log.i(TAG, "onRecorderEventStateChange: 開(kāi)始錄音");} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_BEGIN_RECOGNIZE) {Log.i(TAG, "onRecorderEventStateChange: 開(kāi)始識(shí)別");} else if (recorderEvent == RecorderEvent.RECORDER_EVENT_NO_VOICE_INPUT) {Log.i(TAG, "onRecorderEventStateChange: 無(wú)音頻輸入");} else {Log.i(TAG, "onRecorderEventStateChange: recorderEvent = " + recorderEvent);}}@Overridepublic void onRecorderRecording(byte[] volumedata, int volume) {if (null != mOnAsrRecogListener) {mOnAsrRecogListener.onVolume(volume);}}@Overridepublic void onRecorderEventRecogProcess(RecorderEvent recorderEvent, AsrRecogResult arg1) {if (recorderEvent == RecorderEvent.RECORDER_EVENT_RECOGNIZE_PROCESS) {Log.i(TAG, "onRecorderEventRecogProcess: 識(shí)別中間反饋");}if (arg1 != null) {if (arg1.getRecogItemList().size() > 0) {Log.i(TAG, "onRecorderEventRecogProcess: 識(shí)別中間結(jié)果結(jié)果為:" + arg1.getRecogItemList().get(0).getRecogResult());} else {Log.i(TAG, "onRecorderEventRecogProcess: 未能正確識(shí)別,請(qǐng)重新輸入");}}}}/*** 讀取語(yǔ)法** @param fileName 文件名* @return 語(yǔ)法*/private String loadGrammar(String fileName) {String grammar = "";InputStream is = null;try {is = mActivity.getAssets().open(fileName);byte[] data = new byte[is.available()];is.read(data);grammar = new String(data);} catch (IOException e) {e.printStackTrace();} finally {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}return grammar;}/*** 語(yǔ)音識(shí)別的回調(diào)接口*/public interface OnAsrRecogListener {// 識(shí)別結(jié)果void onAsrRecogResult(AsrRecogResult asrRecogResult);// 識(shí)別錯(cuò)誤碼void onError(int errorCode);// 錄音音量void onVolume(int volume);} }使用
使用和語(yǔ)音識(shí)別完全一致
初始化靈云的語(yǔ)音能力和語(yǔ)法識(shí)別
// 靈云語(yǔ)音工具類 mInitTts = new HciUtil(this); // 初始化靈云語(yǔ)音 boolean isInitHci = mInitTts.initHci(); if (isInitHci) { // 初始化成功……// 語(yǔ)音識(shí)別mAsrUtil = new AsrUtil(this); }語(yǔ)法識(shí)別
/*** 語(yǔ)音識(shí)別(語(yǔ)音轉(zhuǎn)文字)** @param view view*/ public void asr(View view) {mAsrUtil.start(new AsrUtil.OnAsrRecogListener() {@Overridepublic void onAsrRecogResult(AsrRecogResult asrRecogResult) {StringBuilder stringBuffer = new StringBuilder();ArrayList<AsrRecogItem> asrRecogItemArrayList = asrRecogResult.getRecogItemList();for (AsrRecogItem asrRecogItem : asrRecogItemArrayList) {String result = asrRecogItem.getRecogResult();Log.i(TAG, "onAsrRecogResult: " + result);stringBuffer.append(result).append("\n");}showDialog("識(shí)別結(jié)果", stringBuffer.toString());}@Overridepublic void onError(int errorCode) {Log.i(TAG, "onError: " + errorCode);}@Overridepublic void onVolume(int volume) {Log.i(TAG, "onVolume: " + volume);}}); }離線語(yǔ)音識(shí)別
在在線語(yǔ)法識(shí)別的基礎(chǔ)上,離線的語(yǔ)法識(shí)別只需要將CapKey替換,并且添加離線資源即可
離線資源的下載
下載完解壓離線資源
將里面所有的文件重命名,前面加lib,后面加.so,然后導(dǎo)入工程
修改CapKey為asr.local.grammar.v4
注意,靈云的離線語(yǔ)音功能第一次使用需要聯(lián)網(wǎng)激活,激活以后才可以使用離線功能。
總結(jié)
- 上一篇: 阿里开源:思考,演进和发展
- 下一篇: Hadoop十篇文章