Android 科大讯飞语音识别 金额数字

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/li352558693/article/details/41896063

最近要在应用里面使用语音识别功能,老板选择了科大讯飞的技术,小可也就开始看文档啦;

这里只嵌入了语音识别,其他的语法什么的没有研究,有需要的各位看文档呗;

需要的资料 :只识别数字,若不过滤则把LSpeechManager中的onResult方法中的LDataFormat过滤去掉即可

1,首先要在科大讯飞开放平台注册开发者,并注册应用,然后下载SDK;

      http://open.voicecloud.cn/index.php/default/index

2,语音识别需要的文件:

      (1)Msc.jar

      (2)libmsc.so

3,需要的权限 :

     

    <!-- 网络权限 -->
    <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" />
 
4,需要自己的Application,并在其中初始化语音识别

   

public class Lapp extends Application {
	@Override
	public void onCreate() {
		// 应用程序入口处调用,避免手机内存过小,杀死后台进程,造成SpeechUtility对象为null
		// 设置你申请的应用appid
		SpeechUtility.createUtility(Lapp.this, "appid=5486584a");
		super.onCreate();
	}
}

5,语音识别  (使用该类可以直接调用start()方法进行语音听写识别)

/**
 * 语音识别管理类
 * 
 * @author li'mingqi
 * 
 */
public class LSpeechManager {
	private Context mContext;
	// 语音听写
	private SpeechRecognizer mIat;
	// handler
	private Handler mHandler;
	// 识别结果
	private LSpeechResultListener resultListener;
	// 识别成功
	public static final int SPEECH_SUCCESS = 0;
	// 识别失败
	public static final int SPEECH_FAIL = -1;
	// 开始识别
	public static final int SPEECH_START = 1;
	// 识别出错
	public static final int SPEECH_ERROR = 2;

	/**
     * 
     */
	@SuppressLint("HandlerLeak")
	public LSpeechManager(Context context) {
		this.mContext = context;
		// 语音听写部分
		// 创建SpeechRecognizer对象
		mIat = SpeechRecognizer.createRecognizer(this.mContext, null);
		// 设置听写参数
		// 应用领域 --语音识别
		mIat.setParameter(SpeechConstant.DOMAIN, "iat");
		// 语言--中文
		mIat.setParameter(SpeechConstant.LANGUAGE, "zh_cn");
		// mandarin 普通话 cantonese广东话
		mIat.setParameter(SpeechConstant.ACCENT, "mandarin");
		// 客户端引擎选择模式 --云端msc
		mIat.setParameter(SpeechConstant.ENGINE_MODE, "msc");
		// 客户端引擎类型 --云端msc
		mIat.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
		// 数据解码方式 --utf-8
		mIat.setParameter(SpeechConstant.TEXT_ENCODING, "utf-8");
		// 初始化听写Dialog,如果只使用有UI听写功能,无需创建SpeechRecognizer
		mHandler = new Handler() {
			@Override
			public void handleMessage(Message msg) {
				super.handleMessage(msg);
				int what = msg.what;
				switch (what) {
				case SPEECH_SUCCESS:// 识别成功
					String result = (String) msg.obj;
					if (null != resultListener) {
						resultListener.onSuccess(result);
					}
					break;

				case SPEECH_FAIL:// 识别失败
					Toast.makeText(mContext, "请将金额数字按普通话讲出", Toast.LENGTH_SHORT)
							.show();
					break;

				case SPEECH_START://开始识别
					if (null != resultListener) {
						resultListener.onStart();
					}
					break;
				case SPEECH_ERROR://识别出错
					if (null != resultListener) {
						String error = (String) msg.obj;
						resultListener.onError(error);
					}
					break;
				}
			}
		};
	}

	public void start() {
		final StringBuilder sb = new StringBuilder();
		// 开始听写
		mIat.startListening(new RecognizerListener() {

			@Override
			public void onVolumeChanged(int arg0) {
				// 音量值变化
			}

			@Override
			public void onResult(RecognizerResult msg, boolean arg1) {
				// 一般情况下会通过onResults接口多次返回结果,完整的识别内容是多次结果的累加;
				// 关于解析Json的代码可参见MscDemo中JsonParser类;
				// isLast等于true时会话结束。
				/***
				 * 结果--{"sn":1,"ls":false,"bg":0,"ed":0,"ws":[{"bg":0,"cw":[
				 * {"w":"两百","sc":0.00}]}]}
				 * 结果--{"sn":2,"ls":true,"bg":0,"ed":0,"ws"
				 * :[{"bg":0,"cw":[{"w":"。","sc":0.00}]}]}
				 */
				try {
					JSONObject mRsult = new JSONObject(msg.getResultString());
					if (!mRsult.getBoolean("ls")) {
						JSONArray data = mRsult.getJSONArray("ws");
						for (int i = 0; i < data.length(); i++) {
							JSONObject w = data.getJSONObject(i);
							JSONArray array = w.getJSONArray("cw");
							for (int k = 0; k < array.length(); k++) {
								JSONObject cwdata = array.getJSONObject(k);
								sb.append(cwdata.getString("w"));
							}
						}
					} else {
						mIat.stopListening();
						String money = LDataFormat.format(sb.toString());
						if ("".equals(money) || null == money
								|| "0".equals(money)) {
							Message msgs = mHandler.obtainMessage();
							msgs.what = SPEECH_FAIL;
							mHandler.sendMessage(msgs);
						} else {
							Message msgs = mHandler.obtainMessage();
							msgs.what = SPEECH_SUCCESS;
							msgs.obj = money;
							mHandler.sendMessage(msgs);
						}
					}
				} catch (JSONException e) {
					e.printStackTrace();
				}
			}

			@Override
			public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) {
				// 扩展类回调
			}

			@Override
			public void onError(SpeechError error) {
				// 回话发生错误时回调的函数
				String merror = error.getPlainDescription(true);// 获取错误码描述
				Message msg=mHandler.obtainMessage();
				msg.what=SPEECH_ERROR;
				msg.obj=merror;
				mHandler.sendMessage(msg);
			}

			@Override
			public void onEndOfSpeech() {
				// 结束录音
			}

			@Override
			public void onBeginOfSpeech() {
				// 开始录音
				Message msg=mHandler.obtainMessage();
				msg.what=SPEECH_START;
				mHandler.sendMessage(msg);
			}
		});
	}

	/**识别回调
         * @param resultListener
	 *            the resultListener to set
	 */
	public void setResultListener(LSpeechResultListener resultListener) {
		this.resultListener = resultListener;
	}

	public interface LSpeechResultListener {

		public void onStart();//开始识别

		public void onError(String error);//识别出现错误  ---错误的内容

		public void onSuccess(String result);//识别成功   ---识别结果
	}
}

6,贴上过滤文字和其他无关的内容的LDateFormat类  (很大一部分是别人写的,谢谢那位大神!)

    

/**
 * 数据格式化
 * <ol>
 * 该类主要解决语音输入时携带汉字或者汉字数字混合的字符串情况
 * <li>该类会将除{'分','毛','块','十','百','千','万','亿','一','二','三'...}以外所有的汉字移除并替换格式补位.
 * 即'十'放在十位,'百'放在百位...
 * <li>例如:你好,280元----->280;两百八十元------>280
 * <ol>
 * 
 * @author li'mingqi
 * @version 1.0
 */
public class LDataFormat {
	// 全局数组,存储单位量级
	public static String[] strCHup = { "亿", "万", "千", "百", "十", "元" };

	/***
	 * 格式化数据
	 * 
	 * @param source
	 *            语音输入的数据
	 * @return 返回格式化后的数字字符串
	 * 
	 *         li'mingqi 2014-12-11
	 * 
	 **/
	public static String format(String source) {
		// 1,去除不相干的文字信息
		char[] pt = source.toCharArray();
		for (int i = 0; i < pt.length; i++) {
			char k = pt[i];
			if (k == '一' || k == '二' || k == '两' || k == '三' || k == '四'
					|| k == '五' || k == '六' || k == '七' || k == '八' || k == '九'
					|| k == '十' || k == '百' || k == '千' || k == '万' || k == '亿'
					|| k == '0' || k == '1' || k == '2' || k == '3' || k == '4'
					|| k == '5' || k == '6' || k == '7' || k == '8' || k == '9') {

			} else {
				source = source.replace(k + "", "");
			}
		}
		// 去除空格间隙
		source.trim();
		// 2,汉字'十','百','千'的转换
		long money = 0;
		// 如果不是数字也就是 一千万这样的汉字 ---则需要转换 如 一百五十万----1500000
		if (source.contains("一") || source.contains("二")
				|| source.contains("两") || source.contains("三")
				|| source.contains("四") || source.contains("五")
				|| source.contains("六") || source.contains("七")
				|| source.contains("八") || source.contains("九")
				|| source.contains("十") || source.contains("百")
				|| source.contains("千") || source.contains("万")
				|| source.contains("亿")) {
			money = excuteCharge(source);
		}
		// 数据的来源直接就是阿拉伯数字 如200元---此时元已经去掉,即数字200
		else {
			if (!"".equals(source)) {
				money = Integer.parseInt(source);
			}
		}
		// 3,返回最终格式化结果

		return money + "";
	}

	/***
	 * 通过两次递归调用实现分割.
	 * 
	 * @param str
	 * @return li'mingqi 2014-12-11
	 */
	public static long excuteCharge(String str) {
		// 存储量级单位
		long midNumber = 0;
		// 存储是否可以找到最高量级
		int bre = -1;
		// 找到后根据索引实行字符串分割
		int split = 0;
		// 通过循环查找最高量级
		for (int i = 0; i < strCHup.length; i++) {
			bre = str.indexOf(strCHup[i]);
			if (bre != -1) {
				split = i;
				switch (i) {
				case 0:
					midNumber = 100000000;
					break;
				case 1:
					midNumber = 10000;
					break;
				case 2:
					midNumber = 1000;
					break;
				case 3:
					midNumber = 100;
					break;
				case 4:
					midNumber = 10;
					break;
				case 5:
					midNumber = 1;
					break;
				}
				// 只需要找到最高量级,找到即刻跳出循环.
				break;
			}

		}
		// 如果没有找到量级数.说明该数很小,直接调用add()返回该值.
		if (bre == -1) {
			return add(str);
		}
		// 否则要根据量级进行字符串侵害和返回侵害前部分的值
		else {
			// 如果大型整数,如:十万 等.因为后面不需要再分割
			if (str.length() == bre + 1) {
				// 对于单个量级的值,如:十、百、千、万等。不需要裁减字符串。直接返回量级即可
				if (str.length() == 1) {
					return midNumber;
				} else {
					return add(str.substring(0, str.length() - 1)) * midNumber;
				}
			}
			// 对于只有两位数的.如:十九.直接调用add()返回值即可.不能在此处递归.
			else if (str.length() == bre + 2) {
				return add(str);
			}
			// 其他情况则取值和分割.然后再递归调用.
			else {
				String[] strPart = str.split(strCHup[split]);
				return (add(strPart[0]) * midNumber) + excuteCharge(strPart[1]);
			}
		}

	}

	public static long add(String str) {
		// 存储strCHup里具体汉字的数字值
		long mid = 0;
		// 存储strNumup里具体汉字的数字值
		int number = 0;
		// 存储传入字符串的最高级别单位在strCHup数组里的索引.
		int num = -1;
		for (int i = 0; i < strCHup.length; i++) {
			// 取得量级在字符串中的索引.
			num = str.indexOf(strCHup[i]);
			// 定义char型变量,存储每个汉字.便于后面比较
			char ch = ' ';
			// //////////////////////////////////////////////////////////////
			if (num != -1) {

				switch (i) {
				case 0:
					mid = 100000000;
					break;
				case 1:
					mid = 10000;
					break;
				case 2:
					mid = 1000;
					break;
				case 3:
					mid = 100;
					break;
				case 4:
					mid = 10;
					break;
				case 5:
					mid = 1;
					break;
				}

				// 如果以"十"开关的,直接定义number的值.因为在上面能够找到它的量级.
				if ((str.toCharArray())[0] == '十') {
					number = 1;
				}
				// 否则,取得量级前的数字进行比较,再确定number的值
				else {
					if (0 != num) {
						ch = (str.toCharArray())[num - 1];
					}
				}

				// ////////////////////////////////////////////////////
			}
			// 循环结束
			// ////////////////////////////////////////////////////////////////
			// 如果整个字符串就一个字,那么就应该取该值进行比较.而不是再取量级前的数字.
			if (str.length() == 1) {

				ch = (str.toCharArray())[0];
			}
			// 防止几万零几这样的数.
			else if ((str.length() == 2) && ((str.toCharArray())[0] == '零')) {
				ch = (str.toCharArray())[1];
			}
			switch (ch) {
			case '零':
				number = 0;
				break;
			case '一':
				number = 1;
				break;
			case '二':
				number = 2;
				break;
			case '两':
				number = 2;
				break;
			case '三':
				number = 3;
				break;
			case '四':
				number = 4;
				break;
			case '五':
				number = 5;
				break;
			case '六':
				number = 6;
				break;
			case '七':
				number = 7;
				break;
			case '八':
				number = 8;
				break;
			case '九':
				number = 9;
				break;
			}
			// ///////////////////////////////////////////////////////////////

			if (num != -1) {
				break;
			}

		}
		if (num == -1) {
			return number;
		}

		String strLeft = str.substring(num + 1);
		return (number * mid) + add(strLeft);
	}
}
最后在Activity中的使用方法:

    

public class MainActivity extends Activity {
	/**语音识别管理**/
	LSpeechManager manager;
	/**识别内容输入框**/
	EditText text;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		text = (EditText) findViewById(R.id.editText1);
		manager = new LSpeechManager(this);
		manager.setResultListener(new LSpeechResultListener() {

			@Override
			public void onSuccess(String result) {
				// 识别结束
				text.setText(result);
			}

			@Override
			public void onError(String error) {
				// 识别出现异常
			}

			@Override
			public void onStart() {
				// 识别开始
			}
		});
	}

	public void onClick(View v) {
		int id = v.getId();
		switch (id) {
		case R.id.button1:// 开始识别
			manager.start();
			break;
		}
	}
附上demo:http://download.csdn.net/detail/li352558693/8253035

  

    


展开阅读全文

没有更多推荐了,返回首页