標籤:android 訊飛 語音撥號 語音導航 語音啟動應用
轉載請註明出處:周木水的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
Android整合訊飛SDK實現語音撥號、語音導航、語音啟動應用