cc пре 3 дана
родитељ
комит
fe18a4d102

+ 40 - 16
ai-server/src/main/java/com/zsjz/ai/module/aiclean/service/AiSmartCleanService.java

@@ -68,7 +68,9 @@ public class AiSmartCleanService {
 
 
     private final DmService dmService;
     private final DmService dmService;
 
 
-    /** 进度与终态全部走 SSE 推送(cmd 103),前端不再轮询状态接口 */
+    /**
+     * 进度与终态全部走 SSE 推送(cmd 103),前端不再轮询状态接口
+     */
     private final SseService sseService;
     private final SseService sseService;
 
 
     private final FileInfoMapper fileInfoMapper;
     private final FileInfoMapper fileInfoMapper;
@@ -88,11 +90,15 @@ public class AiSmartCleanService {
     @Value("${zsjz.ai-clean.batch-token-budget:0}")
     @Value("${zsjz.ai-clean.batch-token-budget:0}")
     private long batchTokenBudget;
     private long batchTokenBudget;
 
 
-    /** 每任务一个虚拟线程,真正的并发上限由闸门控制(与 FileRecognitionService 同一套) */
+    /**
+     * 每任务一个虚拟线程,真正的并发上限由闸门控制(与 FileRecognitionService 同一套)
+     */
     private final ExecutorService executor = Executors.newThreadPerTaskExecutor(
     private final ExecutorService executor = Executors.newThreadPerTaskExecutor(
             Thread.ofVirtual().name("ai-clean-", 0).factory());
             Thread.ofVirtual().name("ai-clean-", 0).factory());
 
 
-    /** 待人工明细:判定阶段并发写入 */
+    /**
+     * 待人工明细:判定阶段并发写入
+     */
     private final Map<Long, List<NeedReviewItem>> reviewItems = new ConcurrentHashMap<>();
     private final Map<Long, List<NeedReviewItem>> reviewItems = new ConcurrentHashMap<>();
 
 
     /**
     /**
@@ -119,7 +125,7 @@ public class AiSmartCleanService {
         int sheetTotal = usable.stream()
         int sheetTotal = usable.stream()
                 .mapToInt(r -> r.getChildren() == null ? 0 : r.getChildren().size()).sum();
                 .mapToInt(r -> r.getChildren() == null ? 0 : r.getChildren().size()).sum();
         int matched = (int) usable.stream().flatMap(r -> r.getChildren() == null
         int matched = (int) usable.stream().flatMap(r -> r.getChildren() == null
-                ? java.util.stream.Stream.<FileInfo>empty() : r.getChildren().stream())
+                        ? java.util.stream.Stream.<FileInfo>empty() : r.getChildren().stream())
                 .filter(s -> s != null && s.getTemplateId() != null).count();
                 .filter(s -> s != null && s.getTemplateId() != null).count();
         BatchRef ref = upsertBatch(caseId, batchId, usable.size(), sheetTotal, matched);
         BatchRef ref = upsertBatch(caseId, batchId, usable.size(), sheetTotal, matched);
         if (!ref.fresh()) {
         if (!ref.fresh()) {
@@ -143,7 +149,9 @@ public class AiSmartCleanService {
         Thread.startVirtualThread(body);
         Thread.startVirtualThread(body);
     }
     }
 
 
-    /** 前端轮询(兼容旧入口;实时进度已改为 SSE 推送,见 {@link #pushProgress}) */
+    /**
+     * 前端轮询(兼容旧入口;实时进度已改为 SSE 推送,见 {@link #pushProgress})
+     */
     public SmartCleanStatusVO status(Long caseId, Long batchId) {
     public SmartCleanStatusVO status(Long caseId, Long batchId) {
         AiCleanBatch batch = batchMapper.selectOne(Wrappers.<AiCleanBatch>lambdaQuery()
         AiCleanBatch batch = batchMapper.selectOne(Wrappers.<AiCleanBatch>lambdaQuery()
                 .eq(AiCleanBatch::getCaseId, caseId)
                 .eq(AiCleanBatch::getCaseId, caseId)
@@ -227,7 +235,9 @@ public class AiSmartCleanService {
 
 
     // ==================== 后台主流程 ====================
     // ==================== 后台主流程 ====================
 
 
-    /** 后台主流程:判定(并发)→ 一次 doClean → AI 自建表入库 → 终态 */
+    /**
+     * 后台主流程:判定(并发)→ 一次 doClean → AI 自建表入库 → 终态
+     */
     void run(Long batchId, Long caseId, List<FileInfo> roots) {
     void run(Long batchId, Long caseId, List<FileInfo> roots) {
         long start = System.currentTimeMillis();
         long start = System.currentTimeMillis();
         Stats st = new Stats();
         Stats st = new Stats();
@@ -371,7 +381,9 @@ public class AiSmartCleanService {
         }
         }
     }
     }
 
 
-    /** 单表失败:只影响它自己那条 job 与计数,不中断整批 */
+    /**
+     * 单表失败:只影响它自己那条 job 与计数,不中断整批
+     */
     private void fail(Long batchId, PendingAi p, String reason, Stats st) {
     private void fail(Long batchId, PendingAi p, String reason, Stats st) {
         aiCleanService.finish(p.job(), AiCleanStatusEnum.FAIL, reason, System.currentTimeMillis());
         aiCleanService.finish(p.job(), AiCleanStatusEnum.FAIL, reason, System.currentTimeMillis());
         st.failed.incrementAndGet();
         st.failed.incrementAndGet();
@@ -434,7 +446,9 @@ public class AiSmartCleanService {
         return applied;
         return applied;
     }
     }
 
 
-    /** 把本级的 sheet 挂到根节点<b>浅拷贝</b>上发一趟既有清洗,并等它全部落库 */
+    /**
+     * 把本级的 sheet 挂到根节点<b>浅拷贝</b>上发一趟既有清洗,并等它全部落库
+     */
     private void runCleanPass(List<FileInfo> roots, Map<FileInfo, List<FileInfo>> sheetsByRoot, boolean silent) {
     private void runCleanPass(List<FileInfo> roots, Map<FileInfo, List<FileInfo>> sheetsByRoot, boolean silent) {
         // 根节点用浅拷贝:不改动前端提交的原始树;两趟各持各的根,互不覆盖
         // 根节点用浅拷贝:不改动前端提交的原始树;两趟各持各的根,互不覆盖
         // (sheet 对象本身仍是同一批引用,瞬态字段只在分组时写一次)
         // (sheet 对象本身仍是同一批引用,瞬态字段只在分组时写一次)
@@ -492,9 +506,9 @@ public class AiSmartCleanService {
 
 
     /**
     /**
      * 建/重置批次。
      * 建/重置批次。
-     *
-     * @param fresh false 表示上一轮还在跑(非终态),调用方应复用而不是再起一遍 ——
-     *              否则同一批次会有两个线程各自发一次 doClean。
+     * <p>
+     * 表示上一轮还在跑(非终态),调用方应复用而不是再起一遍 ——
+     * 否则同一批次会有两个线程各自发一次 doClean。
      */
      */
     private BatchRef upsertBatch(Long caseId, Long batchId, int fileCount, int sheetTotal, int matched) {
     private BatchRef upsertBatch(Long caseId, Long batchId, int fileCount, int sheetTotal, int matched) {
         AiCleanBatch exist = batchMapper.selectOne(batchKey(caseId, batchId));
         AiCleanBatch exist = batchMapper.selectOne(batchKey(caseId, batchId));
@@ -545,7 +559,9 @@ public class AiSmartCleanService {
         }
         }
     }
     }
 
 
-    /** 批次行 + 是否该由本次调用启动后台流程 */
+    /**
+     * 批次行 + 是否该由本次调用启动后台流程
+     */
     private record BatchRef(AiCleanBatch batch, boolean fresh) {
     private record BatchRef(AiCleanBatch batch, boolean fresh) {
     }
     }
 
 
@@ -630,7 +646,9 @@ public class AiSmartCleanService {
         private final AtomicInteger aiLoad = new AtomicInteger();
         private final AtomicInteger aiLoad = new AtomicInteger();
         private final AtomicInteger needReview = new AtomicInteger();
         private final AtomicInteger needReview = new AtomicInteger();
         private final AtomicInteger failed = new AtomicInteger();
         private final AtomicInteger failed = new AtomicInteger();
-        /** 本轮已消耗的模型 token(判定回写),供批次预算护栏比对 */
+        /**
+         * 本轮已消耗的模型 token(判定回写),供批次预算护栏比对
+         */
         private final AtomicLong tokens = new AtomicLong();
         private final AtomicLong tokens = new AtomicLong();
     }
     }
 
 
@@ -643,7 +661,9 @@ public class AiSmartCleanService {
         executor.shutdownNow();
         executor.shutdownNow();
     }
     }
 
 
-    /** 一个待判定的 AI 表块 */
+    /**
+     * 一个待判定的 AI 表块
+     */
     private record PendingAi(FileInfo root, FileInfo sheet, AiCleanJob job) {
     private record PendingAi(FileInfo root, FileInfo sheet, AiCleanJob job) {
     }
     }
 
 
@@ -655,12 +675,16 @@ public class AiSmartCleanService {
                                  String reason) {
                                  String reason) {
     }
     }
 
 
-    /** 受理响应 */
+    /**
+     * 受理响应
+     */
     public record SmartCleanVO(Long batchId, String stage, int fileCount, int sheetTotal,
     public record SmartCleanVO(Long batchId, String stage, int fileCount, int sheetTotal,
                                int matchedCount, int aiSheetCount) {
                                int matchedCount, int aiSheetCount) {
     }
     }
 
 
-    /** 轮询响应 */
+    /**
+     * 轮询响应
+     */
     public record SmartCleanStatusVO(String stage, int fileCount, int sheetTotal, int matchedCount,
     public record SmartCleanStatusVO(String stage, int fileCount, int sheetTotal, int matchedCount,
                                      int aiJudgedCount, int existingHitCount, int aiLoadCount,
                                      int aiJudgedCount, int existingHitCount, int aiLoadCount,
                                      int needReviewCount, int failedCount, List<NeedReviewItem> needReview) {
                                      int needReviewCount, int failedCount, List<NeedReviewItem> needReview) {