Android修真传之讯飞语音识别第二篇

作者: 请卜要动朕 | 来源:发表于2018-12-25 17:02 被阅读19次
    当前版本1.0.0

    本人是个未满一年经验的小新,正在进行Android修仙之路,由于没有师傅只能单兵作战,在修仙过程之中不断通过实战提高自己的修为。若对实战过程中有误的地方希望道友帮忙指正,不然本人将误入歧途最终成魔(哈哈)。在实战过程之前小辈会参考其他前辈的实战经验,这也是大多修真者都会这么做的,所以在实战过程中都不是原创。

    什么是AIUI

    AIUI 是科大讯飞提供的一套人机智能交互解决方案, 旨在实现人机交互无障碍,使人与机器之间可以通过语音、图像、手势等自然交互方式,进行持续,双向,自然地沟通。现阶段 AIUI 提供以语音交互为核心的交互解决方案,全链路聚合了语音唤醒、语音识别、语义理解、内容(信源)平台、语音合成等模块。可以应用于智能手机(终端)、机器人、音箱、车载、智能家居、智能客服等多种领域,让产品不仅能听会说,而且能理解会思考。AIUI 开放平台主要包含了语义技能(Skill)、问答库(Q&A)编辑以及AIUI 应用(硬件)云端配置的能力,并为不同形态产品提供了不同的接入方式

    为什么要使用AIUI

    比如我现在做一个机器人,这个机器人能和用户进行交流,比如我说查询今天天气,机器人会回答今天的天气状态。如果您没有接入AIUI会怎么做?是不是首先获取用户说出的内容,这个由语音听写SpeechRecognizer对象来完成,获取到内容后还需要进行分词,判断分词结果是否包含天气,然后再根据时间去查询天气。这样的话太麻烦,而且在解决这个问题上还需要更好的算法来支撑。不过AIUI帮我们解决了这个问题,首先AIUI官方提供了很多技能,比如天气技能,我们只需要添加该技能后通过监听AIUI的事件,在AIUIConstant.EVENT_RESULT中接收天气的结果即可。

    什么是技能呢?这个技能就是专门解决一类的问题?比如上面的天气这个问题,这个技能只能回答和天气相关的,除非你自己自定义技能。下面让我们看看讯飞提供了哪些技能给我们开发者使用,当然技能可以进行分享让其他人使用您的技能。 技能商店

    集成AIUI

    首先AIUI相关的操作都是由AIUIAgent这个类来完成的,我们第一步就是需要获取该对象。

            //创建AIUIAgent
            final AIUIAgent mAIUIAgent = AIUIAgent.createAgent(this,
                    getAIUIParams(),mAIUIListener);
    

    第一个参数不解释,第二个参数主要是获取我们assest目录下的cfg文件的内容,如果你下载的SDK中没有改文件的话说明您还没引入AIUI服务,该getAIUIParams方法如下

    private String getAIUIParams() {
            String params = "";
            AssetManager assetManager = getResources().getAssets();
            try {
                InputStream ins = assetManager.open( "cfg/aiui_phone.cfg" );
                byte[] buffer = new byte[ins.available()];
                ins.read(buffer);
                ins.close();
                params = new String(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return params;
        }
    

    第三个就是接受AIUI SDK抛出事件的监听器

     private int mAIUIState;
        private AIUIListener mAIUIListener = new AIUIListener() {
    
            @Override
            public void onEvent(AIUIEvent event) {
                switch (event.eventType) {
                    case AIUIConstant.EVENT_WAKEUP:
                        //唤醒事件
                        Log.d( TAG,  "on event: "+ event.eventType );
                        break;
    
                    case AIUIConstant.EVENT_RESULT: {
                        //结果解析事件
                        try {
                            JSONObject bizParamJson = new JSONObject(event.info);
                            JSONObject data = bizParamJson.getJSONArray("data").getJSONObject(0);
                            JSONObject params = data.getJSONObject("params");
                            JSONObject content = data.getJSONArray("content").getJSONObject(0);
                            if (content.has("cnt_id")) {
                                String cnt_id = content.getString("cnt_id");
                                JSONObject cntJson = new JSONObject(new String(event.data.getByteArray(cnt_id), "utf-8"));
                                String sub = params.optString("sub");
                                if ("nlp".equals(sub)) {
                                    // 解析得到语义结果
                                    String resultStr = cntJson.optString("intent");
                                    Log.d( TAG, "解析得到语义结果 " + resultStr );
    
                                    JSONObject obj = new JSONObject(resultStr);
                                    JSONObject user = obj.getJSONObject("answer");
                                    String result = user.getString("text");
                                    Log.d( TAG, "获取结果内容 " + result );
                                    ToastUtils.showToast(AiuiActivity.this,"获取结果内容" + result);
                                }
                            }
                        } catch (Throwable e) {
                            e.printStackTrace();
                        }
                    } break;
    
                    case AIUIConstant.EVENT_ERROR: {
                        //错误事件
                        Log.d( TAG,  "on event: "+ event.eventType );
                        Log.d(TAG, "错误: "+event.arg1+"\n"+event.info );
                    } break;
    
                    case AIUIConstant.EVENT_VAD: {
                        if (AIUIConstant.VAD_BOS == event.arg1) {
                            //语音前端点
                        } else if (AIUIConstant.VAD_EOS == event.arg1) {
                            //语音后端点
                        }
                    } break;
    
                    case AIUIConstant.EVENT_START_RECORD: {
                        Log.d( TAG,  "on event: "+ event.eventType );
                        //开始录音
                    } break;
    
                    case AIUIConstant.EVENT_STOP_RECORD: {
                        Log.d( TAG,  "on event: "+ event.eventType );
                        // 停止录音
                    } break;
    
                    case AIUIConstant.EVENT_STATE: {
                        mAIUIState = event.arg1;
                        if (AIUIConstant.STATE_IDLE == event.arg1) {
                            // 闲置状态,AIUI未开启
                        } else if (AIUIConstant.STATE_READY == event.arg1) {
                            // AIUI已就绪,等待唤醒
                        } else if (AIUIConstant.STATE_WORKING == event.arg1) {
                            // AIUI工作中,可进行交互
                        }
                    } break;
    
                    default:
                        break;
                }
            }
        };
    

    最终在AIUIConstant.EVENT_RESULT中解析最终的结果,接下来就是需要获取用户输入的内容然后发送给AIUI,但是这里需要注意一点,在进行语音识别前首先开启唤醒改变AIUI内部状态,只有唤醒状态AIUI才能接收语音输入

     // 先发送唤醒消息,改变AIUI内部状态,只有唤醒状态才能接收语音输入
                    if( AIUIConstant.STATE_WORKING != mAIUIState ){
                        AIUIMessage wakeupMsg = new AIUIMessage(
                                AIUIConstant.CMD_WAKEUP,
                                0,
                                0,
                                "",
                                null);
                        mAIUIAgent.sendMessage(wakeupMsg);
    

    这里我就用讯飞自带的RecognizerDialog,首先实例化RecognizerDialog并设置监听

     private RecognizerDialog mRecognizerDialog;
     // 用HashMap存储听写结果
     private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
    
     mRecognizerDialog = new RecognizerDialog(this,null);
            mRecognizerDialog.setListener(new RecognizerDialogListener() {
                @Override
                public void onResult(RecognizerResult recognizerResult, boolean b) {
                    handleResult(recognizerResult);
                }
    
                @Override
                public void onError(SpeechError speechError) {
    
                }
            });
       mRecognizerDialog.show();
    

    处理听写结果

    private void handleResult(RecognizerResult results) {
            String text = JsonParser.parseIatResult(results.getResultString());
            String sn = null;
            // 读取json结果中的sn字段
            try {
                JSONObject resultJson = new JSONObject(results.getResultString());
                sn = resultJson.optString("sn");
            } catch (JSONException e) {
                e.printStackTrace();
            }
    
            mIatResults.put(sn, text);
            StringBuffer resultBuffer = new StringBuffer();
            for (String key : mIatResults.keySet()) {
                resultBuffer.append(mIatResults.get(key));
            }
            Log.d(TAG,"听写结果 " + resultBuffer.toString());
            sendData(resultBuffer.toString());
    

    发送数据给AIUI

     //发送数据
    public void sendData(String text){
            try {
                // 在输入参数中设置tag,则对应结果中也将携带该tag,可用于关联输入输出
                String params = "data_type=text,tag=text-tag";
                byte[] textData = text.getBytes("utf-8");
                AIUIMessage write = new AIUIMessage(AIUIConstant.CMD_WRITE, 0, 0, params, textData);
                mAIUIAgent.sendMessage(write);
    
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    }
    
    最后我们需要在后台添加我们感兴趣的技能即可 进入详情配置 添加技能 测试结果 测试结果 这里偷了懒并没有把结果解析成对象

    问答QA

    创建问答库 填写问答内容 从图中可以得知问题与答案成多对多的关系,这里回答的答案可以进行设置如下图 回答设置 ,每当填写完新的问答后应用必须重新开启。 测试结果

    自定义技能

    自定义技能看文档需要Node.JS 就不介绍了。

    工具类封装

    这里我就简单封装了下语音合成,识别,唤醒以及AIUI

    初始化各个对象

    /**
         * 初始化引擎
         * @param context 上下文
         * @param appid   appid不解释
         */
        public void initEngine(final Context context, final String appid){
            SpeechUtility.createUtility(context, "appid=" + appid);
            mSpeechSynthesizer = SpeechSynthesizer.createSynthesizer(context, new InitListener() {
                @Override
                public void onInit(int code) {
                    if (code != ErrorCode.SUCCESS) {
                        Log.d(TAG, "语音合成初始化失败,错误码:" + code);
                    } else {
                        Log.d(TAG, "语音合成初始化成功");
                    }
                }
            });
    
            mSpeechRecognizer = SpeechRecognizer.createRecognizer(context, new InitListener() {
                @Override
                public void onInit(int code) {
                    if (code != ErrorCode.SUCCESS) {
                        Log.d(TAG, "语音识别初始化失败,错误码:" + code);
                    } else {
                        Log.d(TAG, "语音识别初始化成功");
                    }
                }
            });
    
            mVoiceWakeuper = VoiceWakeuper.createWakeuper(context, new InitListener() {
                @Override
                public void onInit(int code) {
                    if (code != ErrorCode.SUCCESS) {
                        Log.d(TAG,"唤醒初始化失败,错误码:" + code);
                    }else {
                        Log.d(TAG,"唤醒初始化成功");
                    }
                }
            });
    
            //创建AIUIAgent
            mAiuiAgent = AIUIAgent.createAgent(context,
                    getAIUIParams(context),mAIUIListener);
    
    
        }
    

    语音合成

    
        /**
         * 语音合成对象
         */
        private SpeechSynthesizer mSpeechSynthesizer;
    
        /**
         * 设置合成的参数
         * @param key   参数key
         * @param value  参数值
         */
        public void setSynthesizerParameter(String key,String value){
            Log.d(TAG,"setSynthesizerParameter " + key + " " + value);
            if(null == mSpeechSynthesizer){
                return;
            }
            mSpeechSynthesizer.setParameter(key,value);
        }
    
        /**
         * 开始合成
         * @param text   合成的文本
         */
        public void startSpeak(String text){
            Log.d(TAG,"startSpeak " + text);
            if(null == mSpeechSynthesizer){
                return;
            }
            mSpeechSynthesizer.startSpeaking(text,null);
        }
    
        /**
         * 开始合成
         * @param text   合成的文本
         * @param synthesizerListener  合成的状态
         */
        public void startSpeak(String text, SynthesizerListener synthesizerListener){
            Log.d(TAG,"startSpeak " + text);
            if(null == mSpeechSynthesizer){
                return;
            }
            mSpeechSynthesizer.startSpeaking(text,synthesizerListener);
        }
    
        /**
         * 是否正在合成
         * @return
         */
        public boolean isSpeaking(){
            Log.d(TAG,"isSpeaking ");
            if(null == mSpeechSynthesizer){
                return false;
            }
            return mSpeechSynthesizer.isSpeaking();
        }
    
        /**
         * 停止语音
         */
        public void stopSpeaking(){
            Log.d(TAG,"stopSpeaking ");
            if(null == mSpeechSynthesizer){
                return;
            }
            mSpeechSynthesizer.stopSpeaking();
        }
    
        /**
         * 对应的继续播放
         * 暂停播放
         */
        public void pauseSpeaking(){
            Log.d(TAG,"pauseSpeaking ");
            if(null == mSpeechSynthesizer){
                return;
            }
            mSpeechSynthesizer.pauseSpeaking();
        }
    
        /**
         * 恢复播放
         */
        public void resumeSpeaking(){
            Log.d(TAG,"resumeSpeaking ");
            if(null == mSpeechSynthesizer){
                return;
            }
            mSpeechSynthesizer.resumeSpeaking();
        }
    
        /**
         * 合成到文件 合成文本到一个音频文件,不播放
         * @param text 合成的文本
         * @param uri   合成的路径
         * @return
         */
        public int synthesizeToUri(String text, String uri,SynthesizerListener mSynthesizerListener ){
            Log.d(TAG,"synthesizeToUri ");
            if(null == mSpeechSynthesizer){
                return 0;
            }
            return mSpeechSynthesizer.synthesizeToUri(text,uri,mSynthesizerListener);
        }
    
    

    语音识别

     /**
         * 语音听写对象
         */
        private SpeechRecognizer mSpeechRecognizer;
    
        /**
         * 语音听写对话框
         */
        private RecognizerDialog mRecognizerDialog;
    
        /**
         * 用HashMap存储听写结果
         */
        private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();
    
        /**
         * 设置语音听写参数
         * @param key
         * @param value
         */
        public void setRecognizerParameter(String key,String value){
            Log.d(TAG,"setmRecognizerParameter " + key + " " + value);
            if(null == mSpeechRecognizer){
                return;
            }
            mSpeechRecognizer.setParameter(key,value);
        }
    
    
        /**
         * 开始听写(不带识别框)
         */
        public void startRecognizer(RecognizerListener recognizerListener){
            Log.d(TAG,"startRecognizer " );
            if(null == mSpeechRecognizer){
                return;
            }
            chageAiuiState();
            mSpeechRecognizer.startListening(recognizerListener);
        }
    
        /**
         * 开始听写(带识别框)
         */
        public void startRecognizerDialog(Context context, final SpeechRecongnizerResult recongnizerResult){
            Log.d(TAG,"startRecognizerDialog " );
            chageAiuiState();
            mRecognizerDialog = new RecognizerDialog(context, null);
            mRecognizerDialog.setListener(new RecognizerDialogListener() {
                @Override
                public void onResult(RecognizerResult recognizerResult, boolean b) {
                    String result = handleResult(recognizerResult);
                    if(null != recongnizerResult){
                        recongnizerResult.onResult(result);
                        mRecognizerDialog.dismiss();
                    }
                }
    
                @Override
                public void onError(SpeechError speechError) {
                    if(null != recongnizerResult){
                        recongnizerResult.onError(speechError.getErrorDescription());
                    }
                }
            });
            mRecognizerDialog.show();
        }
    
    
        /**
         * 停止识别
         */
        public void stopRecognizer(){
            Log.d(TAG,"stopRecognizer " );
            if(null == mSpeechRecognizer){
                return;
            }
            mSpeechRecognizer.stopListening();
        }
    
        /**
         * 是否正在识别
         * @return
         */
        public boolean isRecognizer(){
            Log.d(TAG,"isRecognizer " );
            if(null == mSpeechRecognizer){
               return false;
            }
            return mSpeechRecognizer.isListening();
        }
    
    
        /**
         * 处理识别结果
         * @param results
         * @param
         */
        public String handleResult(RecognizerResult results) {
            Log.d(TAG,"handleResult " + results);
            String text = JsonParser.parseIatResult(results.getResultString());
            String sn = null;
            // 读取json结果中的sn字段
            try {
                JSONObject resultJson = new JSONObject(results.getResultString());
                sn = resultJson.optString("sn");
            } catch (JSONException e) {
                e.printStackTrace();
            }
    
            mIatResults.put(sn, text);
            StringBuffer resultBuffer = new StringBuffer();
            for (String key : mIatResults.keySet()) {
                resultBuffer.append(mIatResults.get(key));
            }
            Log.d(TAG,"听写结果 " + resultBuffer.toString());
    
            //向AIUI写入数据
            try {
                // 在输入参数中设置tag,则对应结果中也将携带该tag,可用于关联输入输出
                String params = "data_type=text,tag=text-tag";
                byte[] textData = resultBuffer.toString().getBytes("utf-8");
                AIUIMessage write = new AIUIMessage(AIUIConstant.CMD_WRITE, 0, 0, params, textData);
                mAiuiAgent.sendMessage(write);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return resultBuffer.toString();
        }
    

    语音唤醒

    /**
         * 语音唤醒对象
         */
        private VoiceWakeuper mVoiceWakeuper;
    
        /**
         * 设置唤醒参数
         * @param key
         * @param value
         */
        public void setWakeParame(String key,String value){
            if(null == mVoiceWakeuper){
                return;
            }
            mVoiceWakeuper.setParameter(key,value);
        }
    
    
        /**
         * 获取唤醒资源
         * @param context
         * @param appid
         * @return
         */
        public String getResource(Context context,String appid){
             String resPath = ResourceUtil.
                    generateResourcePath(context,
                            ResourceUtil.RESOURCE_TYPE.assets,
                            "ivw/"+ appid+".jet");
             return resPath;
        }
    
        /**
         * 开启唤醒功能
         */
        public void startWakeuper(WakeuperListener wakeuperListener) {
            if(null == mVoiceWakeuper){
                return;
            }
            mVoiceWakeuper.startListening(wakeuperListener);
        }
    
        /**
         * 停止唤醒
         */
        public void stopWakeuper() {
            mVoiceWakeuper.stopListening();
        }
    
        /**
         * 处理唤醒结果
         * @param wakeuperResult
         */
        public WakeResult handleWakeResult(WakeuperResult wakeuperResult){
            Log.d(TAG,"handleWakeResult " + wakeuperResult);
            WakeResult wakeResult = new WakeResult();
            String text = wakeuperResult.getResultString();
            JSONObject object;
            try {
                object = new JSONObject(text);
                wakeResult.setSst(object.optString("sst"));
                wakeResult.setId(object.optString("id"));
                wakeResult.setScore(object.optString("score"));
                wakeResult.setBos(object.optString("bos"));
                wakeResult.setEos(object.optString("eos"));
                return wakeResult;
            } catch (JSONException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    

    AIUI

     private AIUIAgent mAiuiAgent;
    
       private String getAIUIParams(Context context) {
            String params = "";
            AssetManager assetManager = context.getResources().getAssets();
            try {
                InputStream ins = assetManager.open( "cfg/aiui_phone.cfg" );
                byte[] buffer = new byte[ins.available()];
                ins.read(buffer);
                ins.close();
                params = new String(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return params;
        }
    
        private AIUIListener mAIUIListener = new AIUIListener() {
    
            @Override
            public void onEvent(AIUIEvent event) {
                if(null == mAiuiResultListn){
                    return;
                }
                switch (event.eventType) {
                    case AIUIConstant.EVENT_WAKEUP:
                        //唤醒事件
                        Log.d( TAG,  "on event: "+ event.eventType );
                        mAiuiResultListn.onWakeUp();
                        break;
    
                    case AIUIConstant.EVENT_RESULT: {
                        //结果解析事件
                        try {
                            JSONObject bizParamJson = new JSONObject(event.info);
                            JSONObject data = bizParamJson.getJSONArray("data").getJSONObject(0);
                            JSONObject params = data.getJSONObject("params");
                            JSONObject content = data.getJSONArray("content").getJSONObject(0);
                            if (content.has("cnt_id")) {
                                String cnt_id = content.getString("cnt_id");
                                JSONObject cntJson = new JSONObject(new String(event.data.getByteArray(cnt_id), "utf-8"));
                                String sub = params.optString("sub");
                                if ("nlp".equals(sub)) {
                                    // 解析得到语义结果
                                    String resultStr = cntJson.optString("intent");
                                    Log.d( TAG, "解析得到语义结果 " + resultStr );
                                    JSONObject obj = new JSONObject(resultStr);
                                    JSONObject user = obj.getJSONObject("answer");
                                    String result = user.getString("text");
                                    Log.d( TAG, "获取结果内容 " + result );
                                    mAiuiResultListn.onResult(result);
                                }
                            }
                        } catch (Throwable e) {
                            e.printStackTrace();
                            mAiuiResultListn.onResult("我还不知道您说什么,您可以到技能商店添加应用哦");
                        }
                    } break;
    
                    case AIUIConstant.EVENT_ERROR: {
                        //错误事件
                        Log.d( TAG,  "on event: "+ event.eventType );
                        Log.d(TAG, "错误: "+event.arg1+"\n"+event.info );
                        mAiuiResultListn.onError(event.arg1+"\n"+event.info );
                    } break;
    
                    case AIUIConstant.EVENT_VAD: {
                        if (AIUIConstant.VAD_BOS == event.arg1) {
                            //语音前端点
                        } else if (AIUIConstant.VAD_EOS == event.arg1) {
                            //语音后端点
                        }
                    } break;
    
                    case AIUIConstant.EVENT_START_RECORD: {
                        Log.d( TAG,  "on event: "+ event.eventType );
                        //开始录音
                    } break;
    
                    case AIUIConstant.EVENT_STOP_RECORD: {
                        Log.d( TAG,  "on event: "+ event.eventType );
                        // 停止录音
                    } break;
    
                    case AIUIConstant.EVENT_STATE: {
                        mAiuiResultListn.onAiuiState(event.arg1);
                        if (AIUIConstant.STATE_IDLE == event.arg1) {
                            // 闲置状态,AIUI未开启
                        } else if (AIUIConstant.STATE_READY == event.arg1) {
                            // AIUI已就绪,等待唤醒
                        } else if (AIUIConstant.STATE_WORKING == event.arg1) {
                            // AIUI工作中,可进行交互
                        }
                    } break;
    
                    default:
                        break;
                }
            }
        };
    
       private AiuiResultListn mAiuiResultListn;
       public void setAiuiResultListn(AiuiResultListn aiuiResultListn){
           this.mAiuiResultListn = aiuiResultListn;
       }
    
    
        /**
         * 改变AIUI状态,使其接收写入的内容,
         * 但是到了指定的时间后自动关闭,可再
         * 设置参数中设置超时时间
         */
        private void chageAiuiState(){
            AIUIMessage wakeupMsg = new AIUIMessage(
                    AIUIConstant.CMD_WAKEUP,
                    0,
                    0,
                    "",
                    null);
            mAiuiAgent.sendMessage(wakeupMsg);
        }
    
    释放资源
    /**
         * 释放资源
         */
        public void destory(){
            if(null != mSpeechSynthesizer){
                mSpeechSynthesizer.stopSpeaking();
                mSpeechSynthesizer.destroy();
                mSpeechSynthesizer = null;
            }
            if(null != mSpeechRecognizer){
                mSpeechRecognizer.stopListening();
                mSpeechRecognizer.destroy();
                mSpeechRecognizer = null;
            }
            if (mVoiceWakeuper != null) {
                mVoiceWakeuper.destroy();
                mVoiceWakeuper = null;
            }
            if(null != mAiuiAgent){
                mAiuiAgent.destroy();
                mAiuiAgent = null;
            }
        }
    

    涉及的接口以及实体类

    public interface AiuiResultListn {
    
        void onWakeUp();
    
        void onError(String errorMsg);
    
        void onAiuiState(int state);
    
        void onResult(String result);
    
    }
    
    public interface SpeechRecongnizerResult {
    
        void onResult(String result);
    
        void onError(String errorMsg);
    }
    
    public class WakeResult {
    
        //操作类型
        private String sst;
        //唤醒词id
        private String id;
        //得分
        private String score;
        //前端点
        private String bos;
        //尾端点
        private String eos;
    }
    
    主界面 测试界面
    项目地址把自己的jar包与so包替换并在AppSetting中设置您的APPID

    相关文章

      网友评论

        本文标题:Android修真传之讯飞语音识别第二篇

        本文链接:https://www.haomeiwen.com/subject/ksoflqtx.html