By 何明桂(http://blog.youkuaiyun.com/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>");
- 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=";results = xiaoi.revMsg();
接收到的内容也是需要提取的,使用的是正则表达式:
- String msgTmp = EntityUtils.toString(httpResponse.getEntity());
- Pattern p = Pattern.compile("\"MSG\":\"(.*?)\"");
- Matcher m = p.matcher(msgTmp);
- (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 sessionId
- Matcher 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 block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.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 block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return msg;
- }
- }
使用方法:XiaoI xiaoi = new XiaoI();
xiaoi.initialize();
xiaoi.sendMsg(mQuestion);
results = xiaoi.revMsg();
由于发送接收耗时较多,最好放后台处理。
- 上一篇:android 3D系列之纹理篇
-
By 何明桂(http://blog.youkuaiyun.com/hmg25) 转载请注明出处
在给我们的Siri添加小I的接口之后,感觉它还是不够智能,无法像Iphone的Siri一样功能强大。可是国内我依旧没有找到一个能够强大如苹果Siri的服务器,所以只能退而求其次,我引入了”虫洞“的开放API,网站http://www.uzoo.cn/,这是一个功能很强大的接口,可以根据你提供的关键字进行网络搜索,反馈给你答案,官方上的描述:
·支持生活、教育、娱乐等最常使用的几十种功能;
·功能包括:公交、百科、提问、报价、翻译、快讯、歌词、余票……
·自动识别IP地址,查询公交、天气等功能时可以免输入关键词(城市名)
·可查询全国各地周边的餐馆、酒店、银行、学校、机关单位、娱乐场所……
·可选择推送流行IN语、生活小知识、笑话……这个完全可以实现很智能的功能,但是有一个很致命的缺陷,由于太过智能了,不能实现基本的聊天功能,比如你发句”你好“,它就会在百度百科里给你搜索返回一个你好的详细解释。冏,
~_~!所以我们只好刚柔兼并,区分用于无聊调戏的聊天模式以及正常使用的问答模式。好啦,言归正传,今天我们就来实现用于问答模式的虫洞开放API~~详细信息请查询:
http://www.uzoo.cn/web201012/kaifangAPI.jsp
顺便提一句:他们官方QQ交流群里的人都很热情,特别是光年5号,哈哈,耐心回答了我很多问题,感谢一下~~~
虫洞的接口是开放的API,所以使用起来方便多了~
接口地址:
http://wap.unidust.cn/api/searchout.do
参数表:
是否必需
字段名
名称
类型
说明
是
info
查询内容
Text
查询内容,建议采取post方式传参
type
请求类型
CHAR(6)
web或者wap或者client
ch
渠道代码
CHAR(5)
以区分请求来源
否
appid
应用id
CHAR(12)
等同于分类关键字,若为空则后台自动进行判断
使用起来很简单:
- private String WebAPI_Path= "http://wap.unidust.cn/api/searchout.do?type=wap&ch=1001&info=";
- String strQuestion = WebAPI_Path+ question;
直接在开放的API接口后边添加问题,然后接收反馈就行了。
例如”http://wap.unidust.cn/api/searchout.do?type=wap&ch=1001&info=深圳时间“
需要特别注意下的是,反馈回来是数据是UTF-8格式的,所以对于反馈回来的数据需要进行下编码的转换:
- String str = EntityUtils.toString(httpResponse.getEntity());
- ult = new String(str.getBytes("ISO-8859-1"), "UTF-8");
由于反馈回来的数据中包含一些不需要的数据,所以需要裁剪下:
- public Spanned getAnswer(String question){
- String result=getResult(question);
- int firstIndex=result.indexOf("<br/>")+"<br/>".length();
- int lastIndex=result.lastIndexOf("<br/>");
- return Html.fromHtml(result.substring(firstIndex,lastIndex));
- }
本文完整代码:
- public class ChongDong {
- private String WebAPI_Path = "http://wap.unidust.cn/api/searchout.do?type=wap&ch=1001&info=";
- private HttpClient httpClient = null;
- Handler mHandler;
- private ProgressDialog mProgressDialog;
- Context mContext;
- public ChongDong(Context context,Handler handler){
- mContext=context;
- mHandler=handler;
- }
- public String getResult(String question) {
- String strResult = null;
- HttpParams httpParams = new BasicHttpParams();
- HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
- HttpConnectionParams.setSoTimeout(httpParams, 30000);
- httpClient = new DefaultHttpClient(httpParams);
- try {
- String strQuestion = WebAPI_Path + question;
- HttpGet httpRequest = new HttpGet(strQuestion);
- HttpResponse httpResponse = httpClient.execute(httpRequest);
- if (httpResponse.getStatusLine().getStatusCode() == HttpURLConnection.HTTP_OK) {
- String str = EntityUtils.toString(httpResponse.getEntity());
- strResult = new String(str.getBytes("ISO-8859-1"), "UTF-8");
- }
- } catch (ClientProtocolException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- return strResult;
- }
- }
- public Spanned getAnswer(String question){
- String result=getResult(question);
- int firstIndex=result.indexOf("<br/>")+5;
- // int secondIndex=result.indexOf("<br/>", firstIndex)+5;
- int lastIndex=result.lastIndexOf("<br/>");
- /*if(lastIndex>secondIndex)
- return Html.fromHtml(result.substring(secondIndex,lastIndex));
- else*/
- return Html.fromHtml(result.substring(firstIndex,lastIndex));
- }
- public void handleAnswer(String question) {
- mProgressDialog =new ProgressDialog(mContext);
- mProgressDialog.setMessage("这个问题有点难,让我好好想想");
- mProgressDialog.setCancelable(false);
- mProgressDialog.show();
- new ThreadProcess(question).start();
- }
- class ThreadProcess extends Thread
- {
- String question=null;
- public ThreadProcess(String quest){
- question=quest;
- }
- public void run() {
- String result=getResult(question);
- Message message = new Message();
- message.what = 2013;
- message.obj =getAnswer(result);
- mHandler.sendMessage(message);
- mProgressDialog.dismiss();
- }
- }
- }