|
|
@@ -2,7 +2,7 @@
|
|
|
结果汇总与规范覆盖分析组件
|
|
|
"""
|
|
|
import json
|
|
|
-from typing import Dict, List, Any, Set
|
|
|
+from typing import Dict, List, Any, Set, Optional
|
|
|
import ast
|
|
|
import sys
|
|
|
from pathlib import Path
|
|
|
@@ -12,20 +12,24 @@ _root = Path(__file__).parent.parent
|
|
|
if str(_root) not in sys.path:
|
|
|
sys.path.insert(0, str(_root))
|
|
|
|
|
|
-from interfaces import IResultAnalyzer
|
|
|
+from interfaces import IResultAnalyzer, IKeywordChecker
|
|
|
from utils.file_utils import read_csv, write_csv
|
|
|
from foundation.observability.logger.loggering import server_logger as logger
|
|
|
+
|
|
|
+
|
|
|
class ResultAnalyzer(IResultAnalyzer):
|
|
|
"""审查结果汇总分析器"""
|
|
|
|
|
|
- def __init__(self, spec_csv_path: str):
|
|
|
+ def __init__(self, spec_csv_path: str, keyword_checker: Optional[IKeywordChecker] = None):
|
|
|
"""
|
|
|
Args:
|
|
|
spec_csv_path: 规范 CSV 文件路径(Construction_Plan_Content_Specification.csv)
|
|
|
+ keyword_checker: 关键词检查器(可选)
|
|
|
"""
|
|
|
self.spec_csv_path = spec_csv_path
|
|
|
+ self.keyword_checker = keyword_checker
|
|
|
|
|
|
- def process_results(self, results: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
|
|
|
+ def process_results(self, results: List[Dict[str, Any]], specification: Optional[Dict[str, List[Dict[str, str]]]] = None) -> List[Dict[str, Any]]:
|
|
|
"""
|
|
|
按规则清洗审查结果,生成新的 JSON 列表
|
|
|
|
|
|
@@ -34,6 +38,7 @@ class ResultAnalyzer(IResultAnalyzer):
|
|
|
则遍历 review_result 的键名(即二级目录名称):
|
|
|
* 若键名未出现在 section_label 的字符串中,则将该键对应的值列表清空 []
|
|
|
- 所有要点编号列表在块内部去重
|
|
|
+ - 如果启用了关键词检查器,则对缺失的要点进行二次验证
|
|
|
"""
|
|
|
processed: List[Dict[str, Any]] = []
|
|
|
|
|
|
@@ -72,13 +77,19 @@ class ResultAnalyzer(IResultAnalyzer):
|
|
|
else:
|
|
|
new_review_result[key] = points
|
|
|
|
|
|
+ # 关键词二次检查(只过滤,不改变数据结构)
|
|
|
+ if self.keyword_checker and specification:
|
|
|
+ new_review_result = self.keyword_checker.filter_missing_points(
|
|
|
+ new_review_result, content, specification, chapter_classification
|
|
|
+ )
|
|
|
+
|
|
|
processed.append(
|
|
|
{
|
|
|
"chunk_id": chunk_id,
|
|
|
"section_label": section_label,
|
|
|
"chapter_classification": chapter_classification,
|
|
|
"review_result": new_review_result,
|
|
|
- "content": content,
|
|
|
+ "content": content
|
|
|
}
|
|
|
)
|
|
|
|
|
|
@@ -96,7 +107,7 @@ class ResultAnalyzer(IResultAnalyzer):
|
|
|
* 要点来源: 形如 ["第五章 施工安全保证措施->一) 组织保证措施", ...]
|
|
|
- 对于每个规范行(标签 + 二级目录):
|
|
|
* 从所有块中收集该标签 & 二级目录下出现的要点编号(不重复)
|
|
|
- * 根据“内容要点数量”推算缺失的要点编号
|
|
|
+ * 根据"内容要点数量"推算缺失的要点编号
|
|
|
* 将出现过要点的块的 section_label 作为来源去重记录
|
|
|
"""
|
|
|
# 读取规范原始表(制表符分隔)
|
|
|
@@ -197,7 +208,7 @@ class ResultAnalyzer(IResultAnalyzer):
|
|
|
content = chapter_content_map.get(tag, "")
|
|
|
if not section_label:
|
|
|
section_label = chapter_section_label_map.get(tag, "")
|
|
|
-
|
|
|
+
|
|
|
# 组装输出行(在原规范行基础上增加三列)
|
|
|
new_row = dict(row)
|
|
|
new_row["审查到的要点"] = str(found_points)
|
|
|
@@ -244,9 +255,9 @@ class ResultAnalyzer(IResultAnalyzer):
|
|
|
level2 = (row.get("二级目录") or "").strip()
|
|
|
requirement = (row.get("内容要求") or "").strip()
|
|
|
reference_source = '《桥梁公司危险性较大工程管理实施细则(2025版)》'
|
|
|
- reason= f"参照:{reference_source} 中的内容要求,{row.get('section_label', '')}内容属于,专项施工方案内容要求中的 【{suorces_eum[row.get("标签", "")]}】 板块,应包含{requirement}"
|
|
|
+ reason= f"参照:{reference_source} 中的内容要求,{row.get('section_label', '')}内容属于,专项施工方案内容要求中的 【{suorces_eum[row.get('标签', '')]}】 板块,应包含{requirement}"
|
|
|
review_references = (row.get("依据") or "").strip()
|
|
|
-
|
|
|
+
|
|
|
missing_points_raw = row.get("缺失的要点", "")
|
|
|
missing_points = self._parse_list_field(missing_points_raw)
|
|
|
if not missing_points:
|
|
|
@@ -259,7 +270,7 @@ class ResultAnalyzer(IResultAnalyzer):
|
|
|
requirement_list = requirement.split(':')[-1].split(';')
|
|
|
requirement_text = ';'.join([requirement_list[i-1] for i in missing_points])
|
|
|
issue_point = (
|
|
|
- f"{row.get('section_label', '')}下缺失{suorces_eum[row.get("标签", "")]}中的【{level2}】内容"
|
|
|
+ f"{row.get('section_label', '')}下缺失{suorces_eum[row.get('标签', '')]}中的【{level2}】内容"
|
|
|
)
|
|
|
suggestion = f"建议补充:{requirement_text}" if requirement else "补充缺失要点内容"
|
|
|
risk_level = self._map_risk_level(len(missing_points))
|
|
|
@@ -316,5 +327,3 @@ class ResultAnalyzer(IResultAnalyzer):
|
|
|
if missing_count == 2:
|
|
|
return "中风险"
|
|
|
return "低风险"
|
|
|
-
|
|
|
-
|