最近对人工智能感兴趣,查询之后发现了图灵,开放的机器人接口,自然要实现一把了。
当然了本人页面功底较差,(ps:毕竟主要java吗。)对话框,基本上样式抠的图灵的示例窗口,自己实现各种js的效果。
有什么不完善的地方,大家见谅啊。
一、aichart.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>aichart</title> <script type="text/javascript" src="/mblog/assets/js/jquery.min.js"></script> <script type="text/javascript" src="/mblog/assets/tl/tl.js"></script> <style type="text/css"> .dialog{ width: 150px; height: 250px; position:fixed; right:0; top:10% } .dialog img{ display: block; max-width: 100%; height: auto; width: auto\9; } .dialog a:-webkit-any-link { color: -webkit-link; text-decoration: underline; cursor: auto; } .dialog .dialog-right{ width:150px; height: 250px; border: 2px solid #C6DAF5; z-index:999; position: fixed; right: 0; } .dialog .dialog-left{ width:430px; height: 250px; position: fixed; border: 2px solid #C6DAF5; z-index:998; float: right; right: -300px; } .dialog .dialog-right .right-title{ width:100%; height: 10%; font-size:12pt; font-weight:bold; text-align: center; border: 2px solid #C6DAF5; background-color: #C6DAF5; } .dialog .dialog-right .right-pic{ width:100%; height: 90%; background:url(assets/images/ai/timg.png) center; } .dialog-left .chart-area{ width: 440px; height: 250px; border: #dbdada solid 1px; -ms-box-shadow: 0 0 5px 0 #dbdada; -moz-box-shadow: 0 0 5px 0 #dbdada; -webkit-box-shadow: 0 0 5px 0 #dbdada; -o-box-shadow: 0 0 5px 0 #dbdada; box-shadow: 0 0 5px 0 #dbdada; background: #fff; overflow: hidden; position: relative; z-index:998; } .dialog-left .chart-area .roll{ width: 2px; height: 200px; position: absolute; right: 12px; top: 20px; background: #ededed; z-index: 5; display: none; } .chart-area .roll span { width: 6px; height: 26px; background: #ededed; position: absolute; left: -2px; top: 0px; -ms-border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -o-border-radius: 3px; border-radius: 3px; cursor: pointer; } .displayArea { margin-top: 3px; width: 430px; height: 200px; overflow-y: scroll; border-bottom: #f0f0f0 solid 1px; position: relative; overflow:auto; } .rotWord { width:100%; overflow:hidden; margin-bottom: 8px; } .rotWord1 { width:100%; overflow:hidden; margin-bottom: 8px; } .rotWord span { background: url(assets/images/ai/timg.png) no-repeat; height: 30px; width: 30px; float: left; margin-left: 5px; } .rotWord1 span { background: url(assets/images/ai/timg.png) no-repeat; height: 30px; width: 30px; float: left; margin-left: 5px; } .rotWord1 .findMsg{ float: left; margin-left: 14px; width: 210px; padding-bottom: 10px; background: #f1f1f1; -ms-border-radius: 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; -o-border-radius: 8px; border-radius: 8px; position: relative; } .rotWord1 .findMsg i{ position: absolute; width: 0; height: 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-right: 6px solid #f1f1f1; left: -6px; top: 14px; } .rotWord1 .findMsg .main{ width: 188px; border: #dcdcdc solid 1px; margin: 10px auto 0; -ms-border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; -o-border-radius: 4px; border-radius: 4px; } .rotWord1 .findMsg .pic{ position: relative; } .rotWord1 .findMsg .pic img{ display: block; width: 188px; height: 74px; } .rotWord1 .findMsg p{ font-size: 12px; height: 16px; line-height: 16px; text-align: center; position: absolute; left: 0; bottom: 0; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; background: rgba(0,0,0,0.5); color: #fff; } .rotWord1 .findMsg a{ text-decoration: none; } .rotWord1 .findMsg .info{ height: 36px; padding: 2px 6px; background: #fff; } .rotWord1 .findMsg .info img{ float: right; width: 25px; height: 25px; margin: 6px 7px 0 0; } .rotWord1 .findMsg .info .make{ float: left; width: 140px; line-height: 38px; height: 38px; font-size: 12px; color: #8e8c8c; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } .rotWord1 .findMsg .line{ height: 1px; background: #dcdcdc; } .rotWord p { word-break: break-all; float: left; color: #333; font-size: 14px; padding: 3px 15px; line-height: 24px; background: #f1f1f1; -ms-border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; -o-border-radius: 6px; border-radius: 6px; position: relative; max-width: 220px; margin: 0px 0px 0px 14px; } .rotWord p a{ color: #2373be; text-decoration: none; } .rotWord p i{ position: absolute; width: 0; height: 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-right: 6px solid #f1f1f1; left: -6px; top: 10px; } .mWord { width:100%; overflow:hidden; margin-bottom: 5px; } .mWord span { background: url(assets/images/ai/timg.png) no-repeat; height: 30px; width: 30px; float: right; margin-right: 5px; } .mWord p { word-break: break-all; float: right; color: #fff; font-size: 14px; padding: 3px 15px; line-height: 24px; background: #19b955; -ms-border-radius: 6px; -moz-border-radius: 6px; -webkit-border-radius: 6px; -o-border-radius: 6px; border-radius: 6px; position: relative; max-width: 210px; margin: 0px 14px 0px 0px; } .mWord p i{ position: absolute; width: 0; height: 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-left: 6px solid #19b955; right: -6px; top: 10px; } .writeArea { height: 30px; margin-top: 10px; } .writeArea input { width: 330px; height: 25px; line-height: 25px; float: left; margin-left: 12px; border: #d0cfcf solid 1px; -ms-border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; -o-border-radius: 4px; border-radius: 4px; text-indent: 14px; -ms-box-shadow: 1px 1px 2px 0 #d0cfcf; -moz-box-shadow: 1px 1px 2px 0 #d0cfcf; -webkit-box-shadow: 1px 1px 2px 0 #d0cfcf; -o-box-shadow: 1px 1px 2px 0 #d0cfcf; box-shadow: 1px 1px 2px 0 #d0cfcf; font-size: 14px; } .writeArea span { cursor: pointer; float: left; margin-left: 12px; color: #fff; font-size: 14px; width: 40px; height: 25px; text-align: center; line-height: 25px; -ms-border-radius: 4px; -moz-border-radius: 4px; -webkit-border-radius: 4px; -o-border-radius: 4px; border-radius: 4px; background: #00a3f0; } </style> </head> <body style="height:1500px"> <div id="ai_chart_dialog" class="dialog"> <div class="dialog-right"> <div class="right-title">小智</div> <div class="right-pic"></div> </div> <div class="dialog-left"> <div class="chart-area"> <div class="roll" style="display: none;"><span class="point" style="top: 0px;"></span></div> <div class="displayArea" > <div class="diswap"> <div class="rotWord"> <span></span> <p id="member">小娜在此<i></i></p></div> </div> </div> <div class="writeArea"> <input type="text" maxlength="200" placeholder="聊点什么吧"> <span >发 送</span> </div> </div> </div> </div> <script type="text/javascript"> var tuling_button = $('#ai_chart_dialog .dialog-left .writeArea span');//document.getElementById("tuling_button"); function getLen(val){ var len = 0; for (var i=0; i<val.length; i++) { if (val.charCodeAt(i)>127 || val.charCodeAt(i)==94) { len += 2; } else { len ++; } } return len; } function talk(){ //获取输入值 var input = $('#ai_chart_dialog .dialog-left .writeArea input');//document.getElementById("tuling_input"); var val = input.val(); var tuling_dialog = $('#ai_chart_dialog .dialog-left .displayArea .diswap');//document.getElementById("tuling_dialog"); var len = getLen(val); if(len <=0){ //添加机器人回话 tuling_dialog.append("<div class='rotWord' ><span></span><p>还是说点什么吧?<i></i></p></div>"); //滚动条自动到底 }else if(len >32){ //添加机器人回话 tuling_dialog.append("<div class='rotWord' ><span></span><p>好长的句子啊,理解不了了:(<i></i></p></div>"); }else{ //添加自己的问题 tuling_dialog.append("<div class='mWord'><span></span><p>"+val+"<i></i></p></div>"); //发送请求 $.post("AI/tl",{info:val},function(result){ var obj = eval('(' + result + ')'); if(obj.code == 0){ tuling_dialog.append(AITL.parseResult(AITL.toJson(obj.data))); $('#ai_chart_dialog .dialog-left .displayArea').scrollTop($('#ai_chart_dialog .dialog-left .displayArea')[0].scrollHeight); }else{ alert("error"); $('#ai_chart_dialog .dialog-left .displayArea').scrollTop($('#ai_chart_dialog .dialog-left .displayArea')[0].scrollHeight); } }); } //滚动条自动到底 $('#ai_chart_dialog .dialog-left .displayArea').scrollTop($('#ai_chart_dialog .dialog-left .displayArea')[0].scrollHeight);// = $('#ai_chart_dialog .dialog-left .displayArea').height(); //清空输入值 input.val(""); } //绑定回车输入 $('#ai_chart_dialog .dialog-left .writeArea input').bind('keyup', function(event) { if (event.keyCode == "13") { //回车执行查询 talk(); } }); //绑定点击发送时间 $('#ai_chart_dialog .dialog-left .writeArea span').click(function(){ talk(); }); $(function(){ var expanded = true; $('#ai_chart_dialog .dialog-right').click(function(){ if(expanded){ $('#ai_chart_dialog').width(600); $('#ai_chart_dialog .dialog-left').animate({right:'150px'},100); }else{ $('#ai_chart_dialog').width(150); $('#ai_chart_dialog .dialog-left').animate({right:'-300px'},100); } expanded = !expanded; }); }); </script> </body> </html>
二、tl.js
function AITL() { function error(){ return "<div class='rotWord' ><span></span><p>小娜好像生病了,麻烦找找站长医生给看看吧:(<i></i></p></div>"; } function isJson(resjson){ var isjson = typeof(obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && !obj.length; return isjson; }; this.parseText = function(resjson){ var res=""; if(isJson(resjson)){ res = error(); }else{ res = "<div class='rotWord' ><span></span><p>"+resjson.text+"<i></i></p></div>"; } return res; }; this.parseLink = function(resjson){ var res=""; if(isJson(resjson)){ res = error(); }else{ res = "<div class='rotWord' ><span></span><p>"+resjson.text+"<a href='"+resjson.url+"' target=\"_blank\">打开页面</a><i></i></p></div>"; } return res; }; this.parseNews = function(resjson){ var res=""; if(isJson(resjson)){ res = error(); }else{ res = "<div class=\"rotWord1 \">"+ "<span></span> " + "<div class=\"findMsg\"> " + "<i></i> " + "<div class=\"main\"> " ; var newslist = resjson.list; for(var j=0;j<newslist.length;j++){ var news = newslist[j]; if(j==0){ res = res+ "<div class=\"pic\">" + "<p>"+news.article+"</p> " + "<a href=\"" + news.detailurl + "\" target=\"_blank\">" + "<img src=\""+news.icon+"\" alt=\"\">" + "</a> " + "</div> "; }else if(j==newslist.length-1){ res = res+ "<div class=\"info\"> " + "<a href=\""+news.detailurl+"\" target=\"_blank\"> " + "<div class=\"make\">"+news.article+"</div> " + "</a>" + "<a href=\""+news.detailurl+"\" target=\"_blank\">" + "<img src=\""+news.icon+"\" alt=\"\">" + "</a> " + "</div> " + "</div> " + "</div> " + "</div>"; }else{ res = res+ "<div class=\"info\"> " + "<a href=\""+news.detailurl+"\" target=\"_blank\"> " + "<div class=\"make\">"+news.article+"</div> " + "</a>" + "<a href=\""+news.detailurl+"\" target=\"_blank\">" + "<img src=\""+news.icon+"\" alt=\"\">" + "</a> " + "</div> " + "<div class=\"line\"></div> "; } } } return res; }; this.parseFood = function(resjson){ var res=""; if(isJson(resjson)){ res = error(); }else{ res = "<div class=\"rotWord1 clearfix\"> " + "<span></span> " + "<div class=\"findMsg\"> " + "<i></i> " + "<div class=\"main\">"; var foodlist = resjson.list; for(var j=0;j<foodlist.length;j++){ var food = foodlist[j]; if(j==foodlist.length-1){ res = res + "<div class=\"info\"> " + "<a href=\""+food.detailurl+"\" target=\"_blank\"> " + "<div class=\"make\">"+food.info+"</div> " + "</a>" + "</div>" + "</div> " + "</div> " + "</div>"; }else{ res = res + "<div class=\"info\"> " + "<a href=\""+food.detailurl+"\" target=\"_blank\"> " + "<div class=\"make\">"+food.info+"</div> " + "</a>" + "</div> " + "<div class=\"line\"></div>"; } } } return res; }; this.parseErGe = function(resjson){ var res = ""; return res; }; this.parseShiCi = function(resjson){ var res = ""; return res; }; this.parseError = function(resjson){ var res = ""; if(isJson(resjson)){ res = error(); }else{ if(resjson.code == 40002){ res = "<div class='rotWord' ><span></span><p>还是说点什么吧。<i></i></p></div>"; }else if(resjson.code == 40004){ res = "<div class='rotWord' ><span></span><p>她下班了,明天再来玩吧。<i></i></p></div>"; }else{ res = error(); } } return res; }; this.parseNOCODE = function(resjson){ var res = ""; if(isJson(resjson)){ res = error(); }else{ res = error(); } return res; }; }; AITL.toJson = function(str) { return JSON.parse(str); }; AITL.parseResult = function(resjson) { var a = new AITL(); var code = resjson.code; if (code == 100000) { return a.parseText(resjson); } else if (code == 200000) { return a.parseLink(resjson); } else if (code == 302000) { return a.parseNews(resjson); } else if (code == 308000) { return a.parseFood(resjson); } else if (code == 313000) { return a.parseErGe(resjson); } else if (code == 314000) { return a.parseShiCi(resjson); } else if (code == 40001 || code ==40002 || code == 40004 || code ==4007) { return a.parseError(resjson); } else{ return a.parseNOCODE(resjson); } }
三、后端java
controller 这个只给有用的部分吧,毕竟用什么框架的都有自己弄个就好了
String userid = request.getSession().getId(); //图灵网站上的secret //待加密的json数据 String data = "{\"key\":\""+apiKey+"\",\"info\":\""+info+"\",\"userid\":\""+userid+"\"}"; //获取时间戳 String timestamp = String.valueOf(System.currentTimeMillis()); //生成密钥 String keyParam = secret+timestamp+apiKey; String key = Md5.MD5(keyParam); //加密 Aes mc = new Aes(key); data = mc.encrypt(data); //封装请求参数 JSONObject json = new JSONObject(); json.put("key", apiKey); json.put("timestamp", timestamp); json.put("data", data); //请求图灵api String result = PostServer.SendPost(json.toString(), url);
使用到的其他的类,是图灵给的demo里面的东西。也贴出来吧。
Aes.java package org.mblog.tlai.util; import java.security.Key; import java.security.MessageDigest; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; /** * aes加密算法 * @author 图灵机器人 * */ public class Aes { private Key key; /** * AES CBC模式使用的Initialization Vector */ private IvParameterSpec iv; /** * Cipher 物件 */ private Cipher cipher; /** * 构造方法 * @param strKet * 密钥 */ public Aes(String strKey) { try { this.key = new SecretKeySpec(getHash("MD5", strKey), "AES"); this.iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); } catch (final Exception ex) { throw new RuntimeException(ex.getMessage()); } } /** * 加密方法 * * 说明:采用128位 * * @return 加密结果 */ public String encrypt(String strContent) { try { byte[] data = strContent.getBytes("UTF-8"); cipher.init(Cipher.ENCRYPT_MODE, key, iv); byte[] encryptData = cipher.doFinal(data); String encryptResult = new String(Base64.encodeBase64( encryptData), "UTF-8"); return encryptResult; } catch (Exception ex) { throw new RuntimeException(ex.getMessage()); } } /** * * @param algorithm * @param text * @return */ private static byte[] getHash(String algorithm, String text) { try { byte[] bytes = text.getBytes("UTF-8"); final MessageDigest digest = MessageDigest.getInstance(algorithm); digest.update(bytes); return digest.digest(); } catch (final Exception ex) { throw new RuntimeException(ex.getMessage()); } } } ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Md5.java package org.mblog.tlai.util; import java.security.MessageDigest; /** * md5加密 * @author 图灵机器人 * */ public class Md5 { /** * MD5加密算法 * * 说明:32位加密算法 * * @param 待加密的数据 * @return 加密结果,全小写的字符串 */ public static String MD5(String s) { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; try { byte[] btInput = s.getBytes("utf-8"); // 获得MD5摘要算法的 MessageDigest 对象 MessageDigest mdInst = MessageDigest.getInstance("MD5"); // 使用指定的字节更新摘要 mdInst.update(btInput); // 获得密文 byte[] md = mdInst.digest(); // 把密文转换成十六进制的字符串形式 int j = md.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = md[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); } catch (Exception e) { e.printStackTrace(); return null; } } }
++++++++++++++++++++++++++++++++++++++++++
PostServer.java package org.mblog.tlai.util; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.URL; /** * HTTP工具类 * @author 图灵机器人 * */ public class PostServer { /** * 向后台发送post请求 * @param param * @param url * @return */ public static String SendPost(String param, String url) { OutputStreamWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) realUrl .openConnection(); conn.setDoOutput(true); conn.setDoInput(true); conn.setUseCaches(false); conn.setRequestMethod("POST"); conn.setConnectTimeout(50000); conn.setReadTimeout(50000); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Accept", "application/json"); conn.setRequestProperty("Authorization", "token"); conn.setRequestProperty("tag", "htc_new"); conn.connect(); out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8"); out.write(param); out.flush(); out.close(); // in = new BufferedReader(new InputStreamReader( conn.getInputStream(), "UTF-8")); String line = ""; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { e.printStackTrace(); } finally { try { if (out != null) { out.close(); } if (in != null) { in.close(); } } catch (IOException ex) { ex.printStackTrace(); } } return result; } }
乐享:知识积累,快乐无限。