科大讯飞离线语音命令词识别的使用说明

科大讯飞离线语音命令词识别的使用说明最近因为项目的需求 需要在无网络的情况下实现语音识别的功能 因为之前在线识别一直用的科大的 所以经理就和我说 你花半天时间简单熟悉一下 然后出一个 Demo 下午有人过来看 因为之前科大在线 SR 也是别人做的 准确的说我只是了解过一点

大家好,我是讯享网,很高兴认识大家。

      最近因为项目的需求,需要在无网络的情况下实现语音识别的功能,因为之前在线识别一直用的科大的,所以经理就和我说,你花半天时间简单熟悉一下,然后出一个Demo,下午有人过来看;因为之前科大在线SR也是别人做的,准确的说我只是了解过一点,也写过相关的blog——百度语音识别结合云知声离线TTSDemo(AS),Android原生TTS的基本使用以及配合中文语音包实现中文TTS等,但是就半天不到的时间写一个Demo还是很赶的,比较不熟悉。下面就来简单的总结一下这半天的经历。   

源码下载地址

 

第一阶段    基础准备

第一步:找到科大讯飞开发平台官网,注册账户

平台地址

第二步:点击右上角“控制台”进入个人控制台


讯享网

第三步:创建应用,根据选择的服务生成SDK并下载

 

      这里我们添加离线命令词识别服务,获取了对应SDK之后,也就完成的最基本的准备工作了,生成的APPID很重要哟,这个不用说你也应该知道。我们的第一阶段就算完成了

 

第二阶段    Demo导入

第四步:打开AS,创建一个和上图同名的应用

第五步:导入SDK解压文件夹下的sample目录里面的的mscV5PlusDemomodule

 

这里面需要实现在AS项目中导入module操作,如下图所示:

 

选择上面sample下面对应的mscV5PlusDemo即可,如果有需要调整sdk版本的就按照错误提示调整就好了,比较简单;至此,我们就把SDK中的Demo(mscV5PlusDemo)导入到了我们的项目中:

 

第六步:这个时候选择导入的module,在arm机上运行,发现并不能正常运行,那么你需要考虑以下几个问题

(1)Demo中的离线命令词识别的commen.jet文件位置错误

在解压文件夹的res目录下找到asr文件夹,将其copy到Demo里面的assets目录下:

 

(2)一定要在arm机上测试,因为这个Demo里面只有armeabi的so文件

(3)如果可以运行,进入如下界面,发现里面不仅仅只有我们需要的离线命令词识别,还有在线识别等等:

 

我们点击“立刻体验语法识别”,关闭设备网络,选择下图中的“本地”,然后点击“构建语法”,再点击“开始识别”;

这个时候很有可能再报错误,查看错误码发现原来是没有录音权限等权限问题,这个时候你就纳闷了,明明Demo代码中已经添加了权限:

 <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.INTERNET" /> <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.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BROADCAST_STICKY" />

讯享网

为什么还有问题,这个时候你再进入到Demo代码里面查看,里面并没有做6.0以及以上版本的动态权限申请处理,所以怎么办了,要么我们自己加上,要么换一个低一点的机子测试一下。

讯享网// 开始识别,没有权限判断 case R.id.isr_recognize: ((EditText)findViewById(R.id.isr_text)).setText(null);// 清空显示内容 // 设置参数 if (!setParam()) { showTip("请先构建语法。"); return; }; ret = mAsr.startListening(mRecognizerListener); if (ret != ErrorCode.SUCCESS) { showTip("识别失败,错误码: " + ret); } break; 

这里我们就不深究了,因为后面还有好多内容了,假设这个时候你能够正常运行了,也能在Demo中完成离线命令词识别了。那么下一阶段就是瘦身处理了。

 

第三阶段    功能瘦身

第七步:提取离线命令词识别功能

      不得不说,这个Demo对于我们只使用离线命令词识别来说有一点冗余,太多了;下面我们就来把离线命令词功能抽取出来,如下图:

 

实现离线命令词识别的功能实现主要是上图中红色框中AsrDemo中的逻辑,其源码如下:

package com.iflytek.mscv5plusdemo; import android.annotation.SuppressLint; import android.app.Activity; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.RadioGroup.OnCheckedChangeListener; import android.widget.Toast; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.GrammarListener; import com.iflytek.cloud.InitListener; import com.iflytek.cloud.LexiconListener; import com.iflytek.cloud.RecognizerListener; import com.iflytek.cloud.RecognizerResult; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechRecognizer; import com.iflytek.cloud.util.ContactManager; import com.iflytek.cloud.util.ContactManager.ContactListener; import com.iflytek.cloud.util.ResourceUtil; import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE; import com.iflytek.speech.util.FucUtil; import com.iflytek.speech.util.JsonParser; import com.iflytek.speech.util.XmlParser; public class AsrDemo extends Activity implements OnClickListener{ private static String TAG = AsrDemo.class.getSimpleName(); // 语音识别对象 private SpeechRecognizer mAsr; private Toast mToast; // 缓存 private SharedPreferences mSharedPreferences; // 本地语法文件 private String mLocalGrammar = null; // 本地词典 private String mLocalLexicon = null; // 云端语法文件 private String mCloudGrammar = null; // 本地语法构建路径 private String grmPath = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/msc/test"; // 返回结果格式,支持:xml,json private String mResultType = "json"; private final String KEY_GRAMMAR_ABNF_ID = "grammar_abnf_id"; private final String GRAMMAR_TYPE_ABNF = "abnf"; private final String GRAMMAR_TYPE_BNF = "bnf"; private String mEngineType = "cloud"; @SuppressLint("ShowToast") public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.isrdemo); initLayout(); // 初始化识别对象 mAsr = SpeechRecognizer.createRecognizer(this, mInitListener); // 初始化语法、命令词 mLocalLexicon = "张海羊\n刘婧\n王锋\n"; mLocalGrammar = FucUtil.readFile(this,"call.bnf", "utf-8"); mCloudGrammar = FucUtil.readFile(this,"grammar_sample.abnf","utf-8"); // 获取联系人,本地更新词典时使用 ContactManager mgr = ContactManager.createManager(AsrDemo.this, mContactListener); mgr.asyncQueryAllContactsName(); mSharedPreferences = getSharedPreferences(getPackageName(), MODE_PRIVATE); mToast = Toast.makeText(this,"",Toast.LENGTH_SHORT); } / * 初始化Layout。 */ private void initLayout(){ findViewById(R.id.isr_recognize).setOnClickListener(this); findViewById(R.id.isr_grammar).setOnClickListener(this); findViewById(R.id.isr_lexcion).setOnClickListener(this); findViewById(R.id.isr_stop).setOnClickListener(this); findViewById(R.id.isr_cancel).setOnClickListener(this); //选择云端or本地 RadioGroup group = (RadioGroup)this.findViewById(R.id.radioGroup); group.setOnCheckedChangeListener(new OnCheckedChangeListener() { @Override public void onCheckedChanged(RadioGroup group, int checkedId) { if(checkedId == R.id.radioCloud) { ((EditText)findViewById(R.id.isr_text)).setText(mCloudGrammar); findViewById(R.id.isr_lexcion).setEnabled(false); mEngineType = SpeechConstant.TYPE_CLOUD; }else if(checkedId == R.id.radioLocal) { ((EditText)findViewById(R.id.isr_text)).setText(mLocalGrammar); findViewById(R.id.isr_lexcion).setEnabled(true); mEngineType = SpeechConstant.TYPE_LOCAL; } } }); } String mContent;// 语法、词典临时变量 int ret = 0;// 函数调用返回值 @Override public void onClick(View view) { if( null == mAsr ){ // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688 this.showTip( "创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化" ); return; } if(null == mEngineType) { showTip("请先选择识别引擎类型"); return; } switch(view.getId()) { case R.id.isr_grammar: showTip("上传预设关键词/语法文件"); // 本地-构建语法文件,生成语法id if (mEngineType.equals(SpeechConstant.TYPE_LOCAL)) { ((EditText)findViewById(R.id.isr_text)).setText(mLocalGrammar); mContent = new String(mLocalGrammar); mAsr.setParameter(SpeechConstant.PARAMS, null); // 设置文本编码格式 mAsr.setParameter(SpeechConstant.TEXT_ENCODING,"utf-8"); // 设置引擎类型 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath); //使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); // 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener); if(ret != ErrorCode.SUCCESS){ showTip("语法构建失败,错误码:" + ret); } } // 在线-构建语法文件,生成语法id else { ((EditText)findViewById(R.id.isr_text)).setText(mCloudGrammar); mContent = new String(mCloudGrammar); // 指定引擎类型 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType); // 设置文本编码格式 mAsr.setParameter(SpeechConstant.TEXT_ENCODING,"utf-8"); ret = mAsr.buildGrammar(GRAMMAR_TYPE_ABNF, mContent, grammarListener); if(ret != ErrorCode.SUCCESS) showTip("语法构建失败,错误码:" + ret); } break; // 本地-更新词典 case R.id.isr_lexcion: ((EditText)findViewById(R.id.isr_text)).setText(mLocalLexicon); mContent = new String(mLocalLexicon); mAsr.setParameter(SpeechConstant.PARAMS, null); // 设置引擎类型 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL); // 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); //使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath); // 设置语法名称 mAsr.setParameter(SpeechConstant.GRAMMAR_LIST, "call"); // 设置文本编码格式 mAsr.setParameter(SpeechConstant.TEXT_ENCODING,"utf-8"); ret = mAsr.updateLexicon("contact", mContent, lexiconListener); if(ret != ErrorCode.SUCCESS){ showTip("更新词典失败,错误码:" + ret); } break; // 开始识别 case R.id.isr_recognize: ((EditText)findViewById(R.id.isr_text)).setText(null);// 清空显示内容 // 设置参数 if (!setParam()) { showTip("请先构建语法。"); return; }; ret = mAsr.startListening(mRecognizerListener); if (ret != ErrorCode.SUCCESS) { showTip("识别失败,错误码: " + ret); } break; // 停止识别 case R.id.isr_stop: mAsr.stopListening(); showTip("停止识别"); break; // 取消识别 case R.id.isr_cancel: mAsr.cancel(); showTip("取消识别"); break; } } / * 初始化监听器。 */ private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:"+code); } } }; / * 更新词典监听器。 */ private LexiconListener lexiconListener = new LexiconListener() { @Override public void onLexiconUpdated(String lexiconId, SpeechError error) { if(error == null){ showTip("词典更新成功"); }else{ showTip("词典更新失败,错误码:"+error.getErrorCode()); } } }; / * 构建语法监听器。 */ private GrammarListener grammarListener = new GrammarListener() { @Override public void onBuildFinish(String grammarId, SpeechError error) { if(error == null){ if (mEngineType.equals(SpeechConstant.TYPE_CLOUD)) { Editor editor = mSharedPreferences.edit(); if(!TextUtils.isEmpty(grammarId)) editor.putString(KEY_GRAMMAR_ABNF_ID, grammarId); editor.commit(); } showTip("语法构建成功:" + grammarId); }else{ showTip("语法构建失败,错误码:" + error.getErrorCode()); } } }; / * 获取联系人监听器。 */ private ContactListener mContactListener = new ContactListener() { @Override public void onContactQueryFinish(String contactInfos, boolean changeFlag) { //获取联系人 mLocalLexicon = contactInfos; } }; / * 识别监听器。 */ private RecognizerListener mRecognizerListener = new RecognizerListener() { @Override public void onVolumeChanged(int volume, byte[] data) { showTip("当前正在说话,音量大小:" + volume); Log.d(TAG, "返回音频数据:"+data.length); } @Override public void onResult(final RecognizerResult result, boolean isLast) { if (null != result && !TextUtils.isEmpty(result.getResultString())) { Log.d(TAG, "recognizer result:" + result.getResultString()); String text = ""; if (mResultType.equals("json")) { text = JsonParser.parseGrammarResult(result.getResultString(), mEngineType); } else if (mResultType.equals("xml")) { text = XmlParser.parseNluResult(result.getResultString()); } // 显示 ((EditText) findViewById(R.id.isr_text)).setText(text); } else { Log.d(TAG, "recognizer result : null"); } } @Override public void onEndOfSpeech() { // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入 showTip("结束说话"); } @Override public void onBeginOfSpeech() { // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入 showTip("开始说话"); } @Override public void onError(SpeechError error) { showTip("onError Code:" + error.getErrorCode()); } @Override public void onEvent(int eventType, int arg1, int arg2, Bundle obj) { // 以下代码用于获取与云端的会话id,当业务出错时将会话id提供给技术支持人员,可用于查询会话日志,定位出错原因 // 若使用本地能力,会话id为null // if (SpeechEvent.EVENT_SESSION_ID == eventType) { // String sid = obj.getString(SpeechEvent.KEY_EVENT_SESSION_ID); // Log.d(TAG, "session id =" + sid); // } } }; private void showTip(final String str) { runOnUiThread(new Runnable() { @Override public void run() { mToast.setText(str); mToast.show(); } }); } / * 参数设置 * @param * @return */ public boolean setParam(){ boolean result = false; // 清空参数 mAsr.setParameter(SpeechConstant.PARAMS, null); // 设置识别引擎 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, mEngineType); if("cloud".equalsIgnoreCase(mEngineType)) { String grammarId = mSharedPreferences.getString(KEY_GRAMMAR_ABNF_ID, null); if(TextUtils.isEmpty(grammarId)) { result = false; }else { // 设置返回结果格式 mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType); // 设置云端识别使用的语法id mAsr.setParameter(SpeechConstant.CLOUD_GRAMMAR, grammarId); result = true; } } else { // 设置本地识别资源 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath); // 设置返回结果格式 mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType); // 设置本地识别使用语法id mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call"); // 设置识别的门限值 mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30"); // 使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); result = true; } // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 // 注:AUDIO_FORMAT参数语记需要更新版本才能生效 mAsr.setParameter(SpeechConstant.AUDIO_FORMAT,"wav"); mAsr.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory()+"/msc/asr.wav"); return result; } //获取识别资源路径 private String getResourcePath(){ StringBuffer tempBuffer = new StringBuffer(); //识别通用资源 tempBuffer.append(ResourceUtil.generateResourcePath(this, 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(); } @Override protected void onDestroy() { super.onDestroy(); if( null != mAsr ){ // 退出时释放连接 mAsr.cancel(); mAsr.destroy(); } } } 

看着还是比较多的,我之所以说多而没有说难就是因为它并不难;下面的介绍中我们会对其进行再次瘦身。

 

第八步:为自己的Demo做准备工作

(1)把assets目录copy到我们的module中

(2)把jniLibs目录copy到我们的module中

这里是在Project视图下完成的,这里在Android视图下展示效果更好一下

(3)打开Project视图,把libs目录中的内容复制到我们的module中

(4)在build.gradle(Module:app)中的depandencies下添加依赖:

讯享网compile files('libs/Msc.jar')

 

(5)把Demo中的工具类copy到我们的module中

 

截止到现在,我们还在准备阶段,下面就进入正题,来对我们的需要的功能的实现做一个简要的梳理

 

第九步:提取离线命令词识别功能到我们的项目

定义一个activity,CallStepActivity,把AsrDemo中的逻辑代码copy到CallStepActivty中,把对应的布局文件也对应copy进来

 

第十步:梳理逻辑,继续瘦身

上面也说了,AsrDemo中的Demo还是有点冗余,因为好多我们用不上或者暂时用不上,比如在线的命令词识别等肯定用不上,比如词典更新我们暂时用不上,下面就来分析一下单纯使用离线命令词识别的实现(下面是重点

(1)根据应用ID初始化SpeechUtility,通常在程序入口Application中完成

package com.hfut.offlinerecongnizer.activity.util; import android.app.Application; import com.hfut.offlinerecongnizer.R; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechUtility; / * author:why * created on: 2018/8/27 11:10 * description: */ public class MyApplication extends Application { @Override public void onCreate() { // 应用程序入口处调用,避免手机内存过小,杀死后台进程后通过历史intent进入Activity造成SpeechUtility对象为null // 注意:此接口在非主进程调用会返回null对象,如需在非主进程使用语音功能,请增加参数:SpeechConstant.FORCE_LOGIN+"=true" // 参数间使用“,”分隔。 // 设置你申请的应用appid // 注意: appid 必须和下载的SDK保持一致,否则会出现10407错误 StringBuffer param = new StringBuffer(); param.append("appid=" + getString(R.string.app_id)); param.append(","); // 设置使用v5+ param.append(SpeechConstant.ENGINE_MODE + "=" + SpeechConstant.MODE_MSC); SpeechUtility.createUtility(MyApplication.this, param.toString()); super.onCreate(); } } 

(2)在Activity中初始化初始化监听器,用于初始化语音识别引擎

讯享网/ * 初始化监听器。 */ private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:" + code); } } };

(3)初始化语音识别监听器

/ * 识别监听器。 */ private RecognizerListener mRecognizerListener = new RecognizerListener() { @Override public void onVolumeChanged(int volume, byte[] data) { showTip("当前正在说话,音量大小:" + volume); Log.d(TAG, "返回音频数据:" + data.length); } @Override public void onResult(final RecognizerResult result, boolean isLast) { if (null != result && !TextUtils.isEmpty(result.getResultString())) { Log.d(TAG, "recognizer result:" + result.getResultString()); String text = ""; if (mResultType.equals("json")) { text = JsonParser.parseGrammarResult(result.getResultString(), SpeechConstant.TYPE_LOCAL); } else if (mResultType.equals("xml")) { text = XmlParser.parseNluResult(result.getResultString()); } // 显示 ((EditText) findViewById(R.id.isr_text)).setText(text); } else { Log.d(TAG, "recognizer result : null"); } } @Override public void onEndOfSpeech() { // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入 showTip("结束说话"); } @Override public void onBeginOfSpeech() { // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入 showTip("开始说话"); } @Override public void onError(SpeechError error) { showTip("onError Code:" + error.getErrorCode()); } @Override public void onEvent(int i, int i1, int i2, Bundle bundle) { } };

(4)初始化语法文件构建监听器

讯享网/ * 构建语法监听器。 */ private GrammarListener grammarListener = new GrammarListener() { @Override public void onBuildFinish(String grammarId, SpeechError error) { if (error == null) { showTip("语法构建成功:" + grammarId); } else { showTip("语法构建失败,错误码:" + error.getErrorCode()); } } };

(5)初始化语音识别引擎并完成参数设置

// 初始化识别引擎 mAsr = SpeechRecognizer.createRecognizer(this, mInitListener); //设置识别引擎参数 setParam();

其中setPatam():

讯享网public void setParam() { boolean result = true; // 清空参数 mAsr.setParameter(SpeechConstant.PARAMS, null); // 设置识别引擎 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL); // 设置本地识别资源 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath); // 设置返回结果格式 mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType); // 设置本地识别使用语法id mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call"); // 设置识别的门限值 mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30"); }

(6)完成语法构建

private void buildGrammer() { mLocalGrammar = FucUtil.readFile(this, "call.bnf", "utf-8"); // 本地-构建语法文件,生成语法id ((EditText) findViewById(R.id.isr_text)).setText(mLocalGrammar); 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, grmPath); // 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener); if (ret != ErrorCode.SUCCESS) { showTip("语法构建失败,错误码:" + ret); } else { showTip("语法构建成功"); } }

(7)开启识别,停止识别,取消识别分别是:

讯享网 mAsr.startListening(mRecognizerListener); mAsr.stopListening(); mAsr.cancel();

第十一步:最简单的功能实现代码

所以最后组合起来,我们实现剥离了所有其他功能的只是实现离线命令词识别的代码,CallStepActivity代码如下:

package com.hfut.offlinerecongnizer.activity.activity; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.content.SharedPreferences; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.hfut.offlinerecongnizer.R; import com.hfut.offlinerecongnizer.activity.util.FucUtil; import com.hfut.offlinerecongnizer.activity.util.JsonParser; import com.hfut.offlinerecongnizer.activity.util.XmlParser; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.GrammarListener; import com.iflytek.cloud.InitListener; import com.iflytek.cloud.LexiconListener; import com.iflytek.cloud.RecognizerListener; import com.iflytek.cloud.RecognizerResult; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechRecognizer; import com.iflytek.cloud.util.ContactManager; import com.iflytek.cloud.util.ResourceUtil; / * @author why * @date 2018-8-27 15:09:38 */ public class CallStepActivity extends AppCompatActivity implements View.OnClickListener { private static String TAG = OffLineTestActivity.class.getSimpleName(); // 语音识别对象 private SpeechRecognizer mAsr; private Toast mToast; // 本地语法文件 private String mLocalGrammar = null; // 本地语法构建路径 private String grmPath = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/msc/call"; // 返回结果格式,支持:xml,json private String mResultType = "json"; private final String GRAMMAR_TYPE_BNF = "bnf"; @SuppressLint("ShowToast") public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_call_step); initLayout(); mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); // 初始化识别引擎 mAsr = SpeechRecognizer.createRecognizer(this, mInitListener); //构建本地语法 buildGrammer(); } / * 初始化Layout。 */ private void initLayout() { findViewById(R.id.isr_recognize).setOnClickListener(this); findViewById(R.id.isr_stop).setOnClickListener(this); findViewById(R.id.isr_cancel).setOnClickListener(this); } String mContent;// 语法、词典临时变量 int ret = 0;// 函数调用返回值 @Override public void onClick(View view) { if (null == mAsr) { // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688 this.showTip("创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化"); return; } switch (view.getId()) { // 开始识别 case R.id.isr_recognize: ((EditText) findViewById(R.id.isr_text)).setText(null);// 清空显示内容 //设置识别引擎参数 setParam(); ret = mAsr.startListening(mRecognizerListener); if (ret != ErrorCode.SUCCESS) { showTip("识别失败,错误码: " + ret); } break; // 停止识别 case R.id.isr_stop: mAsr.stopListening(); showTip("停止识别"); break; // 取消识别 case R.id.isr_cancel: mAsr.cancel(); showTip("取消识别"); break; } } / * 初始化监听器。 */ private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:" + code); } } }; / * 构建语法监听器。 */ private GrammarListener grammarListener = new GrammarListener() { @Override public void onBuildFinish(String grammarId, SpeechError error) { if (error == null) { showTip("语法构建成功:" + grammarId); } else { showTip("语法构建失败,错误码:" + error.getErrorCode()); } } }; / * 识别监听器。 */ private RecognizerListener mRecognizerListener = new RecognizerListener() { @Override public void onVolumeChanged(int volume, byte[] data) { showTip("当前正在说话,音量大小:" + volume); Log.d(TAG, "返回音频数据:" + data.length); } @Override public void onResult(final RecognizerResult result, boolean isLast) { if (null != result && !TextUtils.isEmpty(result.getResultString())) { Log.d(TAG, "recognizer result:" + result.getResultString()); String text = ""; if (mResultType.equals("json")) { text = JsonParser.parseGrammarResult(result.getResultString(), SpeechConstant.TYPE_LOCAL); } else if (mResultType.equals("xml")) { text = XmlParser.parseNluResult(result.getResultString()); } // 显示 ((EditText) findViewById(R.id.isr_text)).setText(text); } else { Log.d(TAG, "recognizer result : null"); } } @Override public void onEndOfSpeech() { // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入 showTip("结束说话"); } @Override public void onBeginOfSpeech() { // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入 showTip("开始说话"); } @Override public void onError(SpeechError error) { showTip("onError Code:" + error.getErrorCode()); } @Override public void onEvent(int i, int i1, int i2, Bundle bundle) { } }; private void showTip(final String str) { runOnUiThread(new Runnable() { @Override public void run() { mToast.setText(str); mToast.show(); } }); } / * 参数设置 * * @param * @return */ public void setParam() { boolean result = true; // 清空参数 mAsr.setParameter(SpeechConstant.PARAMS, null); // 设置识别引擎 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL); // 设置本地识别资源 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath); // 设置返回结果格式 mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType); // 设置本地识别使用语法id mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call"); // 设置识别的门限值 mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30"); // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 // 注:AUDIO_FORMAT参数语记需要更新版本才能生效 mAsr.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); mAsr.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/asr.wav"); } //获取识别资源路径 private String getResourcePath() { StringBuffer tempBuffer = new StringBuffer(); //识别通用资源 tempBuffer.append(ResourceUtil.generateResourcePath(this, ResourceUtil.RESOURCE_TYPE.assets, "asr/common.jet")); return tempBuffer.toString(); } @Override protected void onDestroy() { super.onDestroy(); if (null != mAsr) { // 退出时释放连接 mAsr.cancel(); mAsr.destroy(); } } private void buildGrammer() { mLocalGrammar = FucUtil.readFile(this, "call.bnf", "utf-8"); // 本地-构建语法文件,生成语法id ((EditText) findViewById(R.id.isr_text)).setText(mLocalGrammar); 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, grmPath); //使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); // 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener); if (ret != ErrorCode.SUCCESS) { showTip("语法构建失败,错误码:" + ret); } else { showTip("语法构建成功"); } } } 

activity_call_step.xml文件:

讯享网<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:focusable="true" android:focusableInTouchMode="true" android:gravity="center_horizontal" android:orientation="vertical" android:padding="10dip" > <include layout="@layout/title" /> <EditText android:id="@+id/isr_text" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:gravity="top|left" android:textSize="20sp" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:layout_marginBottom="2dip" android:gravity="center_horizontal" android:orientation="horizontal" > </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:layout_marginBottom="2dip" android:gravity="center_horizontal" android:orientation="horizontal" > <Button android:id="@+id/isr_recognize" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:text="开始识别" android:textSize="20sp" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="2dip" android:layout_marginLeft="10dip" android:layout_marginRight="10dip" android:layout_marginTop="2dip" android:gravity="center_horizontal" android:orientation="horizontal" > <Button android:id="@+id/isr_stop" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:text="停止录音" android:textSize="20sp" /> <Button android:id="@+id/isr_cancel" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:text="取消" android:textSize="20sp" /> </LinearLayout> </LinearLayout>

如果不出意外的话,运行应该没有任何问题的。至此,最难的最复杂的第三阶段已经结束了,下面就来看看第四阶段的工作任务:

 

第四阶段    提高

第十二步:丰富我们的功能

因为API里面提供了更新词典的功能(从这里我们也可以推出来后面介绍的bnf文件中词槽的定义也可以通过代码来实现):

mAsr.updateLexicon(groupName, mLocalLexicon, lexiconListener);

所以我们就该利用起来,毕竟如果我想修改某一个词槽的定义时,不能每次都是通过编辑bnf文件,然后在运行程序来实现,太麻烦了。这里我通过一个自定义的AlertDialog来实现对词槽的重新赋值,并列的同义词用“,”隔开即可,类似于bnf文件中的  |  符号;下面直接给出OffLineTestActivity代码:

讯享网package com.hfut.offlinerecongnizer.activity.activity; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Dialog; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Environment; import android.support.v7.app.AppCompatActivity; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.Window; import android.view.WindowManager; import android.widget.Button; import android.widget.EditText; import android.widget.RadioGroup; import android.widget.Toast; import com.hfut.offlinerecongnizer.R; import com.hfut.offlinerecongnizer.activity.util.FucUtil; import com.hfut.offlinerecongnizer.activity.util.JsonParser; import com.hfut.offlinerecongnizer.activity.util.XmlParser; import com.iflytek.cloud.ErrorCode; import com.iflytek.cloud.GrammarListener; import com.iflytek.cloud.InitListener; import com.iflytek.cloud.LexiconListener; import com.iflytek.cloud.RecognizerListener; import com.iflytek.cloud.RecognizerResult; import com.iflytek.cloud.SpeechConstant; import com.iflytek.cloud.SpeechError; import com.iflytek.cloud.SpeechRecognizer; import com.iflytek.cloud.util.ContactManager; import com.iflytek.cloud.util.ContactManager.ContactListener; import com.iflytek.cloud.util.ResourceUtil; import com.iflytek.cloud.util.ResourceUtil.RESOURCE_TYPE; / * @author why * @date 2018-8-27 13:20:58 */ public class OffLineTestActivity extends AppCompatActivity implements View.OnClickListener { private static String TAG = OffLineTestActivity.class.getSimpleName(); // 语音识别对象 private SpeechRecognizer mAsr; private Toast mToast; // 缓存 //private SharedPreferences mSharedPreferences; // 本地语法文件 private String mLocalGrammar = null; // 本地词典 private String mLocalLexicon = null; // 本地语法构建路径 private String grmPath = Environment.getExternalStorageDirectory() .getAbsolutePath() + "/msc/call"; // 返回结果格式,支持:xml,json private String mResultType = "json"; private final String GRAMMAR_TYPE_BNF = "bnf"; private String groupName; private String groupInfo; @SuppressLint("ShowToast") public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_off_line_test); initLayout(); // 初始化识别引擎对象 mAsr = SpeechRecognizer.createRecognizer(this, mInitListener); mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); //构建本地语法 buildGrammer(); } / * 初始化Layout */ private void initLayout() { findViewById(R.id.isr_recognize).setOnClickListener(this); findViewById(R.id.isr_lexcion).setOnClickListener(this); findViewById(R.id.isr_stop).setOnClickListener(this); findViewById(R.id.isr_cancel).setOnClickListener(this); } String mContent;// 语法、词典临时变量 int ret = 0;// 函数调用返回值 @Override public void onClick(View view) { if (null == mAsr) { // 创建单例失败,与 21001 错误为同样原因,参考 http://bbs.xfyun.cn/forum.php?mod=viewthread&tid=9688 this.showTip("创建对象失败,请确认 libmsc.so 放置正确,\n 且有调用 createUtility 进行初始化"); return; } switch (view.getId()) { // 本地-更新词典 case R.id.isr_lexcion: AlertDialog.Builder builder = new AlertDialog.Builder(this); LayoutInflater inflater = LayoutInflater.from(this); final View v = inflater.inflate(R.layout.user_info_editor, null); final EditText wordGroupName = v.findViewById(R.id.enter_word_group_name); final EditText wordGroupInfo = v.findViewById(R.id.enter_word_group_info); Button cancleButton = v.findViewById(R.id.register_cancle); Button confirmButton = v.findViewById(R.id.register_confirm); final Dialog dialog = builder.create(); //点击EditText弹出软键盘 cancleButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(OffLineTestActivity.this, "取消", Toast.LENGTH_SHORT).show(); dialog.cancel(); } }); confirmButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (!wordGroupName.getText().toString().equals("")) { groupName= wordGroupName.getText().toString(); } if (!wordGroupInfo.getText().toString().equals("")) { groupInfo = wordGroupInfo.getText().toString(); } mLocalLexicon=getUpdateInfo(groupInfo); ((EditText) findViewById(R.id.isr_text)).setText(mLocalLexicon); mAsr.setParameter(SpeechConstant.PARAMS, null); // 设置引擎类型 mAsr.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_LOCAL); // 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath); // 设置语法名称 mAsr.setParameter(SpeechConstant.GRAMMAR_LIST, "call"); // 设置文本编码格式 mAsr.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8"); //执行更新操作 ret = mAsr.updateLexicon(groupName, mLocalLexicon, lexiconListener); if (ret != ErrorCode.SUCCESS) { showTip("更新词典失败,错误码:" + ret); } else{ showTip("更新词典成功" ); } dialog.cancel(); } }); dialog.show(); dialog.getWindow().setContentView(v);//自定义布局应该在这里添加,要在dialog.show()的后面 dialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); break; // 开始识别 case R.id.isr_recognize: //设置识别引擎参数 setParam(); ((EditText) findViewById(R.id.isr_text)).setText(null);// 清空显示内容 ret = mAsr.startListening(mRecognizerListener); if (ret != ErrorCode.SUCCESS) { showTip("识别失败,错误码: " + ret); } break; // 停止识别 case R.id.isr_stop: mAsr.stopListening(); showTip("停止识别"); break; // 取消识别 case R.id.isr_cancel: mAsr.cancel(); showTip("取消识别"); break; } } private String getUpdateInfo(String groupInfo) { String[] wordList=groupInfo.split(","); StringBuilder builder=new StringBuilder(); for(int i=0;i<wordList.length;i++){ if(i==wordList.length-1) { builder.append(wordList[i] ); Log.d(TAG, "getUpdateInfo: "+wordList[i]); }else{ builder.append(wordList[i] + "\n"); } } return builder.toString(); } / * 初始化监听器。 */ private InitListener mInitListener = new InitListener() { @Override public void onInit(int code) { Log.d(TAG, "SpeechRecognizer init() code = " + code); if (code != ErrorCode.SUCCESS) { showTip("初始化失败,错误码:" + code); } } }; / * 更新词典监听器。 */ private LexiconListener lexiconListener = new LexiconListener() { @Override public void onLexiconUpdated(String lexiconId, SpeechError error) { if (error == null) { showTip("词典更新成功"); } else { showTip("词典更新失败,错误码:" + error.getErrorCode()); } } }; / * 构建语法监听器。 */ private GrammarListener grammarListener = new GrammarListener() { @Override public void onBuildFinish(String grammarId, SpeechError error) { if (error == null) { showTip("语法构建成功:" + grammarId); } else { showTip("语法构建失败,错误码:" + error.getErrorCode()); } } }; / * 识别监听器。 */ private RecognizerListener mRecognizerListener = new RecognizerListener() { @Override public void onVolumeChanged(int volume, byte[] data) { showTip("当前正在说话,音量大小:" + volume); Log.d(TAG, "返回音频数据:" + data.length); } @Override public void onResult(final RecognizerResult result, boolean isLast) { if (null != result && !TextUtils.isEmpty(result.getResultString())) { Log.d(TAG, "recognizer result:" + result.getResultString()); String text = ""; if (mResultType.equals("json")) { text = JsonParser.parseGrammarResult(result.getResultString(), SpeechConstant.TYPE_LOCAL); } else if (mResultType.equals("xml")) { text = XmlParser.parseNluResult(result.getResultString()); } // 显示 ((EditText) findViewById(R.id.isr_text)).setText(text); } else { Log.d(TAG, "recognizer result : null"); } } @Override public void onEndOfSpeech() { // 此回调表示:检测到了语音的尾端点,已经进入识别过程,不再接受语音输入 showTip("结束说话"); } @Override public void onBeginOfSpeech() { // 此回调表示:sdk内部录音机已经准备好了,用户可以开始语音输入 showTip("开始说话"); } @Override public void onError(SpeechError error) { showTip("onError Code:" + error.getErrorCode()); } @Override public void onEvent(int i, int i1, int i2, Bundle bundle) { } }; private void showTip(final String str) { runOnUiThread(new Runnable() { @Override public void run() { mToast.setText(str); mToast.show(); } }); } / * 参数设置 * * @param * @return */ public void setParam() { // 清空参数 mAsr.setParameter(SpeechConstant.PARAMS, null); // 设置识别引擎 mAsr.setParameter(SpeechConstant.ENGINE_TYPE,SpeechConstant.TYPE_LOCAL); // 设置本地识别资源 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); // 设置语法构建路径 mAsr.setParameter(ResourceUtil.GRM_BUILD_PATH, grmPath); // 设置返回结果格式 mAsr.setParameter(SpeechConstant.RESULT_TYPE, mResultType); // 设置本地识别使用语法id mAsr.setParameter(SpeechConstant.LOCAL_GRAMMAR, "call"); // 设置识别的门限值 mAsr.setParameter(SpeechConstant.MIXED_THRESHOLD, "30"); // 设置音频保存路径,保存音频格式支持pcm、wav,设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限 // 注:AUDIO_FORMAT参数语记需要更新版本才能生效 mAsr.setParameter(SpeechConstant.AUDIO_FORMAT, "wav"); mAsr.setParameter(SpeechConstant.ASR_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/msc/asr.wav"); } //获取识别资源路径 private String getResourcePath() { StringBuffer tempBuffer = new StringBuffer(); //识别通用资源 tempBuffer.append(ResourceUtil.generateResourcePath(this, RESOURCE_TYPE.assets, "asr/common.jet")); return tempBuffer.toString(); } @Override protected void onDestroy() { super.onDestroy(); if (null != mAsr) { // 退出时释放连接 mAsr.cancel(); mAsr.destroy(); } } private boolean buildGrammer() { mLocalGrammar = FucUtil.readFile(this, "call.bnf", "utf-8"); // 本地-构建语法文件,生成语法id ((EditText) findViewById(R.id.isr_text)).setText(mLocalGrammar); 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, grmPath); //使用8k音频的时候请解开注释 // mAsr.setParameter(SpeechConstant.SAMPLE_RATE, "8000"); // 设置资源路径 mAsr.setParameter(ResourceUtil.ASR_RES_PATH, getResourcePath()); ret = mAsr.buildGrammar(GRAMMAR_TYPE_BNF, mContent, grammarListener); if (ret != ErrorCode.SUCCESS) { showTip("语法构建失败,错误码:" + ret); } else{ showTip("语法构建成功"); } return true; } }

activity_off_line_test.xml代码:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:focusable="true" android:focusableInTouchMode="true" android:gravity="center_horizontal" android:orientation="vertical" android:padding="10dip" > <include layout="@layout/title" /> <EditText android:id="@+id/isr_text" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1" android:gravity="top|left" android:textSize="20sp" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_margin="10dip" android:layout_marginBottom="2dip" android:gravity="center_horizontal" android:orientation="horizontal" > <Button android:id="@+id/isr_recognize" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:text="开始识别" android:textSize="20sp" /> <Button android:id="@+id/isr_lexcion" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:text="更新词典" android:textSize="20sp" android:enabled="true" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="2dip" android:layout_marginLeft="10dip" android:layout_marginRight="10dip" android:layout_marginTop="2dip" android:gravity="center_horizontal" android:orientation="horizontal" > <Button android:id="@+id/isr_stop" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:text="停止录音" android:textSize="20sp" /> <Button android:id="@+id/isr_cancel" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1" android:text="取消" android:textSize="20sp" /> </LinearLayout> </LinearLayout>

 

word_info_editor.xml代码:

讯享网<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#B0C4DE" android:orientation="vertical"> <TextView android:layout_marginLeft="20dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请编辑更新信息:" android:textColor="#000000" android:textSize="30dp" /> <LinearLayout android:layout_marginLeft="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="词组名称:" android:textSize="20dp" /> <EditText android:id="@+id/enter_word_group_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:hint="请输入词组名称" /> </LinearLayout> <LinearLayout android:layout_marginLeft="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="词组信息:" android:textSize="20dp" /> <EditText android:id="@+id/enter_word_group_info" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:hint="请编写词组信息" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/register_cancle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="350dp" android:text="取消" /> <Button android:id="@+id/register_confirm" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:text="确定" /> </LinearLayout> </LinearLayout>

其中还有一个所有布局都用到的title.xml代码:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:gravity="center"> <TextView android:text="@string/app_name" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="30sp" android:layout_margin="10dip" /> </LinearLayout> 

上面介绍的离线命令词识别都是基于我们自己编辑的bnf文件中的规则来识别,下面给出一个文件示例:

讯享网#BNF+IAT 1.0 UTF-8; !grammar call; //通用词槽 !slot <want>; !slot <deal>; !slot <how>; //联系相关词槽声明 !slot <contact>;//联系人 !slot <callPhone>;//联系方式 !slot <callTo>;//联系动作 //巡游相关词槽声明 !slot <destination>;//巡游点 !slot <goTo>;//去 !slot <goToPre>;//准备去 /* 专业语料相关 */ //办卡业务 !slot <cardType>; //公积金业务 !slot <percent>; !slot <wagesDeal>; !slot <wages>; !start <commands>; <commands>:<callRule>|<guideRule>|<dealCardRule>|<wagesDealRule>; //通用语料 <want>:我想|我要|我准备; <how>:如何|怎么|怎样; <deal>:办理|解决|处理; //测试语料 <contact>:黄老板|王华洋|齐带华|火警!id(119); <callPhone>:打电话|发微信|发短信; <callTo>:给; <callRule>:<callTo><contact><callPhone>|<callPhone><callTo><contact>;//联系语料相关规则 //巡游语料 <destination>:卫生间|饮水机|现金柜台|取款机|充电器|大堂经理; <goTo>:去|到|找; <goToPre>:带我|请带我|我想; <guideRule>:[<goToPre>]<goTo><destination>;//巡游语料相关规则 //办卡语料 <cardType>:卡|信用卡|儿童卡|储蓄卡;//卡片类型 <dealCardRule>:[<want>]<deal><cardType>; //公积金业务 <percent>:比例;//公积金比例 <wagesDeal>:转移|提取;//处理公积金 <wages>:公积金; <wagesDealRule>:[<how>]<wagesDeal><wages>; 具体的编辑规则请参考bnf文档编辑指南,后续我还会对这个编辑规则进行介绍,具体就介绍到这里。 

注:欢迎扫码关注

 

小讯
上一篇 2025-03-08 19:52
下一篇 2025-02-27 22:48

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/31204.html