这几天闲着无聊想找个人说说话又怕打扰到别人,于是我就想到自己做一个可以对话的AI这样就不无聊了。

首先需要一个AI接口,上网搜了一下还是很多的(大多都要收费)我选了一个免费的AI接口:腾讯AI开放平台(https://ai.qq.com),注册个账号申请一下就可以了。

虽说是大厂的接口,但我个人感觉有点弱智,很多话它都答不上来,反正免费又不要钱就不要在意这些细节了。

接口找到了,接下来就该写代码了。

据腾讯AI开放平台提供的开发文档我们知道首先我们要向服务器发送一个包含6个参数的请求信息:应用标识app_id、请求时间戳time_stamp、随机字符串nonce_str、签名信息sign、会话标识session、用户输入的聊天内容question。

  其中app_id在我们申请到接口后就已经得到了,time_stamp可以通过时间函数实时获取到,session我们可以随便弄一个,现在就差nonce_str和sign了。

 懒得整理,直接上代码:

public class Ichat {
    
    private static String APP_ID = "";    //去腾讯AI开放平台查看
    private static String API_INTERFACE = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat";//请求地址
    private static String SESSION = "100001";//会话
    private static String APP_KEY = "";//去腾讯AI开放平台查看
    
    public static void main(String[] args) throws UnsupportedEncodingException, InterruptedException{
            
        System.out.println("聊天开始:");
        
        while(true){
                
            get(in());
            
        }
        //System.out.println("聊天结束!");
       
    }
    
    
    
    //输入信息
    public static String in(){
        
        Scanner sc = new Scanner(System.in);
        String s = null;
        
        System.out.print("\n我:\n\t");
        
        s = sc.nextLine();
        //sc.close();
        
        return s;
    }
    
    
    
    
    /***打印信息*/
    public static void print(String str){
        
        String answer = null;
        String ret = null;
        
        answer = str.substring(str.indexOf("answer")+10 , str.lastIndexOf("\""));
        
        ret = str.substring(str.indexOf("ret")+6 , str.indexOf(","));
        
        System.out.println("\n智障:\n\t" + (ret.equals("16394") ? "我不明白你在说什么呢!" : answer));
        
    }
    
    
    
    /**
     * 将<key, value>请求参数对按key进行字典升序排序,得到有序的参数对列表N
        将列表N中的参数对按URL键值对的格式拼接成字符串,得到字符串T(如:key1=value1&key2=value2),URL键值拼接过程value部分需要URL编码,
        URL编码算法用大写字母,例如%E8,而不是小写%e8
        将应用密钥以app_key为键名,组成URL键值拼接到字符串T末尾,得到字符串S(如:key1=value1&key2=value2&app_key=密钥)
        对字符串S进行MD5运算,将得到的MD5值所有字符转换成大写,得到接口请求签名
     * 
     * 生成签名
     * 参考 https://blog.csdn.net/Java_Antelope/article/details/100015942
     * @throws IOException 
     */
    private static String sign(TreeMap<String, String> tm){
    
        StringBuffer sb = new StringBuffer();
        
        for(String key: tm.keySet()){

            sb.append(key + "=" + (encode(tm.get(key))).toUpperCase() + "&");
            
        }
        
        sb.append("app_key=" + APP_KEY);
        
        return md5(sb.toString());
    }
    
    
    
    /***URL加密 ***/
    public static String encode(String str){
        
        String s = null;
        //url加解密URLDecoder.decode( URL, "UTF-8" )
        try {
            s = java.net.URLEncoder.encode(str, "UTF-8").toUpperCase();
        } catch (UnsupportedEncodingException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        return s;
    }
    

    
    /***请求信息***/
    public static String post(String question){
        
        //treemap是有序的默认降序排序,hashmap无序
        TreeMap<String , String> tm = new TreeMap<>();
        
        //将数据放入treemap
        tm.put("app_id", APP_ID);
        tm.put("time_stamp", System.currentTimeMillis()/1000 + "");//获得系统时间 秒
        tm.put("nonce_str", random(10));//随机字符串
        tm.put("session", SESSION);
        tm.put("question", question);
        tm.put("sign", sign(tm));//生成秘钥
        
        StringBuffer sb = new StringBuffer();
        
        //将treemap里的内容拼接成url格式
        for(String key: tm.keySet()){

            sb.append(key + "=" + (encode(tm.get(key))).toUpperCase() + "&");
            
        }
        sb.deleteCharAt(sb.length()-1);//去掉字符串结尾的 &
        
        return sb.toString();
        
    }
    
    
    
    /***得到信息***/
    public static void get(String question){
        
        StringBuilder builder=new StringBuilder();//创建实例
        try{//try代码块,当发生异常时会转到catch代码块中
            
            URL url=new URL(API_INTERFACE + "?" + post(question));//创建一个URL类的实例,并指定网址
            
            URLConnection connection=url.openConnection();//创建实例连接指定URL上的内容
            
            java.io.InputStream is=connection.getInputStream();//获取内容的字节流
            
            InputStreamReader isr=new InputStreamReader(is,"utf-8");//将字节流包装为字符串流,并制定编码格式为utf-8
            
            BufferedReader br=new BufferedReader(isr);//创建一个实例用来存放转换后的字符
            
            String line;//定义一个字符串类型变量
            
            
            while ((line=br.readLine()) !=null){//读取信息,并且当信息不为空时
                
                    builder.append(line+"\n");//append方法使builder包含line中的所有信息
                }
            br.close();//关闭流
            isr.close();//关闭流
            is.close();//关闭流
            //System.out.println(builder);//输出读取的信息
            
            }catch (MalformedURLException e){//当try代码块有异常时转到catch代码块 
                e.printStackTrace();//打印异常所在位置及原因
            }catch (IOException e){//当try代码块有异常时转到catch代码块
                e.printStackTrace();//打印异常所在位置及原因
        }
        
        print(builder.toString());
        
    }
        
    
    
    
    /***生成随机字符 ***/
    public static String random(Integer count){
        
        final char[] ARR = {'1','2','3','4','5','6','7','8','9','0',
            'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w',
            'x','y','z'};
        
        Random rand = new Random();
        StringBuilder str = new StringBuilder();
        while (count != 0){
            str.append(ARR[rand.nextInt(ARR.length)]);
            count--;
        }
        return str.toString();
    }
    
    
    /***md5算法***/
    public static String md5(String plainText) {
        
        byte[] secretBytes = null;
        try {
            secretBytes = MessageDigest.getInstance("md5").digest(
                    plainText.getBytes());
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("没有这个md5算法!");
        }
        String md5code = new BigInteger(1, secretBytes).toString(16);
        for (int i = 0; i < 32 - md5code.length(); i++) {
            md5code = "0" + md5code;
        }
        return md5code;
    }

}

 

posted on 2021-06-01 16:49  讨厌鬼  阅读(664)  评论(1)    收藏  举报