Android 讯飞语音识别功能开发

以下代码主要参考博客:
Android 科大讯飞语音识别

Android蓝牙串口开发部分请参照博客:
Android蓝牙串口开发

讯飞语音官方开发文档:
语音听写 Android SDK 文档

文章目录

前言

语音识别目前使用的比较频繁,项目需要使用语音识别用户指令,然后通过蓝牙通信传递指定,命令下位机做出反应。手机端主要负责命令的发送,选用讯飞语音SDK,学习官方文档和参考博客进行开发。写这篇博客记录一下。

一、SDK的下载和导入

这一部分可以可以参照讯飞语音官方文档来进行
官方文档:语音听写 Android SDK 文档

1.SDK的下载

首先,登录iFLYTEK开放平台。没有要注册的帐户。

[En]

First of all, log in on the iFLYTEK open platform. There is no account to register.

Android 讯飞语音识别功能开发
在控制台中,按照流程创建新的应用程序。
[En]

In the console, follow the process to create a new application.

Android 讯飞语音识别功能开发
Android 讯飞语音识别功能开发
在下方的SDK下载中,下载相应的SDK。
Android 讯飞语音识别功能开发
解压缩完成后,首先设置项目。
[En]

After the decompression is completed, set up the project first.

; 2.新建工程

打开Android Studio 开发平台,新建工程画好前端设计界面,建立工程这一部分就不在赘述。

Android 讯飞语音识别功能开发

3.配置项目

a.导包

将解压后的libs文件夹中的文件放入项目的libs文件夹中。

Android 讯飞语音识别功能开发
Android 讯飞语音识别功能开发
Android 讯飞语音识别功能开发

对Msc包右键,选择Add As Library导入,此时Msc包可展开。
然后再添加assets,将assets文件夹添加到工程main文件夹下面。

Android 讯飞语音识别功能开发

; b.权限

导包完成后,我们需要给App一些必要权限,来使用手机的硬件功能。


    <uses-permission android:name="android.permission.INTERNET"/>

    <uses-permission android:name="android.permission.RECORD_AUDIO"/>

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>

    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

    <uses-permission android:name="android.permission.READ_CONTACTS"/>

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <uses-permission android:name="android.permission.WRITE_SETTINGS"
        tools:ignore="ProtectedPermissions" />

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>

    <uses-permission android:name="android.permission.CAMERA" />

c.修改buid.gradle

打开buid.gradle后,在文件中做以下修改。

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    implementation files('libs/Msc.jar')
}

然后点击Sync Now。

Android 讯飞语音识别功能开发

二、工具类

1.Json解析类

识别语音时,需要用到Json格式,所以需要有一个解析Json格式的类。
在工程中,新建一个JsonParser 的类。

package com.example.speechrecognitionforbluetooth;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;

public class JsonParser {

    public static String parseIatResult(String json) {
        StringBuffer ret = new StringBuffer();
        try {
            JSONTokener tokener = new JSONTokener(json);
            JSONObject joResult = new JSONObject(tokener);

            JSONArray words = joResult.getJSONArray("ws");
            for (int i = 0; i < words.length(); i++) {

                JSONArray items = words.getJSONObject(i).getJSONArray("cw");
                JSONObject obj = items.getJSONObject(0);
                ret.append(obj.getString("w"));

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret.toString();
    }

    public static String parseGrammarResult(String json) {
        StringBuffer ret = new StringBuffer();
        try {
            JSONTokener tokener = new JSONTokener(json);
            JSONObject joResult = new JSONObject(tokener);

            JSONArray words = joResult.getJSONArray("ws");
            for (int i = 0; i < words.length(); i++) {
                JSONArray items = words.getJSONObject(i).getJSONArray("cw");
                for(int j = 0; j < items.length(); j++)
                {
                    JSONObject obj = items.getJSONObject(j);
                    if(obj.getString("w").contains("nomatch"))
                    {
                        ret.append("没有匹配结果.");
                        return ret.toString();
                    }
                    ret.append("【结果】" + obj.getString("w"));
                    ret.append("【置信度】" + obj.getInt("sc"));
                    ret.append("\n");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            ret.append("没有匹配结果.");
        }
        return ret.toString();
    }

    public static String parseLocalGrammarResult(String json) {
        StringBuffer ret = new StringBuffer();
        try {
            JSONTokener tokener = new JSONTokener(json);
            JSONObject joResult = new JSONObject(tokener);

            JSONArray words = joResult.getJSONArray("ws");
            for (int i = 0; i < words.length(); i++) {
                JSONArray items = words.getJSONObject(i).getJSONArray("cw");
                for(int j = 0; j < items.length(); j++)
                {
                    JSONObject obj = items.getJSONObject(j);
                    if(obj.getString("w").contains("nomatch"))
                    {
                        ret.append("没有匹配结果.");
                        return ret.toString();
                    }
                    ret.append("【结果】" + obj.getString("w"));
                    ret.append("\n");
                }
            }
            ret.append("【置信度】" + joResult.optInt("sc"));

        } catch (Exception e) {
            e.printStackTrace();
            ret.append("没有匹配结果.");
        }
        return ret.toString();
    }

    public static String parseTransResult(String json, String key) {
        StringBuffer ret = new StringBuffer();
        try {
            JSONTokener tokener = new JSONTokener(json);
            JSONObject joResult = new JSONObject(tokener);
            String errorCode = joResult.optString("ret");
            if(!errorCode.equals("0")) {
                return joResult.optString("errmsg");
            }
            JSONObject transResult = joResult.optJSONObject("trans_result");
            ret.append(transResult.optString(key));

        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret.toString();
    }
}

用于进行语音识别的方法调用。

[En]

A method call used to give speech recognition.

2.语音识别相关方法

现在需要实现语音识别的核心代码了,具体代码请参考官方文档Demo或访问参考博客学习,这里做一个展示。

a.变量声明

首先,比较要导入的包。

[En]

First, compare the package you want to import.

import com.iflytek.cloud.ErrorCode;
import com.iflytek.cloud.InitListener;
import com.iflytek.cloud.RecognizerResult;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechRecognizer;
import com.iflytek.cloud.ui.RecognizerDialog;
import com.iflytek.cloud.ui.RecognizerDialogListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import static android.widget.Toast.LENGTH_SHORT;

为语音识别部分声明必要的变量。

[En]

Declare the necessary variables for the speech recognition part.


    private SpeechRecognizer mIat;
    private RecognizerDialog mIatDialog;

    private HashMap<String, String> mIatResults = new LinkedHashMap<String, String>();

    private SharedPreferences mSharedPreferences;

    private String mEngineType = SpeechConstant.TYPE_CLOUD;
    private String language = "zh_cn";

    private TextView tvResult;

    private Button mBTN_SPEECH;
    private String resultType = "json";

b.权限请求

在调用过程中,您需要动态获取权限。

[En]

During the call, you need to obtain permissions dynamically.


    private void initPermission() {
        String permissions[] = {Manifest.permission.RECORD_AUDIO,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.INTERNET,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };

        ArrayList<String> toApplyList = new ArrayList<String>();

        for (String perm : permissions) {
            if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(this, perm)) {
                toApplyList.add(perm);
            }
        }
        String tmpList[] = new String[toApplyList.size()];
        if (!toApplyList.isEmpty()) {
            ActivityCompat.requestPermissions(this, toApplyList.toArray(tmpList), 123);
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    }

c.语音监听


    private InitListener mInitListener = new InitListener() {

        @Override
        public void onInit(int code) {
            Log.d(TAG, "SpeechRecognizer init() code = " + code);
            if (code != ErrorCode.SUCCESS) {
                showMsg("初始化失败,错误码:" + code + ",请点击网址https://www.xfyun.cn/document/error-code查询解决方案");
            }
        }
    };

    private RecognizerDialogListener mRecognizerDialogListener = new RecognizerDialogListener() {
        public void onResult(RecognizerResult results, boolean isLast) {

            printResult(results);

        }

        public void onError(SpeechError error) {
            showMsg(error.getPlainDescription(true));
        }

    };

    private void showMsg(String msg) {
        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (null != mIat) {

            mIat.cancel();
            mIat.destroy();
        }
    }

d.数据解析

分析得到的数据,利用Text将结果显示出来,然后分析结果,利用蓝牙将指令发送出去。


    private void printResult(RecognizerResult results) {
        String text = JsonParser.parseIatResult(results.getResultString());

        String sn = null;

        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));
        }

        mET_DATE.setText(resultBuffer.toString());
        sendCMDByBluetooth(resultBuffer.toString());
    }

c.参数配置


    public void setParam() {

        mIat.setParameter(SpeechConstant.PARAMS, null);

        mIat.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType);

        mIat.setParameter(SpeechConstant.RESULT_TYPE, resultType);

        if (language.equals("zh_cn")) {
            String lag = mSharedPreferences.getString("iat_language_preference",
                    "mandarin");
            Log.e(TAG, "language:" + language);
            mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");

            mIat.setParameter(SpeechConstant.ACCENT, lag);
        } else {

            mIat.setParameter(SpeechConstant.LANGUAGE, language);
        }
        Log.e(TAG, "last language:" + mIat.getParameter(SpeechConstant.LANGUAGE));

        mIat.setParameter(SpeechConstant.VAD_BOS, mSharedPreferences.getString("iat_vadbos_preference", "4000"));

        mIat.setParameter(SpeechConstant.VAD_EOS, mSharedPreferences.getString("iat_vadeos_preference", "1000"));

        mIat.setParameter(SpeechConstant.ASR_PTT, mSharedPreferences.getString("iat_punc_preference", "1"));

        mIat.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mIat.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/iat.wav");
    }

三、调用代码编写

准备工作基本完成后,我们现在需要在主程序中调用该方法以逻辑地实现函数。

[En]

After the preparatory work has been basically completed, we now need to call the method to implement the function logically in the main program.

1.点击事件的监听

首先,实现了对屏幕点击事件的监控。

[En]

First of all, the screen to achieve a click event monitoring.

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private static final String TAG ="MainActivity" ;

    @Override
    public void onClick(View v) {
        if( null == mIat ){

            showMsg( "创建对象失败,请确认 libmsc.so 放置正确,且有调用 createUtility 进行初始化" );
            return;
        }

        mIatResults.clear();
        setParam();
        mIatDialog.setListener(mRecognizerDialogListener);
        mIatDialog.show();
    }
}

2.识别结果的显示

结果的显示包含在用于数据分析的部分代码中

[En]

The display of the results is contained in part of the code for data analysis


mET_DATE.setText(resultBuffer.toString());
sendCMDByBluetooth(resultBuffer.toString());

3.语音命令识别和发送

在检测到语音输入后,生成识别结果,并显示后,根据您需要的判断逻辑对识别结果进行分析,并发出指令。

[En]

After the speech input is detected, a recognition result is generated, and after it is displayed, the recognition result is analyzed according to the judgment logic you need, and an instruction is issued.


    public void sendCMDByBluetooth(String Speech){

        String CMD = Speech.substring(0,Speech.indexOf("。"));

        if (CONNECT_STATUS) {
            switch (CMD){
                case "打开灯光":{
                    write("A");
                    Toast.makeText(MainActivity.this, "指令:打开灯光 CMD:A", LENGTH_SHORT).show();
                    break;
                }
                case "关闭灯光":{
                    write("B");
                    Toast.makeText(MainActivity.this, "指令:关闭灯光 CMD:B", LENGTH_SHORT).show();
                    break;
                }
                case "打开风扇":{
                    write("C");
                    Toast.makeText(MainActivity.this, "指令:打开风扇 CMD:C", LENGTH_SHORT).show();
                    break;
                }
                case "关闭风扇":{
                    write("D");
                    Toast.makeText(MainActivity.this, "指令:关闭风扇 CMD:D", LENGTH_SHORT).show();
                    break;
                }
            }
        } else {
            Toast.makeText(getApplicationContext(), "请先连接蓝牙", Toast.LENGTH_SHORT).show();
        }

    }

总结

Android 讯飞语音识别功能开发

对我来说,该项目主要的难点在于对SDK的使用,以及类的调用。更灵活的使用还需要加深理解。

关于Android经典蓝牙串口开发在我的另一篇博客有记录。
Android蓝牙串口开发

Original: https://blog.csdn.net/u011604460/article/details/124294562
Author: CallMeMinxJ
Title: Android 讯飞语音识别功能开发

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/527221/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球