这篇博客主要讲解如何实现离线命令词的功能
科大讯飞离线命令词这个功能还是比较好用的 , 它可以配合着语音唤醒一起使用,这个时候就可以做出来你想要的效果 ,如智能音响什么的 ! 不多说, 直接上代码!
集成SDK可以参考官方文档来集成 , 我这边主要讲解一下如何实现和如何编写BNF文件!
经过我二次封装可以直接调用
代码如下:
public class IflyGrammar {private final static String mTag = "IflyGrammar";private Context mContext;private HashMap<String, String> mTszjNames;// 语音识别对象 private SpeechRecognizer mAsr;private Toast mToast;// 缓存 private SharedPreferences mSharedPreferences;private String mContent;// 语法、词典临时变量 // 本地语法文件 private String mLocalGrammar = null;// 本地词典 private String mLocalLexicon = null;// 本地语法构建路径 private String grmPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/msc/test";// 返回结果格式,支持:xml,json private String mResultType = "json";private final String KEY_GRAMMAR_ABNF_ID = "grammar_abnf_id";private final String GRAMMAR_TYPE_ABNF = "abnf";private final String GRAMMAR_TYPE_BNF = "bnf";private String mEngineType = SpeechConstant.TYPE_LOCAL;private int mRet;private VoiceWakeuper mIvw;//初始化监听器 private InitListener mInitListener = new InitListener() {@Override public void onInit(int code) {Log.d(mTag, "SpeechRecognizer init() code = " + code);if (code != ErrorCode.SUCCESS) {showTip("初始化失败,错误码:" + code);}}};//识别监听器 private RecognizerListener mRecognizerListener = new RecognizerListener() {@Override public void onVolumeChanged(int volume, byte[] data) { // showTip("当前正在说话,音量大小:" + volume); Log.d(mTag, "返回音频数据:" + data.length);}@Override public void onResult(final RecognizerResult result, boolean isLast) {if (null != result && !TextUtils.isEmpty(result.getResultString())) {Log.d(mTag, "recognizer result:" + result.getResultString());String text = "";if (mResultType.equals("json")) {text = JsonParser.parseGrammarResult(result.getResultString(), mEngineType);GrammarRec grammarRec = JsonUtil.parseJStr2Object(GrammarRec.class, result.getResultString());if (grammarRec == null) return;switch (grammarRec.getWs().get(0).getSlot()) {//这里面是识别后的回调在这这个里面做操作!,然后用EventBus传出去.case "<open>":String tt = JsonParser.parseGrammarResult(result.getResultString());Log.e("走了",tt);if (tt.contains("XXXX")) {String s = "1";EventBus.getDefault().post(new StartIDActivity(s));} break;default:break;}
} else if (mResultType.equals("xml")) {text = XmlParser.parseNluResult(result.getResultString());}// 显示 // ((EditText) findViewById(R.id.isr_text)).setText(text); } else {Log.d(mTag, "recognizer result : null");}}@Override public void onEndOfSpeech() {// 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入 showTip("结束说话");Global.mIflyGrammer.stopRecognize();EventBus.getDefault().post(new kaiqi());Log.e("走了","4444444");}@Override public void onBeginOfSpeech() {// 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入 showTip("开始说话");}@Override public void onError(SpeechError error) {showTip("onError Code:" + error.getErrorCode());}@Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {// 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因 // 若使用本地能力,会话id为null // if (SpeechEvent.EVENT_SESSION_ID == eventType) { // String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID); // Log.d(TAG, "session id =" + sid); // } }};//构建语法监听器 private GrammarListener mGrammarListener = new GrammarListener() {@Override public void onBuildFinish(String grammarId, SpeechError error) {if (error == null) {if (mEngineType.equals(SpeechConstant.TYPE_CLOUD)) {SharedPreferences.Editor editor = mSharedPreferences.edit();if (!TextUtils.isEmpty(grammarId))editor.putString(KEY_GRAMMAR_ABNF_ID, grammarId);editor.commit();}showTip("语法构建成功:" + grammarId);} else {showTip("语法构建失败,错误码:" + error.getErrorCode());}}};//更新词典监听器 private LexiconListener mLexiconListener = new LexiconListener() {@Override public void onLexiconUpdated(String lexiconId, SpeechError error) {if (error == null) {showTip("词典更新成功");} else {showTip("词典更新失败,错误码:" + error.getErrorCode());}}};public IflyGrammar(Context context) {mContext = context;mToast = Toast.makeText(context, "", Toast.LENGTH_SHORT);mAsr = SpeechRecognizer.createRecognizer(mContext, mInitListener);buildGrammar();initTzsjNames();updateLexicon();}//设置参数 public boolean setParam() {boolean result = false;// 清空参数 mAsr.setParameter(SpeechConstant.PARAMS, null);// 设置识别引擎 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);// 设置本地识别资源 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());// 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);// 设置返回结果格式 mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType);// 设置本地识别使用语法id mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call");// 设置识别的门限值 mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30");// 使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); result = true;// 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 // 注:AUDIO_FORMAT参数语记需要更新版本才能生效 mAsr.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");mAsr.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/asr.wav");return result;}//获取识别资源路径 private String getResourcePath() {StringBuffer tempBuffer = new StringBuffer();//识别通用资源 tempBuffer.append(ResourceUtil.generateResourcePath(mContext, ResourceUtil.RESOURCE_TYPE.assets, "asr/common.jet"));//识别8k资源-使用8k的时候请解开注释 // tempBuffer.append(";"); // tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets, "asr/common_8k.jet")); return tempBuffer.toString();}private void showTip(final String str) {Toast.makeText(mContext, str, Toast.LENGTH_SHORT).show();}//构建语法 private void buildGrammar() {// 初始化语法、命令词 mLocalLexicon = "张海羊\n刘婧\n王锋\n";mLocalGrammar = FucUtil.readFile(mContext, "call.bnf", "utf-8");mContent = new String(mLocalGrammar);mAsr.setParameter(SpeechConstant.PARAMS, null);// 设置文本编码格式 mAsr.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");// 设置引擎类型 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);// 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);//使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); // 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());mRet = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, mGrammarListener);if (mRet != ErrorCode.SUCCESS) {showTip("语法构建失败,错误码:" + mRet);}}private void initTzsjNames() {mTszjNames = new HashMap<>();Iterator iterator = Global.mPersons.entrySet().iterator();mLocalLexicon = "";while (iterator.hasNext()) {Map.Entry entry = (Map.Entry) iterator.next();Person person = (Person) entry.getValue();mTszjNames.put(person.mName, person.mID);mLocalLexicon += person.mName + "\n";}}//本地-更新词典 private void updateLexicon() {mContent = new String(mLocalLexicon);mAsr.setParameter(SpeechConstant.PARAMS, null);// 设置引擎类型 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);// 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());//使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath);// 设置语法名称 mAsr.setParameter(SpeechConstant.GRAMMAR_LIST, "call");// 设置文本编码格式 mAsr.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");mRet = mAsr.updateLexicon("contact", mContent, mLexiconListener);if (mRet != ErrorCode.SUCCESS) {showTip("更新词典失败,错误码:" + mRet);}}//开始识别 public void startRecognize() {// 设置参数 if (!setParam()) {showTip("请先构建语法。");return;}mRet = mAsr.startListening(mRecognizerListener);if (mRet != ErrorCode.SUCCESS) {showTip("识别失败,错误码: " + mRet);}}//停止识别 public void stopRecognize() {mAsr.stopListening();showTip("停止识别");}//取消识别 public void cancelRecognize() {mAsr.cancel();showTip("取消识别");}//反初始化 public void unInit() {if (null != mAsr) {// 退出时释放连接 mAsr.cancel();mAsr.destroy();}} }
以上就是命令词的代码可以直接复制使用 , 主要识别之后的操作我这边是用EvntBus传到相应的界面进行操作的!
然后现在教如何编写BNF文件:代码如下
#BNF+IAT 1.0 UTF-8; !grammar call; !slot <contact>;//这个是槽,你要加东西的话也是先创建槽然后在底下写上对应的 !slot <open>; !slot <location>; !slot <notes>; !slot <flish>; !slot <delete>; !slot <map>; !start <locationStart>; <locationStart>:[<open>]<notes>;//这里是命令的拼接,中括号里面的是指令 ,后面跟着的是口令! <contact>:张海洋|李四|王五; <open>:打开|发送;
以上就是命令词的代码实现 , 有什么不懂可以在底下评论,留言!