Răsfoiți Sursa

fix(sgsc-时效性审查模型-xth): 修复纯数字导致的误判bug - 新增判断返回json

suhua31 1 săptămână în urmă
părinte
comite
27dde599c3

+ 44 - 2
core/construction_review/component/reviewers/standard_timeliness_reviewer.py

@@ -26,6 +26,10 @@
         results = reviewer.review_standards(standards_list)
 """
 import asyncio
+import json
+import os
+import threading
+from datetime import datetime
 from typing import List, Dict, Any, Optional
 from dataclasses import dataclass, asdict
 
@@ -67,13 +71,14 @@ class StandardTimelinessReviewer:
     对标准列表进行时效性审查。
     """
 
-    def __init__(self, db_pool=None, standard_service: Optional[StandardMatchingService] = None):
+    def __init__(self, db_pool=None, standard_service: Optional[StandardMatchingService] = None, callback_task_id: Optional[str] = None):
         """
         初始化审查器
 
         Args:
             db_pool: 数据库连接池,用于初始化 StandardMatchingService(如未提供standard_service则必填)
             standard_service: 已初始化的 StandardMatchingService 实例(优先级高于 db_pool)
+            callback_task_id: 回调任务ID,用于持久化判定结果
 
         Raises:
             RuntimeError: 当db_pool和standard_service都为None时抛出异常
@@ -86,6 +91,8 @@ class StandardTimelinessReviewer:
         self.db_pool = db_pool
         self._service = standard_service
         self._own_service = False  # 标记是否由本实例创建 service
+        self.callback_task_id = callback_task_id
+        self._log_lock = threading.Lock()
 
     async def __aenter__(self):
         """异步上下文管理器入口"""
@@ -102,6 +109,38 @@ class StandardTimelinessReviewer:
             await self._service.close()
         return False
 
+    def _log_determination_results(self, review_results: List["TimelinessReviewResult"]) -> None:
+        """将时效性判定结果持久化到JSON文件,不影响主逻辑"""
+        if not self.callback_task_id:
+            return
+        try:
+            with self._log_lock:
+                log_dir = os.path.join("temp", "construction_review", "timeliness_result")
+                os.makedirs(log_dir, exist_ok=True)
+                log_path = os.path.join(log_dir, f"{self.callback_task_id}.json")
+
+                records = []
+                if os.path.exists(log_path):
+                    try:
+                        with open(log_path, "r", encoding="utf-8") as f:
+                            records = json.load(f)
+                            if not isinstance(records, list):
+                                records = []
+                    except Exception:
+                        records = []
+
+                for result in review_results:
+                    records.append({
+                        "timestamp": datetime.now().isoformat(),
+                        "callback_task_id": self.callback_task_id,
+                        **result.to_dict()
+                    })
+
+                with open(log_path, "w", encoding="utf-8") as f:
+                    json.dump(records, f, ensure_ascii=False, indent=2)
+        except Exception as e:
+            logger.warning(f"记录时效性判定结果失败: {e}")
+
     def review_standards(self, standards: List[Dict[str, str]]) -> List[TimelinessReviewResult]:
         """
         审查标准列表的时效性
@@ -128,6 +167,7 @@ class StandardTimelinessReviewer:
                 review_result = self._convert_match_to_review_result(match_result)
                 review_results.append(review_result)
 
+        self._log_determination_results(review_results)
         return review_results
 
     def review_single(self, standard_name: str, standard_number: str, seq_no: int = 1) -> Optional[TimelinessReviewResult]:
@@ -150,7 +190,9 @@ class StandardTimelinessReviewer:
         # 如果 match 返回 None(文件名为空),则返回 None
         if match_result is None:
             return None
-        return self._convert_match_to_review_result(match_result)
+        review_result = self._convert_match_to_review_result(match_result)
+        self._log_determination_results([review_result])
+        return review_result
 
     def _convert_match_to_review_result(self, match_result: StandardMatchResult) -> TimelinessReviewResult:
         """

+ 4 - 0
core/construction_review/component/reviewers/timeliness_basis_reviewer.py

@@ -388,6 +388,10 @@ class BasisReviewService:
 
         start_time = time.time()
         total_batches = (len(items) + 2) // 3  # 计算总批次数
+
+        # 绑定 callback_task_id 到时效性审查器,用于记录判定结果
+        if self._timeliness_reviewer and callback_task_id:
+            self._timeliness_reviewer.callback_task_id = callback_task_id
         
         # 发送开始审查的SSE推送(使用独立命名空间,避免与主流程进度冲突)
         if progress_manager and callback_task_id:

+ 3 - 0
core/construction_review/component/reviewers/timeliness_content_reviewer.py

@@ -276,6 +276,9 @@ class ContentTimelinessReviewer:
 
         try:
             async with self._semaphore:
+                # 绑定 callback_task_id,用于记录判定结果
+                if callback_task_id:
+                    self._timeliness_reviewer.callback_task_id = callback_task_id
                 # 执行规则匹配审查
                 review_results = self._timeliness_reviewer.review_standards(standards_list)
 

+ 1 - 1
core/construction_review/component/standard_matching/standard_dao.py

@@ -12,7 +12,7 @@ class StandardDAO:
 
     def __init__(self, db_pool):
         self.db_pool = db_pool
-        self.table_name = "t_samp_standard_base_info"
+        self.table_name = "t_samp_standard_base_info_status"
 
     async def load_all_standards(self) -> List[Dict]:
         """

+ 7 - 2
core/construction_review/component/standard_matching/standard_service.py

@@ -369,8 +369,13 @@ class StandardMatcher:
         exact_match = self._find_exact_name_match(name_matches, result.normalized_name)
 
         if exact_match:
-            # 找到名称匹配的记录
-            return self._handle_fuzzy_name_match(result, exact_match)
+            # 找到名称匹配的记录,检查标准号是否一致
+            if result.normalized_number == exact_match.normalized_number:
+                # 标准号实质一致,按完全匹配处理
+                return self._handle_full_match(result, exact_match)
+            else:
+                # 名称匹配但标准号不一致 = 标准号错误
+                return self._set_mismatch_result(result, exact_match)
 
         # 名称完全不匹配,但标准号已匹配成功
         # 说明该标准存在于库中,应返回不匹配而非不存在