业界干货Android _ 资源、知识总结链接目录 + 框架

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

2018-12-25  本文已影响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
上一篇下一篇

猜你喜欢

热点阅读