科大讯飞离线关键词识别(语法识别)(2)

关键词识别和语音听写还是有差别的,语音听写是直接将所说的话转化成语音,至于识别的准确率看所说的话是否是常用的,如果遇到不常见的词比如
背身腿降这个指令,识别出来的就是乱七八糟的。而关键词识别也就是针对这种关键词识别有很好的效果,在于你自己构建一个.bnf文件,然后写上关键词

#BNF+IAT 1.0 UTF-8;
!grammar call;
!slot ;
!slot ;
!slot ;
!slot ;
!start ;
:[];
:北盛|背升|结束|背平|北平|备品|腿升|腿伸|腿平|坐立|躺平|停止|左翻身|有翻身|右翻身|开盖|灌溉|关盖|打包|打开电源|关闭电源|调节|打包|烘干|男性清晰|男性清洗|女性清晰|女性清洗;

其实需要修改的就是后面中文。
然后下载官方的关键词识别库,包括libs里面的两个文件和Msc.jar包,然后我重新在main下面和java同级建立一个jniLibs目录,里面放的如下文件科大讯飞离线关键词识别(语法识别)(2)_第1张图片
实际上官方下载只有两个,以至于我后来测试一直报10107错误,我就百度讯飞10107错误,解释是
在这里插入图片描述
于是查看文章里面
科大讯飞离线关键词识别(语法识别)(2)_第2张图片
可是这个类是mAsr自带的,这个参数我也没法修改,于是我在科大讯飞工作平台提交了工作单
科大讯飞离线关键词识别(语法识别)(2)_第3张图片
科大讯飞离线关键词识别(语法识别)(2)_第4张图片
很感谢日均两问的回复,最后我找到了最原始的也就是里面含有7个库的文件,这下语法直接构建成功了。这是我在做关键词识别的时候遇到的最大的问题
现在发一下代码
工具类构建语法BuildLocalGrammer

public abstract class BuildLocalGrammer {
    /**
     * 构建语法的回调
     *
     * @param errMsg null 构造成功
     */
    public abstract void result(String errMsg, String grammarId);

    // Log标签
    private static final String TAG = "BuildLocalGrammar";

    public static final String GRAMMAR_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/msc/test";
    // 上下文
    private Context mContext;
    // 语音识别对象
    private SpeechRecognizer mAsr;

    public BuildLocalGrammer(Context context) {
        mContext = context;

        // 初始化识别对象
        mAsr = SpeechRecognizer.createRecognizer(context, new InitListener() {

            @Override
            public void onInit(int code) {
                Log.d(TAG, "SpeechRecognizer init() code = " + code);
                if (code != ErrorCode.SUCCESS) {
                    result(code + "", null);
                    Log.d(TAG, "初始化失败,错误码:" + code);
                    Toast.makeText(mContext, "初始化失败,错误码:" + code, Toast.LENGTH_SHORT).show();
                }
            }
        });
    }

    ;

    /**
     * 构建语法
     *
     * @return
     */
    public void buildLocalGrammar() {
        try {
            /*
             * TODO 如果你要在程序里维护bnf文件,可以在这里加上你维护的一些逻辑
             * 如果不嫌麻烦,要一直改bnf文件,这里的代码可以不用动,不过我个人不建议一直手动修改bnf文件
             * ,内容多了以后很容易出错,不好找Bug,建议每次改之前先备份。 建议用程序维护bnf文件。
             */

            /*
             * 构建语法
             */
            String mContent;// 语法、词典临时变量
            String 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, SpeechConstant.TYPE_LOCAL);
            // 设置语法构建路径
            mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, GRAMMAR_PATH);
            // 使用8k音频的时候请解开注释
            // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
            // 设置资源路径
            mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
            // 构建语法
            int ret = mAsr.buildGrammar("bnf", mContent, new GrammarListener() {

                @Override
                public void onBuildFinish(String grammarId, SpeechError error) {
                    if (error == null) {
                        Log.d(TAG, "语法构建成功");
                        result(null, grammarId);
                    } else {
                        Log.d(TAG, "语法构建失败,错误码:" + error.getErrorCode());
                        result(error.getErrorCode() + "", grammarId);
                    }
                }
            });
            if (ret != ErrorCode.SUCCESS) {
                Log.d(TAG, "语法构建失败,错误码:" + ret);
                result(ret + "", null);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取识别资源路径
    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();
    }


}

识别类KqwSpeechRecognizer

public abstract class KqwSpeechRecognizer {

    /**
     * 初始化的回调
     *
     * @param flag
     *            true 初始化成功 false 初始化失败
     */
    public abstract void initListener(boolean flag);

    public abstract void resultData(String data);

    public abstract void speechLog(String log);


    // Log标签
    private static final String TAG = "KqwLocal";
    private Toast mToast;

    public static final String GRAMMAR_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/msc/test";
    // 上下文
    private Context mContext;
    // 语音识别对象
    private SpeechRecognizer mAsr;

    public KqwSpeechRecognizer(Context context) {
        mContext = context;

        // 初始化识别对象
        mAsr = SpeechRecognizer.createRecognizer(context, new InitListener() {

            @Override
            public void onInit(int code) {
                Log.d(TAG,   code+"");
                if (code != ErrorCode.SUCCESS) {
                    initListener(false);
                    Toast.makeText(mContext, "初始化失败,错误码:" + code, Toast.LENGTH_SHORT).show();
                } else {
                    initListener(true);
                }
            }
        });

    }

    /**
     * 参数设置
     */
    public void setParam() {
        // 清空参数
        mAsr.setParameter(SpeechConstant.PARAMS, null);
        // 设置识别引擎 本地引擎
        mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL);
        // mAsr.setParameter(SpeechConstant.ENGINE_TYPE,
        // SpeechConstant.TYPE_MIX);
        // mAsr.setParameter(SpeechConstant.ENGINE_TYPE, "mixed");
        // // 设置本地识别资源
        mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath());
        // 设置语法构建路径
        mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, GRAMMAR_PATH);
        // 设置返回结果格式
        mAsr.setParameter(SpeechConstant.RESULT_TYPE, "json");
        // 设置本地识别使用语法id
        mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call");
        // 设置识别的门限值
        mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "60");
        // 使用8k音频的时候请解开注释
        // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000");
        mAsr.setParameter(SpeechConstant.DOMAIN, "iat");
        mAsr.setParameter(SpeechConstant.NLP_VERSION, "2.0");
        mAsr.setParameter("asr_sch", "1");
        // mAsr.setParameter(SpeechConstant.RESULT_TYPE, "json");
    }

    // 获取识别资源路径
    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();
    }

    int ret = 0;// 函数调用返回值

    /**
     * 开始识别
     */
    public void startListening() {
        // 设置参数
        setParam();
        ret = mAsr.startListening(mRecognizerListener);
        if (ret != ErrorCode.SUCCESS) {
            Log.i(TAG, "识别失败,错误码: " + ret);
        }
    }
    public void stopListening(){
        mAsr.stopListening();
    }

    /**
     * 识别监听器。
     */
    private RecognizerListener mRecognizerListener = new RecognizerListener() {

        StringBuffer stringBuffer = new StringBuffer();

        public void onVolumeChanged(int volume) {
            Log.i(TAG, "当前正在说话,音量大小:" + volume);
            speechLog("当前正在说话,音量大小:" + volume);
        }

        @Override
        public void onResult(final RecognizerResult result, boolean isLast) {
            /*
             * TODO 拼接返回的数据
             *
             * 这里返回的是Json数据,具体返回的是离线名命令词返回的Json还是语义返回的Json,需要做判断以后在对数据数据进行拼接
             */
            stringBuffer.append(result.getResultString()).append("\n\n");
            // isLast为true的时候,表示一句话说完,将拼接后的完整的一句话返回
            if (isLast) {
                // 数据回调
                resultData(stringBuffer.toString());
            }
        }

        @Override
        public void onEndOfSpeech() {
            showTip("结束说话");
            speechLog("结束说话");
        }

        @Override
        public void onVolumeChanged(int i, byte[] bytes) {


        }

        @Override
        public void onBeginOfSpeech() {
            stringBuffer.delete(0, stringBuffer.length());
            showTip("开始说话");
            speechLog("开始说话");
        }

        @Override
        public void onError(SpeechError error) {
            Log.i(TAG, "error = " + error.getErrorCode());
            if (error.getErrorCode() == 20005) {
                // 本地命令词没有识别,也没有请求到网络
                resultData("没有构建的语法");
                speechLog("没有构建的语法");
                /*
                 * TODO
                 * 当网络正常的情况下是不会回调20005的错误,只有当本地命令词识别不匹配,网络请求也失败的情况下,会返回20005
                 * 这里可以自己再做处理,例如回复“没有听清”等回复
                 */
            } else {
                /*
                 * TODO
                 * 其他错误有很多,需要具体问题具体分析,正常在程序没有错误的情况下,只会回调一个没有检测到说话的错误,没记错的话错误码是10118
                 */
            }
        }

        @Override
        public void onEvent(int eventType, int arg1, int arg2, Bundle obj) {
            Log.i(TAG, "eventType = " + eventType);
        }

    };
    private void showTip(final String str) {
      new Thread (new Runnable() {
            @Override
            public void run() {
                mToast.setText(str);
                mToast.show();
            }
        });
    }

}

然后再mainActivity就可以直接使用了

public class MainActivity extends Activity {

    private TextView mTvResult;
    private TextView mTvLog;
    private BuildLocalGrammar buildLocalGrammar;
    private KqwSpeechRecognizer kqwSpeechRecognizer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SpeechUtility.createUtility(this, SpeechConstant.APPID+"=5de9a6f7");
        mTvResult = (TextView) findViewById(R.id.tv_result);
        mTvLog = (TextView) findViewById(R.id.tv_log);

        /**
         * 初始化本地语法构造器
         */
        buildLocalGrammar = new BuildLocalGrammar(this) {

            @Override
            public void result(String errMsg, String grammarId) {
                // errMsg为null 构造成功
                if (TextUtils.isEmpty(errMsg)) {
                    Toast.makeText(MainActivity.this, "构造成功", Toast.LENGTH_SHORT).show();

                } else {
                    Toast.makeText(MainActivity.this, "构造失败", Toast.LENGTH_SHORT).show();
                }
            }
        };

        /**
         * 初始化离线命令词识别器
         */
        kqwSpeechRecognizer = new KqwSpeechRecognizer(this) {

            @Override
            public void speechLog(String log) {
                // 录音Log信息的回调
                mTvLog.setText(log);
            }

            @Override
            public void resultData(String data) {
                // 是识别结果的回调
                mTvResult.setText(data);
            }

            @Override
            public void initListener(boolean flag) {
                // 初始化的回调
                if (flag) {
                    Toast.makeText(MainActivity.this, "初始化成功", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(MainActivity.this, "初始化失败", Toast.LENGTH_SHORT).show();
                }
            }
        };

        /**
         * 构造本地语法文件,只有语法文件有变化的时候构造成功一次即可,不用每次都构造
         */
        buildLocalGrammar.buildLocalGrammar();

    }

    /**
     * 开始识别按钮
     *
     * @param view
     */
    public void start(View view) {
        mTvResult.setText(null);
        // 开始识别
        kqwSpeechRecognizer.startListening();
    }

}

项目代码上传到Github上

你可能感兴趣的:(android)