这篇博客主要讲解如何实现离线命令词的功能

      科大讯飞离线命令词这个功能还是比较好用的 , 它可以配合着语音唤醒一起使用,这个时候就可以做出来你想要的效果 ,如智能音响什么的 !  不多说, 直接上代码!

     集成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>:打开|发送;

以上就是命令词的代码实现 , 有什么不懂可以在底下评论,留言!