1. 程式人生 > >基於SmartQQ協議的QQ聊天機器人-4

基於SmartQQ協議的QQ聊天機器人-4

IE content ... 模塊 查詢 否則 文本 clip backup

本節的主題是:結合上節的分析,具體分析函數的實現

1. 回復消息模塊:

  1. 集中在org.b3log.xiaov.service包。主控文件是QQService.java,其他只是回復算法的api和一些支持工具utils,不用管。目前我在研究怎麽改寫它——支持“基於文本的一問一答”

  2. 配置文件有兩個目前用得上:
    src/main/resources下面的xiaov.properties(針對機器人功能做的一些配置);
    log4j.properties(定制整個項目中的Logger模塊在各個文件中的級別,用於調試和寫日誌)

  3. xiaov.properties中設置了bot.follow.keywords和bot.follow.keywordAnswer,就是【捕獲關鍵字】+【返回對應答案魔板】,但是它只是個demo,我要讓他支持海量文本,並結構化輸入和結構化輸出。更多參數的解釋見我的代碼註釋。

2. 下面針對上述3點進行操作:

  1. 發送消息與回復消息的調用關系:{結合viso繪制調用流程圖}
  2. 見代碼的修改
  3. 我修改了兩個函數:
  • answer裏面回復的邏輯+解決編碼問題+try-catch;
  • QQService.java裏面的onQQGroupMessage對問題的驗證邏輯
/*
// answer裏面回復的邏輯+解決編碼問題+try-catch;
// xiaov_1_0\src\main\java\org\b3log\xiaov\service\QQService.java
     * 這是我對xiaov-1.0的註釋1.0
     * 這個函數非常重要,定義了提問和回答這兩個功能的數據結構及數據來源
* 我會抽時間把這個函數講清楚 TODO * */ private String answer(final String content, final String userName) throws SQLException { if (keywords.size() == 0) // 加載一次即可 { // 獲取keys,只調用一次 keywords = AnswersFromSQLite.getAllKeys(); } // LOGGER.debug(keywords.get(0));// 測試下content
String keyword = ""; for (final String kw : keywords) { if (StringUtils.containsIgnoreCase(content, kw)) { keyword = kw; break; } } // LOGGER.debug(content);// 測試下content // LOGGER.debug(keyword);// 測試下keyword有沒有捕捉到 String ret = ""; String msg = replaceBotName(content); if (StringUtils.isNotBlank(keyword)) { try { // 這部分是我的改寫 ret = AnswersFromSQLite.getValue(keyword);// 自定義回復消息 ret= URLEncoder.encode(ret, "UTF-8"); } catch (final UnsupportedEncodingException e) { LOGGER.log(Level.ERROR, "Search key encoding failed", e); } } else if (StringUtils.contains(content, XiaoVs.QQ_BOT_NAME) && StringUtils.isNotBlank(msg)) { ... // 這部分和作者源碼一致,省略了 } try { ret= URLDecoder.decode(ret, "UTF-8"); } catch (final UnsupportedEncodingException e) { LOGGER.log(Level.ERROR, "ret decoding failed", e); } return ret; } // E:\Software_install\MyEclipse15_20_Work\code_backup\xiaov_1_0\src\main\java\org\b3log\xiaov\service\SQLiteAnswers\AnswersFromSQLite.class public class AnswersFromSQLite { ... //見我的源碼 public static String getValue(String key) throws SQLException { // 測試查詢某條記錄 Dao<t_answers, Integer> dao = getDao(); List<t_answers> ans = queryByOPtions(dao, key); // logger.info(ans.get(0).getValue()); if (ans != null) { return ans.get(0).getValue(); // 僅返回第一條記錄的value字段 } return null; } ... //省略,見我的代碼 }

// QQService.java裏面的onQQGroupMessage對問題的驗證邏輯
// E:\Software_install\MyEclipse15_20_Work\code_backup\xiaov_1_0\src\main\java\org\b3log\xiaov\service\QQService.java
/*
     * 這是我的註釋1.0
     * 這個函數非常重要,我會抽時間把這個函數講清楚 TODO
     * */

    private void onQQGroupMessage(final GroupMessage message) throws SQLException {
        final long groupId = message.getGroupId();
        final long userId = message.getUserId();// 獲取消息的sender的QQ號,與機器人的QQ做比較
        //LOGGER.debug(Long.toString(userId));
        //final long botId = XiaoVs.getInt("qq.bot.id");//從配置文件中讀當前機器人的QQ號 {還有點bug,後面再修}
        
        // 為了解決2872995315溢出的問題,只能把userId和機器人ID比較由 Long比較   轉化成  字符串比較
        String s_userId = Long.toString(userId);
        //final String s_botId = "2872995315";//暫時寫死
        final String s_botId = XiaoVs.getString("qq.bot.id"); //從xiaov.properties配置文件中讀

        final String content = message.getContent();
        final String userName = Long.toHexString(message.getUserId());
        // Push to third system
        String qqMsg = content.replaceAll("\\[\"face\",[0-9]+\\]", "");
        if (StringUtils.isNotBlank(qqMsg)) {
            qqMsg = "<p>" + qqMsg + "</p>";
            sendToThird(qqMsg, userName);
        }

        String msg = "";
        // 下面是對於QQ用戶提問的語句進行合法性分析,如果符合規則,那就收集答案,並發送到QQ群 {要避免機器人自問自答的情況發生}
        /*
        if (StringUtils.contains(content, XiaoVs.QQ_BOT_NAME)
                || (StringUtils.length(content) > 6
                && (StringUtils.contains(content, "?") || StringUtils.contains(content, "?") || StringUtils.contains(content, "問")))) {
            msg = answer(content, userName);
        }*/
        if ( StringUtils.contains(content, XiaoVs.QQ_BOT_NAME) // TODO:這裏是對提問的基本要求{過濾不合法的提問}
             || (StringUtils.length(content) > 0) && !(s_userId.equals(s_botId))  ) { //徹底解決了機器人自問自答的bug
            msg = answer(content, userName);
        }
        
        if (StringUtils.isBlank(msg)) {
            return;
        }

        if (RandomUtils.nextFloat() >= 0.9) {
            Long latestAdTime = GROUP_AD_TIME.get(groupId);
            if (null == latestAdTime) {
                latestAdTime = 0L;
            }

            final long now = System.currentTimeMillis();

            if (now - latestAdTime > 1000 * 60 * 30) {
                msg = msg + "。\n" + ADS.get(RandomUtils.nextInt(ADS.size()));

                GROUP_AD_TIME.put(groupId, now);
            }
        }

        sendMessageToGroup(groupId, msg);
    }
  • 我覺得必須要放到svn或者git托管了,否則一旦出錯了,沒有回滾項目就完了

3. 突然發現的小Tips:

突然發現,其實還有個小薇的守護QQ(在哪裏有寫?防止丟消息??)但是我目前沒用守護QQ,依舊正常運行,後面有需要再處理這個tips

基於SmartQQ協議的QQ聊天機器人-4