By
何明桂(http://blog.csdn.net/hmg25) 轉載請註明出處
Iphone4S的Siri讓人眼前一亮,網上出現了無數調戲Siri的視頻。真是讓android使用者們心癢不已。好在隨後android陣營中的高手迅速反擊,推出了Iris。悲劇的是Iris僅支援英文,讓我們這些英語爛的無比的人調戲Iris不成,反被它給調戲了。真是鬱悶的不行啊~_~
所以我打算使用android的資源自己打造一個中文版的Siri,讓我們用中文隨意的來調戲它。(我自己做了一個簡單的,哈哈,放在優億市場裡,有興趣的童鞋可以去體驗下http://www.eoemarket.com/apps/61634)
首先,我們來分析Siri的構成,應該大致可以分為3個組成部份:語音辨識、自然語言處理、語音輸出。對於語音辨識,我們可以使用google的語音辨識API進行語音的識別,講語音轉成文字。語音輸出,其實就是使用TTS,講文字進行語音合成播放出來,這個android也是有介面可以利用的。真正核心的是自然語言識別處理這個部分,Siri功能的好壞判斷很大一部分是取決於此的,這需要很大一個資料庫來維持運轉,在本地是無法實現的,即使iphone的Siri也是講語音辨識的指令語音上傳到Apple的伺服器上去解析後返回。由於apple的介面不開放,所以我們無法使用他們的介面,好在世界上擁有這樣伺服器的不止蘋果一家,android上的Iris利用的就是http://start.csail.mit.edu/(自然語音問答系統)這個網站提供的介面以及一個叫做cleverbot的一款智能聊天平台http://www.cleverbot.com/這個聊天網站是支援漢語的,不過,只是支援拼音輸入——汗啊。
所以我們的核心任務就是尋找一個支援中文漢字輸入的問答系統。經過在網路上長時間的搜尋,結果發現——很遺憾,沒有找到(PS:如果有誰找到了比較好的網址,麻煩共用,告訴我一聲),不過對於我們調戲Siri的這個需求,我找到了一個較好的替代品——聊天機器人.http://www.xiaoi.com/widget/1007/小i智能聊天機器人。
經過短時間的摸索,我實現了一個類來,初始化串連小i機器人的介面,發送資料以及接受反饋。用到的介面地址如下:
private String Webbot_Path = "http://webbot.xiaoi.com/engine/widget1007/webbot.js?encoding=utf-8";private String Send_Path = "http://122.226.240.164/engine/widget1007/send.js?encoding=utf-8&";private String Recv_Path = "http://122.226.240.164/engine/widget1007/recv.js?encoding=utf-8&";
http串連上邊的Webbot_Path,會反饋回來一些資料:
var L_IDS_SEND_MESSAGE_URL = "http://122.226.240.164/engine/widget1007/send.js?encoding=utf-8&";var L_IDS_RECV_MESSAGE_URL = "http://122.226.240.164/engine/widget1007/recv.js?encoding=utf-8&";var L_IDS_GET_RESOURCE_URL = "http://122.226.240.164/engine/widget1007/getres.do";var __sessionId = "86491993134658194";document.write("<script src='http://122.226.240.164/engine/widget1007/_core.js?encoding=utf-8&'><\/script>");
反饋回來的資料包 括上邊的發送和接收地址,以及一個sessionId,這個sessionId很重要,類似於一個key,用於後邊的會話中。由於發送和接收地址是固定的,可以直接寫死,但是sessionId是變動的,所以首先需要將它從反饋回來的茫茫資料中提取出來,我使用的是一個簡單的Regex:
String strResult = EntityUtils.toString(httpResponse.getEntity()); Pattern p = Pattern.compile("sessionId = .(\\d+)"); //get sessionId Matcher m = p.matcher(strResult); if (m.find()) mSessionId = m.group(1);
得到sessionId後,我們就可以進行初始化了,初始化的過程很簡單,將sessionId將填入下邊格式中,發送到伺服器去就行了。
String strSendJoin = Send_Path+ "SID="+ mSessionId+"&USR="+ mSessionId+ "&CMD=JOIN&r=";
初始化完成後,就可以使用下邊的格式網址發送問題以及接收答案:
String strSend = Send_Path + "SID=" + mSessionId + "&USR="+
mSessionId + "&CMD=CHAT&SIG=You&MSG=" + msg +"&FTN=&FTS=&FTC=&r=";String strRec = Recv_Path + "SID=" + mSessionId + "&USR="+mSessionId
+ "&r=";xiaoi.sendMsg(mQuestion);
results = xiaoi.revMsg();
接收到的內容也是需要提取的,使用的是Regex:
String msgTmp = EntityUtils.toString(httpResponse.getEntity()); Pattern p = Pattern.compile("\"MSG\":\"(.*?)\""); Matcher m = p.matcher(msgTmp);if (m.find()) { msg = m.group(1);}
通過上述的小i聊天機器人的介面,你便可以實現一個簡單的,可以自由聊天對話的Siri。小I機器人還是很智能的,聊天的對話也很有意思,但是僅僅只能聊天,這個和iphone
Siri的差距太大了,所以稍後我們將給它添加另外一個智能的大腦。
本文完整代碼如下:
public class XiaoI {private String Webbot_Path = "http://webbot.xiaoi.com/engine/widget1007/webbot.js?encoding=utf-8";private String Send_Path = "http://122.226.240.164/engine/widget1007/send.js?encoding=utf-8&";private String Recv_Path = "http://122.226.240.164/engine/widget1007/recv.js?encoding=utf-8&";private String mSessionId = null;private HttpClient httpClient = null;public boolean initialize() {boolean success=false;HttpParams httpParams = new BasicHttpParams();HttpConnectionParams.setConnectionTimeout(httpParams, 30000);HttpConnectionParams.setSoTimeout(httpParams, 30000);httpClient = new DefaultHttpClient(httpParams);try {String strGetId = Webbot_Path;HttpGet httpRequest = new HttpGet(strGetId);HttpResponse httpResponse = httpClient.execute(httpRequest);if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {String strResult = EntityUtils.toString(httpResponse.getEntity());Pattern p = Pattern.compile("sessionId = .(\\d+)"); //get sessionIdMatcher m = p.matcher(strResult);if (m.find()) {mSessionId = m.group(1);String strSendJoin = Send_Path + "SID=" + mSessionId+ "&USR=" + mSessionId + "&CMD=JOIN&r=";HttpGet httpRequest1 = new HttpGet(strSendJoin);httpResponse = httpClient.execute(httpRequest1);String strRevAsk = Recv_Path + "SID=" + mSessionId+ "&USR=" + mSessionId + "&r=";HttpGet httpRequest2 = new HttpGet(strRevAsk);httpResponse = httpClient.execute(httpRequest2);success=true;}}} catch (ClientProtocolException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}finally{return success;}}public void sendMsg(String msg) {String strTalksend = Send_Path + "SID=" + mSessionId + "&USR="+ mSessionId + "&CMD=CHAT&SIG=You&MSG=" + msg+ "&FTN=&FTS=&FTC=&r=";HttpGet httpRequest = new HttpGet(strTalksend);try {httpClient.execute(httpRequest);} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public String revMsg() {String strTalkRec = Recv_Path + "SID=" + mSessionId + "&USR="+ mSessionId + "&r=";HttpGet httpRequest = new HttpGet(strTalkRec);String msg = null;try {HttpResponse httpResponse = httpClient.execute(httpRequest);if (httpResponse.getStatusLine().getStatusCode() == 200) {String msgTmp = EntityUtils.toString(httpResponse.getEntity());Pattern p = Pattern.compile("\"MSG\":\"(.*?)\"");Matcher m = p.matcher(msgTmp);if (m.find()) {msg = m.group(1);}}} catch (ClientProtocolException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}return msg;}}
使用方法:XiaoI xiaoi = new XiaoI();
xiaoi.initialize();
xiaoi.sendMsg(mQuestion);
results = xiaoi.revMsg();
由於發送接收耗時較多,最好放幕後處理。