Bladeren bron

修改标签

YPZ 20 uur geleden
bovenliggende
commit
318bb80d95

+ 39 - 3
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketEmailsServiceImpl.java

@@ -585,8 +585,15 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
             // 不再做 inner.toString() 兜底——整串 Result 里有 files=[]/inputs=[] 等空数组
             // 会被误当成 AI 输出的 JSON 数组(如 [models]),污染解析。
             String text = extractCleanText(r.getResult());
-            //去掉text中<think>...</think>之间的内容,<think>...</think>也不保留
-            text = text.replaceAll("<think>.*?</think>", "");
+            // 去掉 <think>...</think>(含标签本身)。思考块是多行的,必须用 stripThinkBlocks 里的 DOTALL 正则,
+            // 直接写 replaceAll("<think>.*?</think>", "") 会因为 . 不匹配换行而整段删不掉。
+            text = stripThinkBlocks(text);
+            if (text == null) {
+                log.warn("AI 返回内容为空,emailId={}", marketEmailsEntity.getId());
+                return;
+            }
+            // 删掉思考块后正文开头/结尾常留下一串空行:连续 3 个以上换行压成 2 个(保留段落间隔),再去首尾空白
+            text = text.replaceAll("\\n{3,}", "\n\n").trim();
             marketEmailsEntity.setContent(text);
 
             this.updateById(marketEmailsEntity);
@@ -1820,6 +1827,35 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
         return t == null ? null : t.toString();
     }
 
+    /**
+     * 剥掉 AI 输出里的思考块。
+     * <p>
+     * 规则:<strong>凡是落在 {@code <think>} 与 {@code </think>} 之间的内容,连同这两个标签本身一起删掉</strong>;
+     * 标签之外的正文原样保留(多个思考块夹着正文时,只删块、保留正文)。
+     * <p>
+     * 两个坑:
+     * <ol>
+     *   <li><strong>必须开 DOTALL</strong>。模型的思考过程几乎都是多行的,而 Java 正则里 {@code .} 默认
+     *       不匹配 {@code \n}。写成 {@code "<think>.*?</think>"} 时多行块整个匹配不上,
+     *       结果就是一整段思考过程原样留在邮件正文里 —— 本次的 bug 就在这里。</li>
+     *   <li>兼容"只有 {@code <think>} 没有 {@code </think>}"的截断情况(思考过程超长被砍断很常见),
+     *       此时从开标签一直删到文本结尾,避免思考片段混进正文。</li>
+     * </ol>
+     *
+     * @param text 原始文本,允许为 null
+     * @return 去掉思考块后的文本;null 原样返回
+     */
+    private String stripThinkBlocks(String text) {
+        if (text == null || text.isEmpty()) {
+            return text;
+        }
+        // (?s) 让 . 匹配换行;(?i) 兼容 <Think>;[^>]* 兼容带属性的开标签(如 <think lang="zh">)
+        // (?:...</think>|$) 兜底未闭合:有闭合标签就截到闭合处,没有就截到结尾
+        String cleaned = text.replaceAll("(?si)<think\\b[^>]*>[\\s\\S]*?(?:</think>|$)", "");
+        // 再兜一层:清掉可能残留的孤立标签(比如正文里孤零零一个 </think>)
+        return cleaned.replaceAll("(?i)</?think\\b[^>]*>", "");
+    }
+
     /**
      * 从 AI 文本中解析排期阶段列表。
      * 兼容:思考块包裹、json 代码块、裸数组、全角标点/括号,以及模型把输出数组重复拼接的情况。
@@ -1943,7 +1979,7 @@ public class MarketEmailsServiceImpl extends MyBaseServiceImpl<MarketEmailsMappe
      */
     private List<String> extractJsonCandidates(String text) {
         List<String> result = new ArrayList<>();
-        String cleaned = text.replaceAll("(?s)<think>[\\s\\S]*?</think>", "");
+        String cleaned = stripThinkBlocks(text);
         int from = 0;
         while (true) {
             int start = cleaned.indexOf('[', from);

+ 1 - 0
java/storlead-sasa/storlead-trade/src/main/java/com/storlead/trade/service/impl/MarketingCampaignServiceImpl.java

@@ -264,6 +264,7 @@ public class MarketingCampaignServiceImpl
         List<MarketEmailsEntity> campaignEmails = marketEmailsService.lambdaQuery()
                 .eq(MarketEmailsEntity::getMarketingCampaignId, id)
                 .eq(MarketEmailsEntity::getHasFirst, 1)
+                .ne(MarketEmailsEntity::getStatus,-3)
                 .eq(MarketEmailsEntity::getIsDelete, CommonConstant.DEL_FLAG_0)
                 .list();
         for (MarketEmailsEntity email : campaignEmails) {