转载请注明出处:周木水的CSDN博客
http://blog.csdn.net/zhoumushui
科大讯飞语音SDK的语义分析还是挺强大的,可使我们的应用更加强大。
上篇博文介绍了讯飞SDK的一些简单功能:
Android 使用讯飞语音SDK
今天来看看对语义分析结果JSON的解析并处理:
实现语音拨号
首先,我们看看“打电话给张三”这句话在服务器分析之后,传给我们的JSON是什么样的:
{ "semantic": { "slots": { "name": "张三" } }, "rc": 0, "operation": "CALL", "service": "telephone", "text": "打电话给张三。" }
所以,我们的思路就是获取到name,然后和联系人ContentProvider中的联系人DisplayName进行逐一匹配。但是要考虑到同音字的问题(例如:“打电话给张晓静”,服务器返回的name是”张小静“,这就没法匹配。)在没有匹配的情况下,我们将name转成拼音,然后再和联系人拼音进行对比即可。
看一下核心代码:
if ("telephone".equals(strService)) { // "operation": "CALL" String peopleName = jsonObject.getJSONObject("semantic").getJSONObject("slots").getString("name"); String operationStr = jsonObject.getString("operation"); if ("CALL".equals(operationStr)) { String phoneNum = getContactNumberByName(peopleName); String phoneCode = ""; try { phoneCode = jsonObject.getJSONObject("semantic").getJSONObject("slots").getString("code"); } catch (Exception e) {} if (phoneNum != null & phoneNum.trim().length() > 0) { String strAnswer = "正在打电话给:" + peopleName; tvAnswer.setText(strAnswer); startSpeak(strAnswer); Uri uri = Uri.parse("tel:" + phoneNum); Intent intent = new Intent(Intent.ACTION_CALL, uri); startActivity(intent); } else if (phoneCode != null& phoneCode.trim().length() > 0) { String strAnswer = "正在打电话给:" + peopleName; tvAnswer.setText(strAnswer); startSpeak(strAnswer); Uri uri = Uri.parse("tel:" + phoneCode); Intent intent = new Intent(Intent.ACTION_CALL, uri); startActivity(intent); } else { String phoneNumFromPinYin = getContactNumberByPinYin(PinYinUtil.convertAll(peopleName)); if (phoneNumFromPinYin != null& phoneNumFromPinYin.trim().length() > 0) { String strAnswer = "正在打电话给:" + peopleName; tvAnswer.setText(strAnswer); startSpeak(strAnswer); Uri uri = Uri.parse("tel:" + phoneNumFromPinYin); Intent intent = new Intent(Intent.ACTION_CALL, uri); startActivity(intent); } else { String strAnswer = "通讯录中未找到:" + peopleName; tvAnswer.setText(strAnswer); startSpeak(strAnswer); } } } }
语音导航
这里不考虑”从A到B怎么走(A,B都为异地)“的情况。起点不是当前位置的情况解析方式相同,只是不常用。所以这里的例子起点默认为当前定位位置。
当我们说”导航到深圳北站“时,服务器返回的JSON如下:
{ "semantic": { "slots": { "endLoc": { "type": "LOC_POI", "poi": "深圳南站", "city": "深圳市", "cityAddr": "深圳" }, "startLoc": { "type": "LOC_POI", "city": "CURRENT_CITY", "poi": "CURRENT_POI" } } }, "rc": 0, "operation": "ROUTE", "service": "map", "text": "导航到深圳南站。" }
首先我们对JSON进行解析:
if ("map".equals(strService)) { // operation": "ROUTE" String endPoiStr = jsonObject.getJSONObject("semantic").getJSONObject("slots").getJSONObject("endLoc").getString("poi"); String endCityStr = jsonObject.getJSONObject("semantic").getJSONObject("slots").getJSONObject("endLoc").getString("city"); String endAddressStr = ""; if ("CURRENT_CITY".equals(endCityStr)) endCityStr = mSharedPreferences.getString("cityName", "未知"); }
调用百度地图的导航接口,需要传入起始点的经纬度。当前位置的经纬度是已知的,所以要将目的地的字符串转成经纬度。这就涉及到百度LBS SDK的使用:
{ mEndSearch = GeoCoder.newInstance(); mEndSearch.setOnGetGeoCodeResultListener(new MyOnGetGeoCoderResultListener()); mEndSearch.geocode(new GeoCodeOption().city(endCityStr).address(endPoiStr)); }
class MyOnGetGeoCoderResultListener implements OnGetGeoCoderResultListener { @Override public void onGetGeoCodeResult(GeoCodeResult result) { // TODO Auto-generated method stub mEndLatLng = result.getLocation(); if (mEndLatLng != null) { // 起始点:当前位置 startLat = Double.parseDouble(mSharedPreferences.getString( "latitude", "0.0")); startLng = Double.parseDouble(mSharedPreferences.getString( "longitude", "0.0")); // 目的地 endLat = mEndLatLng.latitude; endLng = mEndLatLng.longitude; LatLng startLatLng = new LatLng(startLat, startLng); LatLng endLatLng = new LatLng(endLat, endLng); // 构建 导航参数 NaviPara para = new NaviPara(); para.startPoint = startLatLng; para.startName = "从这里开始"; para.endPoint = endLatLng; para.endName = "到这里结束"; try { BaiduMapNavigation.openBaiduMapNavi(para, getApplicationContext()); } catch (BaiduMapAppNotSupportNaviException e) { e.printStackTrace(); } } } @Override public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) { } }
语音启动应用
当我们说”打开百度地图“时,服务器返回的JSON是:
{ "semantic": { "slots": { "name": "百度地图" } }, "rc": 0, "operation": "LAUNCH", "service": "app", "text": "打开百度地图。" }
和语音拨号类似,我们可以获取到应用的名称,然后和ResolveInfo中应用的名称Label进行比对,如果匹配,则拿到包名,然后进行启动。
注意:要考虑到应用名称为非中文的情况。(比如我们说”启动QQ“,但讯飞识别的是”qq“,如果简单粗暴的进行String的equals比较,则会匹配失败。这时候需要将应用名称与Label都转成大写或小写。)
if ("app".equals(strService)) { // "operation": "LAUNCH", String appName = jsonObject.getJSONObject("semantic").getJSONObject("slots").getString("name"); String operationStr = jsonObject.getString("operation"); if ("LAUNCH".equals(operationStr)) { String packageName = getAppPackageByName(appName); Toast.makeText(getApplicationContext(),packageName, Toast.LENGTH_SHORT).show(); if (!"com.tchip.carlauncher".equals(packageName)) { String strAnswer = "正在启动:"+ appName; tvAnswer.setText(strAnswer); startSpeak(strAnswer); startAppbyPackage(packageName); } else { String strAnswer = "未找到应用:"+ appName; tvAnswer.setText(strAnswer); startSpeak(strAnswer); } } }
转载请注明出处:周木水的CSDN博客
http://blog.csdn.net/zhoumushui