android之基于百度语音合讯飞语音识别的语音交互

app:http://fir.im/gval 这里面包含拨盘UI

开发平台:android studio

模拟一个  原始需求如下:

1)  在界面上,通过声音提示用户讲话;

2)  将语音内容转换为文字并存储。

例如:用户启动应用后,点击按键后,应用问“请问你在哪个国家”,5s后如果用户不回答,再问“请问你在哪个国家”,如果5s后,用户仍然不回答,不再询问。如果5s内用户回答,则将内容记录下来,记录完毕后,再继续问“请问你在那个城市”。

       这个真的是,困难很多,虽然现在做好了,但是我有很多要分享的

       一开始我是使用百度的接口,百度有提供demo,这个就不说了,下载了语音识别和语音合成,语音合成的没什么声音,虽然声音不太好听,但是语音识别的问题太多了,这两个肯定不是一拨人写的,从代码风格就可以看出来,去他的官网找资料,反正我是没找过什么有用的,语音识别那个,给了一个app,那个跟给的源码都不是一个,简直醉了,把提供的源码搞到项目里,项目可以运行,或许是androidstudio的缘故,要么就是源码有问题,反正问题很多,

对了这里要说一个androidstudio导jar文件和so 文件的,jar文件就拷贝到lib下,右击倒数2-3那边就好了,so文件需要新建一个jniLibs的文件夹,so文件包括文件夹拷贝到这个目录下,使用百度的需要把两个jar文件都加入进来

        使用百度的语音识别,我在小米5+的系统上,麦克风一直起不来,该给的权限都给了,可能是系统的问题,这个浪费了我两天时间,不得不说,百度的源码做的不太方便,不方便使用和阅读,

 从百度的语音合成上学到一个首页的布局

public class MainActivity extends PreferenceActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.addPreferencesFromResource(R.xml.category);
    }

}
然后xml文件:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                  android:key="root_screen">

    <Preference android:title="Version 1.2.6" >

    </Preference>
    <Preference android:title="拨盘UI" >
        <intent
                android:targetPackage="android.cl.com.tts"
                android:targetClass="android.cl.com.tts.UIActivity" >
        </intent>
    </Preference>


    <Preference android:title="Only 小Q speaking" >
        <intent
            android:targetPackage="android.cl.com.tts"
            android:targetClass="android.cl.com.tts.BaiDuWordToVoiceActivity" >
        </intent>
    </Preference>

    <Preference android:title="Only you speaking" >
        <intent
            android:targetPackage="android.cl.com.tts"
            android:targetClass="android.cl.com.tts.IFVoiceToWordActivity" >
        </intent>
    </Preference>

    <Preference android:title="小Q 语音交互" >
        <intent
            android:targetPackage="android.cl.com.tts"
            android:targetClass="android.cl.com.tts.TTSActivity" >
        </intent>
    </Preference>
</PreferenceScreen>
不需要写按钮啦,监听啦,个人很喜欢,适合做界面跳转页

然后就找到讯飞的语音,这个怎么说呢,写的很好,怪我不是使用,反正我把这两个功能的源码下载下来,或许是我使用的工具
android studio的问题,反正源码我 出现21001错误码的分析,没时间解决,不知道什么问题
看这位前辈的 看着很有用 http://blog.csdn.net/q610098308/article/details/46981715

后来跟同学要了一个讯飞以前的VoiceToWord源码

这个试了一下,写的简洁,但是功能都有,哈哈哈,一下子找到出路了,用百度的语音合成,用讯飞的语音识别

android之基于百度语音合讯飞语音识别的语音交互_第1张图片
这边主要就是如何让机器说完了,然后用户说,机器记录显示,机器再提示语音,同时需要判断是否要问同一个问题

android之基于百度语音合讯飞语音识别的语音交互_第2张图片

我这些算法的代码都在一个文件里,就直接上代码:

package android.cl.com.tts;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.Toast;

import com.iflytek.cloud.speech.RecognizerResult;
import com.iflytek.cloud.speech.SpeechConstant;
import com.iflytek.cloud.speech.SpeechError;
import com.iflytek.cloud.speech.SpeechListener;
import com.iflytek.cloud.speech.SpeechUser;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;

import java.util.ArrayList;
import java.util.List;

import BaiDuUtil.SpeechUtil;
import IFVoiceUtil.JsonParser;

public class TTSActivity extends AppCompatActivity {

    private SpeechUtil speechUtil;
    private Button btn;

    //处理结果
    private ListView listView;
    private List<String> ls;
    private String[] params = {"你好,请问你在哪个国家", "请问你在哪个城市", "请问你的新年愿望是什么", "祝你新的一年心想事成"};
    private int i = 0; //记录params 下标
    private int count = 2;//一个问题询问两次

    //识别窗口
    private RecognizerDialog iatDialog;
    private  boolean listen = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_tts);

        init();

        btn = (Button) findViewById(R.id.btn_tts);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                //voice.GetWordFromVoice();这个方法必须要所在的函数全部执行完界面才会出现,
                //所以更新界面的方式放在监听器里去执行
//                voice.GetWordFromVoice();

                getMessage();

//                if (i < params.length && count > 0) {
////                    SpeechUser.getUser().login(TTSActivity.this, null, null, "appid=5687e671", listener);
//                    btn.setText("下一个问题");
//                } else {
//
//                    restart();
////                    btn.setClickable(false);
//                }

            }
        });

        //飞科授权登陆                                                换成自己的Id
        SpeechUser.getUser().login(TTSActivity.this, null, null, "appid=000000", listener);
    }


    private void init() {
        speechUtil = new SpeechUtil(this);
        ls = new ArrayList<String>();
        //获取xml文件中listView控件
        listView = (ListView) findViewById(R.id.resultListView);
        //初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer
        iatDialog = new RecognizerDialog(this);
        ls.add("Version 2.0");
        ls.add("Just a minute...");
        listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, ls));
    }

    private void getMessage() {
        if (check()) {
            //不管回答与否,先进入下一个问题 这段代码OK
//            Log.e("msg", "speak");
//            Toast.makeText(this, "小Q,已经在准备说话啦", Toast.LENGTH_LONG).show();
            speechUtil.speak(params[i++]);


            Log.e("msg", "wait");
           //不是最后一句
            if(i < params.length){
                //语音没有说完
                while (!speechUtil.getStopmessage()) {
                    Log.e("msg", "speak waiting...");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //啊啊啊啊啊啊啊啊啊,看来是这儿的问题,语音说完了,我忘了设置 setStopmessage(false);
                //提示语音需要联网,肯定没有本地主线程跑的快呀,while语句直接没有执行
                //就是这儿的问题,
//                Toast.makeText(this, "请在屏幕变化时回答小Q的问题", Toast.LENGTH_LONG).show();
                speechUtil.setStopmessage(false);

                Log.e("msg", "next");
                //voice.GetWordFromVoice();这个方法必须要所在的函数全部执行完界面才会出现

                listen = true;
                GetWordFromVoiceLocal();
                btn.setText("下一个问题");
                Log.e("msg", "GetVoice");
            }

//        }else if(count == 0 || i == (params.length - 1) ){
        }else {
            //2 次未回答 ,全部回答完
            //提示最后一句
            speechUtil.speak(params[i]);
            listen = false;//不需要监听
            Log.e("msg",params[i] );
//            Log.e("msg", "wait");
            //语音没有说完
            while (!speechUtil.getStopmessage()) {
                Log.e("msg", "speak waiting...");
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            speechUtil.setStopmessage(false);

            restart();
        }
    }
    private void restart(){
        btn.setText("重新交互");
        i = 0;
        count = 2;
        ls.clear();
        ls.add("Version 2.0");
        ls.add("Just a minute...");
        listView.setAdapter(new ArrayAdapter<String>(TTSActivity.this, android.R.layout.simple_list_item_1, ls));
    }
    private Boolean check() {
        // 2次未回答     问题全部问完
        if (count > 0 && i < (params.length-1)) {
            return true;
        }else{
            return false;
        }

    }

    private void show(String message) {
//        if(checkMessage(message)){
            ls.add(message);
            //然后为listView控件调用setAdapter方法,让数据显示在界面上。
            listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, ls));
//        }

    }
    //去掉 “ 。 ? !” 这些都是识别的结果,不知为何
    private Boolean checkMessage(String message) {

//        if ("。".equals(message) ||"?".equals(message) || checkList(message) ) {
        if ("。".equals(message) ||"?".equals(message)||"!".equals(message)  ) {
            return false;
        }
        return true;
    }
    //去掉  提问的问题
    private Boolean checkList(String message) {

        for(int j = 0;j < params.length;j++){
            if( params[j].equals(message))
                return true;
        }
        return false;
    }

    public void GetWordFromVoiceLocal() {


        iatDialog.setParameter(SpeechConstant.DOMAIN, "iat");
        //设置识别语言为中文
        iatDialog.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
        //设置方言为普通话
        iatDialog.setParameter(SpeechConstant.ACCENT, "mandarin");
        //设置录音采样率为
        iatDialog.setParameter(SpeechConstant.SAMPLE_RATE, "16000");
        //清空Grammar_ID,防止识别后进行听写时Grammar_ID的干扰
        iatDialog.setParameter(SpeechConstant.CLOUD_GRAMMAR, null);
        //设置监听对象
        iatDialog.setListener(recognizerDialogListener);
        //开始识别
        iatDialog.show();

    }

    /**
     * 用户登录回调监听器.
     */
    private SpeechListener listener = new SpeechListener() {
        @Override
        public void onData(byte[] arg0) {
        }
        @Override
        public void onCompleted(SpeechError error) {
            if (error != null) {
//                System.out.println("user login success");
                Log.e("msg", "user login success");
            }
        }
        @Override
        public void onEvent(int arg0, Bundle arg1) {
        }
    };
    private RecognizerDialogListener recognizerDialogListener = new RecognizerDialogListener() {

        //自定义的结果回调函数,成功执行第一个方法,失败执行第二个方法
        @Override
        public void onResult(RecognizerResult results, boolean isLast) {

            //想想问题是它总是在监听,没有提供类似监听停止的函数,所以我给它加一个判断
            //语音没有播报完前不可以监听,试试吧,感觉可以实现

            //不过加了 listen 可以成功把 “。 ? !”这些过滤掉,哈哈哈,也是有用的
            if(listen) {

                String text = JsonParser.parseIatResult(results.getResultString());
                Log.e("msg", text);
                if (i != params.length) {
                    count = 2;
                    show(text);
                }
                listen = false;
            }
            //取消监听对象 ,对话框的 kill,效果就是语音说完,对话框再出现
            //下面的都不行,总是第一句问答没有问题,从第二句开始总是监听机器播放的
//            iatDialog.setListener(null);
//            iatDialog.destroy();
//            iatDialog.cancel();
//            iatDialog.hide();
//            iatDialog  = null;
//            Log.e("msg", "iatDialog  = null;");
//            iatDialog.dismiss()不能用,一使用就强行退出了
//            iatDialog.dismiss();



        }
        /**
         * 识别回调错误.
         */
        @Override
        public void onError(SpeechError error) {
            // TODO Auto-generated method stub
            int errorCoder = error.getErrorCode();
            switch (errorCoder) {
                case 10118:

                    Log.e("msg", "10118");
                    if (i <( params.length-1 )) {
                        //第一个问题
                        if(i > 0){
                            i--;
                        }

                        count --;
                        btn.setText("继续同一个问题");
                    }
                    iatDialog.hide();
//                    iatDialog.setListener(null);
//                    SpeechUser.getUser().logout();
                    break;
                case 10204:

                    Log.e("msg", "10204");
                    iatDialog.hide();

//				System.out.println("can't connect to internet");
                    break;
                default:
                    break;
            }
        }
    };
}


一开始忘了设置一个参数 speechUtil.setStopmessage(false);,导致第一问答没有问题,但是第二句提问时,直接就录音了,没有录上用户的语音,反而录上机器的播放的语音,这个问题很奇怪,昨天夜里搞到两点多,把基本的语音顺序播放,等待用户语音输入给弄好,虽然存在这个问题,但是毕竟前进了一大步嘛

昨天的思路是想把那个 RecognizerDialog  给kill 了

地下这几个参数我都试了,可是都达不到想要的效果,或者说直接没有用

//取消监听对象 ,对话框的 kill,效果就是语音说完,对话框再出现
            //下面的都不行,总是第一句问答没有问题,从第二句开始总是监听机器播放的
//            iatDialog.setListener(null);
//            iatDialog.destroy();
//            iatDialog.cancel();
//            iatDialog.hide();
//            iatDialog  = null;
//            Log.e("msg", "iatDialog  = null;");
//            iatDialog.dismiss()不能用,一使用就强行退出了
//            iatDialog.dismiss();


发现 RecognizerDialogListener 一直在工作,找不到什么方法让其停止,除非kill  Activity,

就想用一个变量判断一下是否接收监听消息

//想想问题是它总是在监听,没有提供类似监听停止的函数,所以我给它加一个判断
            //语音没有播报完前不可以监听,试试吧,感觉可以实现

            //不过加了 listen 可以成功把 “。 ? !”这些过滤掉,哈哈哈,也是有用的
            if(listen) {

                String text = JsonParser.parseIatResult(results.getResultString());
                Log.e("msg", text);
                if (i != params.length) {
                    count = 2;
                    show(text);
                }
                listen = false;
            }

后来调试了一下,发现在这里

 <span style="white-space:pre">		</span>//语音没有说完
                while (!speechUtil.getStopmessage()) {
                    Log.e("msg", "speak waiting...");
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                //啊啊啊啊啊啊啊啊啊,看来是这儿的问题,语音说完了,我忘了设置 setStopmessage(false);
                //提示语音需要联网,肯定没有本地主线程跑的快呀,while语句直接没有执行
                //就是这儿的问题,

                speechUtil.setStopmessage(false);
上面代码最后一句,看一下是什么

 //说话语音结束
    private Boolean stopmessage = false;

    public Boolean getStopmessage() {
        return stopmessage;
    }

    public void setStopmessage(Boolean stopmessage) {
        this.stopmessage = stopmessage;
    }
while 循环结束后,那个值是 true,表示已经讲完,下一次再判断时,while循环里直接被跳过了,因为条件不符合


这个问题解决了,感觉天都快亮了,轮流应答解决了,剩下的就是一下小问题了,算是代码的逻辑问题吧,怎么一步一步代码执行完,上面的代码都有注释

OK,基本算是完成了


有需要的可以自行下载源码扩展

为什么需要 1 分,首先申明我不是缺这一分,是担心有人瞎下载源码,用作其他用途,所以加了限制,但是又不会需要你太多分

如果你需要,但是有没有分,可以私信我,或者:[email protected],不一定及时回复哦!

附件:

源码:不是一个项目,由于使用android studio,所以上传的是一个module,这里面包含拨盘UI

http://download.csdn.net/detail/i_do_can/9389208

你可能感兴趣的:(语音,讯飞语音,文字转语音,语音交互,语音转文字)