#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
@Project   : lq-agent-api
@File      : construction_review/ai_review_engine.py
@IDE       : VsCode
@Author    : 王旭明
@Date      : 2025-12-01 11:07:12
@Description: AI审查引擎核心组件，负责执行各类文档审查任务，支持并发处理和多种审查模式

=================================
📋 方法总览 (Method Overview)
=================================

🏗️ 核心审查流程:
├── basic_compliance_check()      # 基础合规性检查 (语法/语义/完整性)
├── technical_compliance_check()  # 技术性合规检查 (标准/设计/参数)
├── rag_enhanced_check()          # RAG增强审查 (向量/混合检索)
└── _calculate_overall_risk()     # 计算总体风险等级

🔍 专项检查方法:
├── check_grammar()               # 词句语法检查
├── check_semantic_logic()        # 语义逻辑检查
├── check_completeness()          # 完整性检查
├── check_mandatory_standards()   # 强制性标准检查
├── check_design_values()         # 设计值检查
├── check_technical_parameters()  # 技术参数检查
└── prep_basis_review()           # 编制依据审查

🔍 RAG检索增强:
├── vector_search()               # 向量检索
├── hybrid_search()               # 混合检索
├── rerank_results()              # 重排序结果
└── generate_enhanced_suggestions() # 生成增强建议

🛠️ 工具辅助方法:
├── _process_review_result()      # 处理审查结果
├── _execute_check_with_semaphore() # 信号量并发控制
├── _calculate_basic_score()      # 计算基础得分
├── _calculate_technical_score()  # 计算技术得分
└── _aggregate_results()          # 汇总审查结果

⚙️ 配置管理:
├── __init__()                    # 初始化引擎 (max_concurrent_reviews=8)
└── set_review_location_label()   # 设置审查位置标签
"""

import asyncio
import concurrent.futures
import json
import os
import time
from dataclasses import dataclass
from enum import Enum
from typing import Any, Dict, List, Optional, Sequence
import pandas as pd
import json
import ast  # 用于安全解析字符串为Python对象
import pandas as pd

from core.base.task_models import TaskFileInfo
from core.construction_review.component.infrastructure.milvus import MilvusConfig, MilvusManager
from core.construction_review.component.infrastructure.parent_tool import (
    enhance_with_parent_docs_grouped,
    extract_query_pairs_results
)
from core.construction_review.component.infrastructure.relevance import is_relevant_async
from core.construction_review.component.reviewers.base_reviewer import BaseReviewer
from core.construction_review.component.reviewers.utils.text_split import split_text
from foundation.ai.rag.retrieval.entities_enhance import entity_enhance
from foundation.ai.rag.retrieval.query_rewrite import query_rewrite_manager
from foundation.infrastructure.config.config import config_handler
from foundation.observability.logger.loggering import review_logger as logger
from foundation.observability.cachefiles import cache, CacheBaseDir
from core.construction_review.component.reviewers.utils.directory_extraction import BasisItems

from pathlib import Path
import sys
import json




from core.construction_review.component.reviewers.base_reviewer import ReviewResult
from .reviewers.utils.redis_csv_utils import (
    get_redis_connection,
)

@dataclass
class ReviewResult:
    """审查结果"""
    unit_index: int
    unit_content: Dict[str, Any]
    basic_compliance: Dict[str, Any]
    technical_compliance: Dict[str, Any]
    rag_enhanced: Dict[str, Any]
    overall_risk: str

class Stage(Enum):
    """工作流状态"""
    BASIC = {
        'reviewer_type':'basic',
        'grammar': 'sensitive_word_check',
        'sensitive':'sensitive_check',
        'semantic': 'semantic_logic_check',
        'completeness': 'completeness_check',
        'timeliness': 'timeliness_check',
        'reference': 'reference_check'
    }
    TECHNICAL = {
        'reviewer_type':'technical',
        'non_parameter': 'non_parameter_compliance_check',
        'parameter': 'parameter_compliance_check'
    }
    RAG = {
        'rag': 'rag_enhanced_review',
    }
    AI = {
        'reviewer_type':'ai',
        'professional': 'professional_suggestion',
        'standardization': 'standardization_suggestion',
        'completeness': 'completeness_suggestion',
        'readability': 'readability_suggestion'
    }


class AIReviewEngine(BaseReviewer):
    """AI审查引擎 - 支持审查条目并发"""

    def __init__(self, task_file_info: TaskFileInfo = None, max_concurrent_reviews: int = 8, db_pool=None):
        """
        初始化AI审查引擎

        Args:
            task_file_info: TaskFileInfo 实例，包含任务相关信息
            max_concurrent_reviews: 最大并发审查数量
            db_pool: 数据库连接池（用于时效性审查等新逻辑）
        """
        super().__init__()

        # ✅ 保存 TaskFileInfo 实例
        self.task_info = task_file_info

        self.file_id = task_file_info.file_id
        self.callback_task_id = task_file_info.callback_task_id
        self.user_id = task_file_info.user_id
        self.review_config = task_file_info.review_config
        self.project_plan_type = task_file_info.project_plan_type
        self.tendency_review_role = task_file_info.tendency_review_role

        self.max_concurrent_reviews = max_concurrent_reviews
        self.semaphore = asyncio.Semaphore(max_concurrent_reviews)
        self.milvus_collection = config_handler.get('milvus', 'MILVUS_COLLECTION', 'default')

        # [新增] 数据库连接池
        self.db_pool = db_pool

        self.milvus = MilvusManager(MilvusConfig())
        self.redis_client = get_redis_connection()   # 获取Redis连接

    def _process_review_result(self, result):
        """
        处理审查结果，统一转换为字典格式

        Args:
            result: 原始审查结果

        Returns:
            Dict: 处理后的审查结果字典
        """
        if isinstance(result, Exception):
            return {"error": str(result), "success": False}
        elif hasattr(result, '__dict__'):  # ReviewResult对象
            return {
                "success": result.success if hasattr(result, 'success') else False,
                "details": result.details if hasattr(result, 'details') else {},
                "error_message": result.error_message if hasattr(result, 'error_message') else None,
                "execution_time": result.execution_time if hasattr(result, 'execution_time') else None
            }
        else:
            return result  # 已经是字典

    def _execute_check_with_semaphore(self, check_func, *args, **kwargs):
        """
        使用信号量执行检查任务的包装器

        Args:
            check_func: 检查函数
            *args: 位置参数
            **kwargs: 关键字参数

        Returns:
            包装后的异步函数
        """
        async def wrapped_check():
            async with self.semaphore:
                return await check_func(*args, **kwargs)
        return wrapped_check()

    def rag_enhanced_check(self, unit_content: Dict[str, Any]) -> Dict[str, Any]:
        """
        RAG增强审查

        流程:
        1. 提取查询对
        2. 实体增强检索
        3. 自动拼接父文档内容

        Args:
            unit_content: 待审查单元内容

        Returns:
            Dict[str, Any]: RAG增强审查结果
        """
        logger.info(f"[RAG增强] 开始处理, 内容长度: {len(unit_content)}")

        # Step 2: 构建查询对
        query_pairs = query_rewrite_manager.query_extract(unit_content)

        # 检查 query_pairs 是否为 None（模型调用失败时的防护）
        if query_pairs is None:
            logger.warning("[RAG增强] Query提取失败，返回空结果")
            return {
                'vector_search': [],
                'retrieval_status': 'query_extract_failed',
                'file_name': '',
                'text_content': '',
                'metadata': {},
                'entity_results': [],        # 保持结构一致
                'total_entities': 0          # 保持结构一致
            }

        logger.info(f"[RAG增强] 提取到 {len(query_pairs)} 个查询对")

        # Step 3: 根据查询对主实体、辅助实体，进行实体增强召回
        bfp_result_lists = entity_enhance.entities_enhance_retrieval(query_pairs)

        # Step 4: 检查检索结果
        if not bfp_result_lists:
            logger.warning("[RAG增强] 实体检索未返回结果")
            return {
                'vector_search': [],
                'retrieval_status': 'no_results',
                'file_name': '',
                'text_content': '',
                'metadata': {}
            }

        # Step 5: 父文档增强（使用分组增强策略）
        try:
            enhancement_result = enhance_with_parent_docs_grouped(
                self.milvus,
                bfp_result_lists,
                score_threshold=0.5,  # bfp_rerank_score 阈值
                max_parents_per_pair=3,  # 每个查询对最多3个父文档
                max_parent_text_length=8000  # 单个父文档最大8000字符（约5300 tokens）
            )
            enhanced_results = enhancement_result['enhanced_results']
            enhanced_count = enhancement_result['enhanced_count']
            enhanced_pairs = enhancement_result.get('enhanced_pairs', 0)
            total_pairs = enhancement_result.get('total_pairs', 0)

            logger.info(f"[RAG增强] 分组增强完成: {enhanced_pairs}/{total_pairs} 个查询对进行了增强")
            logger.info(f"[RAG增强] 成功增强 {enhanced_count} 个结果，使用了 {len(enhancement_result['parent_docs'])} 个父文档")
        except Exception as e:
            logger.error(f"[RAG增强] 父文档增强失败: {e}", exc_info=True)
            # 失败时使用原始结果
            enhanced_results = bfp_result_lists

        # Step 5: 提取查询对结果（只保留得分>0.5的结果）
        entity_results = extract_query_pairs_results(enhanced_results, query_pairs, score_threshold=0.5)

        # 保存最终结果用于调试
        # with open(rf"temp\construction_review/ai_review_engine\extract_query_pairs_results.json", "w", encoding='utf-8') as f:
        #     json.dump(entity_results, f, ensure_ascii=False, indent=4)

        # 如果没有结果通过阈值过滤，返回空结果
        if not entity_results:
            logger.warning("[RAG增强] 没有结果通过阈值过滤（得分>0.5），返回空结果")
            return {
                'vector_search': [],
                'retrieval_status': 'no_results',
                'file_name': '',
                'text_content': '',
                'metadata': {},
                'entity_results': [],
                'total_entities': 0
            }

        # 返回格式：返回列表形式的 entity_results
        return {
            'retrieval_status': 'success',
            'entity_results': entity_results,
            'total_entities': len(entity_results)
        }

    async def basic_compliance_check(self,trace_id_idx: str, unit_content: Dict[str, Any],state:Dict[str, Any],stage_name:str) -> Dict[str, Any]:
        """
        基础合规性检查

        Args:
            trace_id_idx: 追踪ID索引
            unit_content: 待审查单元内容
            state: 状态字典
            stage_name: 阶段名称
            current_progress: 当前进度

        Returns:
            Dict[str, Any]: 基础合规性检查结果
        """
        review_content = unit_content['content']
        #review_references = unit_content.get('review_references')

        logger.info(f"basic开始基础合规性检查, 内容长度: {len(review_content)}")

        async def check_with_semaphore(check_func, **kwargs):
            async with self.semaphore:
                return await check_func(**kwargs)

        TASK_TIMEOUT = 55

        basic_tasks = []

        if 'sensitive_word_check'  in self.task_info.get_review_config_list():
            basic_tasks.append(
                asyncio.create_task(
                    asyncio.wait_for(
                        check_with_semaphore(self.sensitive_word_check, trace_id_idx=trace_id_idx, review_content=review_content, state=state, stage_name=stage_name),
                        timeout=TASK_TIMEOUT
                    )
                )
            )
        if 'semantic_logic_check' in self.task_info.get_review_config_list():
            basic_tasks.append(
                asyncio.create_task(
                    asyncio.wait_for(
                        check_with_semaphore(self.check_semantic_logic, trace_id_idx=trace_id_idx, review_content=review_content, state=state, stage_name=stage_name),
                        timeout=TASK_TIMEOUT
                    )
                )
            )
        if 'sensitive_check' in self.task_info.get_review_config_list():
            basic_tasks.append(
                asyncio.create_task(
                    asyncio.wait_for(
                        check_with_semaphore(self.check_sensitive, trace_id_idx=trace_id_idx, review_content=review_content, state=state, stage_name=stage_name),
                        timeout=TASK_TIMEOUT
                    )
                )
            )
        if 'completeness_check' in self.task_info.get_review_config_list():
            basic_tasks.append(
                asyncio.create_task(
                    asyncio.wait_for(
                        check_with_semaphore(self.check_completeness, trace_id_idx=trace_id_idx, review_content=unit_content, state=state, stage_name=stage_name),
                        timeout=TASK_TIMEOUT
                    )
                )
            )

        # 一次性执行所有任务，避免重复协程调用
        if not basic_tasks:
            return {
                "sensitive_word_check": self._process_review_result(None),
                "semantic_logic_check": self._process_review_result(None),
                "sensitive_check": self._process_review_result(None),
            }

        # 使用 asyncio.wait 替代 gather，提供更好的超时控制
        # 整体超时时间 = 单个任务超时 + 缓冲时间
        total_timeout = TASK_TIMEOUT * len(basic_tasks) + 10

        done, pending = await asyncio.wait(basic_tasks, timeout=total_timeout)

        # 取消未完成的任务
        for task in pending:
            task.cancel()
            logger.warning(f"[基础审查] 任务超时，已取消")

        # 收集结果
        results = []
        for task in done:
            try:
                result = task.result()
                results.append(result)
            except Exception as e:
                logger.error(f"[基础审查] 任务执行失败: {str(e)}", exc_info=True)
                logger.error(f"[基础审查] 异常类型: {type(e).__name__}")
                logger.error(f"[基础审查] 异常详情: {repr(e)}")
                results.append(e)

        # 根据配置项分配结果
        grammar_result = self._process_review_result(None)
        semantic_result = self._process_review_result(None)
        sensitive_result = self._process_review_result(None)
        #completeness_result = self._process_review_result(None)
        #logger.info(f"completeness_result: {completeness_result}")
        result_index = 0

        if 'sensitive_word_check' in self.task_info.get_review_config_list():
            if result_index < len(results):
                grammar_result = self._process_review_result(results[result_index])
            result_index += 1
            cache.ai_review_engine(grammar_result, base_cache_dir=CacheBaseDir.CONSTRUCTION_REVIEW)
        if 'semantic_logic_check' in self.task_info.get_review_config_list():
            if result_index < len(results):
                semantic_result = self._process_review_result(results[result_index])
            result_index += 1

        if 'sensitive_check' in self.task_info.get_review_config_list():
            if result_index < len(results):
                sensitive_result = self._process_review_result(results[result_index])
            result_index += 1
        return {
            'sensitive_word_check': grammar_result,
            'semantic_logic_check': semantic_result,
            'sensitive_check': sensitive_result,
            #'completeness_check': completeness_result,
        }

    async def technical_compliance_check(self,trace_id_idx: str, unit_content: Dict[str, Any],
                                      state:Dict[str, Any],stage_name:str) -> Dict[str, Any]:
        """
        技术性合规检查（包含RAG增强审查）

        支持基于 entity_results 列表的动态审查任务创建：
        - entity_results 列表中每个查询对都会创建独立的审查任务
        - 支持参数性和非参数性审查的动态任务创建

        Args:
            trace_id_idx: 追踪ID索引
            unit_content: 待审查单元内容
            state: 状态字典
            stage_name: 阶段名称

        Returns:
            Dict[str, Any]: 技术性合规检查结果
        """
        review_content = unit_content['content']
        logger.info(f"开始技术性合规检查，内容长度: {len(review_content)}")

        # 先执行RAG增强检索，获取相关标准文档作为参考
        logger.info(f"检查审查项列表：{self.task_info.get_review_config_list():}")
        entity_results = []  # 初始化 entity_results 列表

        if 'non_parameter_compliance_check' in self.task_info.get_review_config_list() or 'parameter_compliance_check' in self.task_info.get_review_config_list():
            logger.info("执行专业性审查，开始RAG增强检索")
            rag_result = self.rag_enhanced_check(review_content)
            entity_results = rag_result.get('entity_results', [])
            logger.info(f"[RAG增强] 获取到 {len(entity_results)} 个查询对结果")

            # 如果有 entity_results，记录详细信息
            if entity_results:
                for idx, entity_item in enumerate(entity_results):
                    logger.info(f"[RAG增强] 查询对 {idx}: entity={entity_item.get('entity')}, combined_query={entity_item.get('combined_query')[:50]}...")

        async def check_with_semaphore(check_func, **kwargs):
            async with self.semaphore:
                return await check_func(**kwargs)

        # 根据配置动态创建技术性检查任务
        technical_tasks = []
        task_mapping = []

        TASK_TIMEOUT = 150

        # 判断是否需要基于 entity_results 创建动态任务
        if entity_results and len(entity_results) > 0:
            logger.info(f"[技术审查] 基于 entity_results 创建动态审查任务，共 {len(entity_results)} 个查询对")

            # 为每个查询对创建独立的审查任务
            for idx, entity_item in enumerate(entity_results):
                combined_query = entity_item.get('combined_query', '')
                entity = entity_item.get('entity', f'entity_{idx}')
                text_content = entity_item.get('text_content', '')
                file_name = entity_item.get('file_name', '')

                logger.info(f"[技术审查] 为查询对 {idx} ({entity}) 创建审查任务")

                # 根据配置创建参数性或非参数性审查任务
                if 'parameter_compliance_check' in self.task_info.get_review_config_list():
                    # 参数性合规检查
                    task_mapping.append(f'parameter_compliance_{idx}')
                    technical_tasks.append(
                        asyncio.create_task(
                            asyncio.wait_for(
                                check_with_semaphore(
                                    self.check_parameter_compliance,
                                    trace_id_idx=trace_id_idx,
                                    review_content=review_content,
                                    review_references=text_content,  # 使用查询对的检索结果作为参考
                                    reference_source=file_name,
                                    state=state,
                                    stage_name=stage_name,
                                    entity_query=combined_query  # 传入组合查询条文
                                ),
                                timeout=TASK_TIMEOUT
                            )
                        )
                    )

                if 'non_parameter_compliance_check' in self.task_info.get_review_config_list():
                    # 非参数性合规检查
                    task_mapping.append(f'non_parameter_compliance_{idx}')
                    technical_tasks.append(
                        asyncio.create_task(
                            asyncio.wait_for(
                                check_with_semaphore(
                                    self.check_non_parameter_compliance,
                                    trace_id_idx=trace_id_idx,
                                    review_content=review_content,
                                    review_references=text_content,  # 使用查询对的检索结果作为参考
                                    reference_source=file_name,
                                    state=state,
                                    stage_name=stage_name,
                                    entity_query=combined_query  # 传入组合查询条文
                                ),
                                timeout=TASK_TIMEOUT
                            )
                        )
                    )

            logger.info(f"[技术审查] 总共创建了 {len(technical_tasks)} 个动态审查任务")

        else:
            # 没有entity_results，直接返回None
            logger.warning("[技术审查] 未提取到实体，跳过技术性审查")
            return None

        # 一次性执行所有任务，避免重复协程调用

        # 使用 asyncio.wait 替代 gather，提供更好的超时控制
        # 整体超时时间 = 单个任务超时 × 任务数量 + 缓冲时间
        total_timeout = TASK_TIMEOUT * len(technical_tasks) + 10

        done, pending = await asyncio.wait(technical_tasks, timeout=total_timeout)

        # 取消未完成的任务
        for task in pending:
            task.cancel()
            logger.warning(f"[技术审查] 任务超时，已取消")

        # 收集结果
        results = []
        for task in done:
            try:
                result = task.result()
                results.append(result)
            except Exception as e:
                logger.error(f"[技术审查] 任务执行失败: {str(e)}", exc_info=True)
                logger.error(f"[技术审查] 异常类型: {type(e).__name__}")
                logger.error(f"[技术审查] 异常详情: {repr(e)}")
                results.append(e)

        # 扁平化处理结果：直接返回每个实体的审查结果
        logger.info(f"[技术审查] 处理审查结果，共 {len(entity_results)} 个实体")

        flattened_results = {}
        result_index = 0

        for idx, entity_item in enumerate(entity_results):
            entity = entity_item.get('entity', f'entity_{idx}')

            # 提取非参数性审查结果（如果配置了）
            if 'non_parameter_compliance_check' in self.task_info.get_review_config_list():
                key = f'non_parameter_compliance_{entity}_{idx}'
                if result_index < len(results):
                    flattened_results[key] = self._process_review_result(results[result_index])
                    logger.info(f"[技术审查] {key} 结果已处理")
                else:
                    logger.warning(f"[技术审查] {key} 缺少结果")
                result_index += 1

            # 提取参数性审查结果（如果配置了）
            if 'parameter_compliance_check' in self.task_info.get_review_config_list():
                key = f'parameter_compliance_{entity}_{idx}'
                if result_index < len(results):
                    flattened_results[key] = self._process_review_result(results[result_index])
                    logger.info(f"[技术审查] {key} 结果已处理")
                else:
                    logger.warning(f"[技术审查] {key} 缺少结果")
                result_index += 1

        logger.info(f"[技术审查] 成功处理 {len(flattened_results)} 个审查结果")
        return flattened_results

    async def sensitive_word_check(self, trace_id_idx: str, review_content: str,
                          state: str, stage_name: str) -> Dict[str, Any]:
        """
        词句语法检查

        Args:
            trace_id_idx: 追踪ID索引
            review_content: 审查内容
            state: 状态字典
            stage_name: 阶段名称

        Returns:
            ReviewResult: 语法检查结果
        """
        from core.construction_review.component.reviewers.sensitive_word_check import sensitive_word_check_reviewer
        
        # 构造trace_id
        prompt_name = Stage.BASIC.value['grammar']
        trace_id = prompt_name + trace_id_idx
        
        # 调用语法检查审查模块
        result = await sensitive_word_check_reviewer.check_grammar(
            trace_id=trace_id,
            review_content=review_content,
            state=state,
            stage_name=stage_name
        )
        
        return result

    async def check_semantic_logic(self, trace_id_idx: str, review_content: str,
                                 state: str, stage_name: str) -> Dict[str, Any]:
        """
        语义逻辑检查

        Args:
            trace_id_idx: 追踪ID索引
            review_content: 审查内容
            state: 状态字典
            stage_name: 阶段名称

        Returns:
            ReviewResult: 语义逻辑检查结果
        """
        from core.construction_review.component.reviewers.semantic_logic import semantic_logic_reviewer
        
        # 构造trace_id
        prompt_name = Stage.BASIC.value['semantic']
        trace_id = prompt_name + trace_id_idx
        
        # 调用语义逻辑审查模块
        result = await semantic_logic_reviewer.check_semantic_logic(
            trace_id=trace_id,
            review_content=review_content,
            state=state,
            stage_name=stage_name
        )
        
        return result
        
    async def check_completeness(
        self, trace_id_idx: str, review_content: List[Dict[str, Any]],
        state: str, stage_name: str
    ) -> Dict[str, Any]:
        """
        正文内容完整性审查 - 轻量级三级分类检查
        
        基于文档分类器输出的三级分类编码，直接判断哪些三级分类有内容覆盖，哪些缺失。
        无需LLM，通过集合运算快速计算完整性。
        
        Args:
            trace_id_idx: 追踪ID索引
            review_content: 审查内容，文档块（chunks）列表，每个chunk需包含三级分类编码
            state: 状态字典，可包含大纲信息
            stage_name: 阶段名称
            
        Returns:
            Dict[str, Any]: 完整性检查结果，包含缺失的三级分类详情
        """
        from .reviewers.completeness_reviewer import (
            LightweightCompletenessChecker,
            result_to_dict as result_to_dict_lightweight
        )
        
        start_time = time.time()
        name = "completeness_check_lightweight"
        
        try:
            logger.info(f"[{name}] 开始轻量级三级完整性审查")
            
            # 标准CSV路径（使用doc_worker下的标准分类表）
            csv_path = str(
                Path(__file__).parent / 'doc_worker' / 'config' / 
                'StandardCategoryTable.csv'
            )
            
            # 创建轻量级审查器（传入model_client用于LLM生成建议）
            # self.model_client 是从 BaseReviewer 继承的
            checker = LightweightCompletenessChecker(
                csv_path,
                model_client=getattr(self, 'model_client', None)
            )
            
            # 从state获取outline和原始chunks（如果有）
            outline = None
            all_chunks = []
            if state and isinstance(state, dict):
                structured = state.get('structured_content', {})
                outline = structured.get('outline')
                all_chunks = structured.get('chunks', [])

            # 从传入的chunks中提取chapter_code和章节信息
            chapter_code = "all"
            chapter_name = ""
            if review_content and isinstance(review_content, list):
                first_chunk = review_content[0]
                if isinstance(first_chunk, dict):
                    chapter_code = first_chunk.get('chapter_classification', 'all')
                    chapter_name = first_chunk.get('chapter', '') or first_chunk.get('section_label', '')
                    # 只保留章级标题（"->" 之前的部分），避免二级标题污染 location
                    if chapter_name and '->' in chapter_name:
                        chapter_name = chapter_name.split('->')[0]

            # 获取该章节的所有原始chunks用于完整性审查（包含所有分类代码）
            chapter_chunks = review_content
            if chapter_code != "all" and all_chunks:
                # 从state中获取该章节的所有原始chunks
                chapter_chunks = [
                    c for c in all_chunks
                    if c.get('chapter_classification') == chapter_code
                ]
                logger.info(f"[{name}] 章节 '{chapter_code}' 从state获取 {len(chapter_chunks)} 个原始chunks进行完整性审查")

            # 执行检查（传入当前章节分类，只检查该章节下的三级分类）
            result = await checker.check(
                chunks=chapter_chunks,
                outline=outline,
                chapter_classification=chapter_code if chapter_code != "all" else None
            )
            
            # 转换为字典
            result_dict = result_to_dict_lightweight(result)

            # ========== 新增：目录一二级缺失检查 ==========
            # 只在全文档检查或 catalogue 章节时执行，避免重复
            outline_issues = []
            if chapter_code in ["all", "catalogue"]:
                try:
                    outline_result = await self._check_outline_for_completeness(
                        state=state,
                        trace_id_idx=trace_id_idx
                    )
                    outline_issues = outline_result.get("issues", [])
                except Exception as e:
                    logger.warning(f"目录缺失检查失败: {str(e)}")
            # =============================================

            # 使用 recommendations 构建 response_items
            # recommendations 已按 一级→二级→三级 层级判断，用 continue 阻断级联：
            #   一级缺失 → 只报一级，不再向下检查
            #   二级缺失 → 只报二级，不再检查其下三级
            #   二级存在 → 才报三级缺失
            _level_risk = {
                "一级": ("高风险", "high"),
                "二级": ("中风险", "medium"),
                "三级": ("中风险", "medium"),
                "一致性": ("低风险", "low"),
            }
            response_items = []
            for rec in result_dict.get('recommendations', []):
                level = rec.get('level', '')
                if level == '通过':
                    continue
                risk_level, risk_level_en = _level_risk.get(level, ("中风险", "medium"))
                issue_point = rec.get('issue_point', '')
                location = rec.get('location', '')
                # 三级缺失：将 location 中的标准分类名替换为文档实际章节名，信息更直观
                if level == '三级' and chapter_name and ' > ' in location:
                    sec_part = location.split(' > ', 1)[1]
                    new_location = f"{chapter_name} > {sec_part}"
                    issue_point = issue_point.replace(location, new_location, 1)
                    location = new_location
                response_items.append({
                    "check_item": "completeness_check",
                    "chapter_code": chapter_code if chapter_code != "all" else "unknown",
                    "check_item_code": f"{chapter_code if chapter_code != 'all' else 'unknown'}_completeness_check",
                    "check_result": {
                        "issue_point": issue_point,
                        "location": location,
                        "suggestion": rec.get('suggestion', ''),
                        "reason": rec.get('reason', ''),
                        "risk_level": risk_level
                    },
                    "exist_issue": True,
                    "risk_info": {"risk_level": risk_level_en}
                })
            
            # 合并目录缺失检查的问题（目录缺失作为完整性的一部分）
            if outline_issues:
                response_items.extend(outline_issues)
            
            # 如果没有缺失项，显示完整度
            if not response_items:
                completeness_rate = result_dict.get('tertiary_completeness', {}).get('completeness_rate', '0%')
                response_items.append({
                    "check_item": "completeness_check",
                    "chapter_code": chapter_code if chapter_code != "all" else "all",
                    "check_item_code": f"{chapter_code if chapter_code != 'all' else 'all'}_completeness_check",
                    "check_result": {
                        "issue_point": f"【内容完整】三级分类覆盖完整",
                        "location": chapter_name or "全文档",
                        "suggestion": "",
                        "reason": "",
                        "risk_level": "低风险"
                    },
                    "exist_issue": False,
                    "risk_info": {"risk_level": "low"}
                })
            
            execution_time = time.time() - start_time
            
            # 构建与原有格式兼容的结果
            check_result = {
                "details": {
                    "name": "completeness_check",
                    "response": response_items,
                    "review_location_label": "三级完整性审查",
                    "chapter_code": chapter_code,
                    "original_content": f"标准三级分类: {result_dict.get('tertiary_completeness', {}).get('total', 0)}个, "
                                        f"有内容: {result_dict.get('tertiary_completeness', {}).get('present', 0)}个, "
                                        f"缺失: {result_dict.get('tertiary_completeness', {}).get('missing', 0)}个",
                    # 保留完整的轻量级审查结果供前端使用
                    "lightweight_result": result_dict
                },
                "success": True,
                "execution_time": execution_time
            }
            
            logger.info(f"[{name}] 审查完成，耗时: {execution_time:.2f}s, "
                       f"三级完整率: {result_dict.get('tertiary_completeness', {}).get('completeness_rate', 'N/A')}")
            
            return check_result, trace_id_idx
            
        except Exception as e:
            execution_time = time.time() - start_time
            error_msg = f"{name} 轻量级审查失败: {str(e)}"
            logger.error(error_msg, exc_info=True)
            
            # 从传入的chunks中提取chapter_code（错误处理中也要获取）
            chapter_code = "all"
            chapter_name = ""
            if review_content and isinstance(review_content, list):
                first_chunk = review_content[0]
                if isinstance(first_chunk, dict):
                    chapter_code = first_chunk.get('chapter_classification', 'all')
                    chapter_name = first_chunk.get('chapter', '') or first_chunk.get('section_label', '')
                    # 只保留章级标题（"->" 之前的部分），避免二级标题污染 location
                    if chapter_name and '->' in chapter_name:
                        chapter_name = chapter_name.split('->')[0]

            # 返回错误信息（与正常路径一致的格式）
            error_result = {
                "details": {
                    "name": "completeness_check",
                    "response": [{
                        "check_item": "completeness_check",
                        "chapter_code": chapter_code if chapter_code != "all" else "unknown",
                        "check_item_code": f"{chapter_code if chapter_code != 'all' else 'unknown'}_completeness_check",
                        "check_result": {
                            "issue_point": f"【审查异常】{error_msg}",
                            "location": chapter_name or chapter_code,
                            "suggestion": "请检查系统配置或联系管理员",
                            "reason": "",
                            "risk_level": "高风险"
                        },
                        "exist_issue": True,
                        "risk_info": {"risk_level": "high"}
                    }],
                    "review_location_label": "三级完整性审查",
                    "chapter_code": chapter_code,
                    "original_content": ""
                },
                "success": False,
                "execution_time": execution_time
            }
            return error_result, trace_id_idx

    async def _check_outline_for_completeness(
        self,
        state: Dict[str, Any],
        trace_id_idx: str
    ) -> Dict[str, Any]:
        """
        为完整性检查提供目录一二级缺失结果
        复用 check_outline_catalogue 方法，返回标准 issue 格式列表
        
        Args:
            state: AI审查状态，包含 structured_content
            trace_id_idx: 追踪ID索引
            
        Returns:
            Dict: {"issues": [...]} 标准格式的 issue 列表
        """
        try:
            # 调用现有目录缺失检查方法
            outline_data = state.get("structured_content", {})
            result = await self.check_outline_catalogue(
                trace_id_idx=trace_id_idx,
                outline_data=outline_data,
                state=state,
                stage_name="completeness_check"
            )
            
            if not result.get("success"):
                return {"issues": []}
            
            # 转换为 completeness_check 格式的 issues
            issues = []
            details = result.get("details", {})
            missing_first = details.get("missing_first", [])
            missing_second = details.get("missing_second", [])
            missing_first_count = len(missing_first)
            missing_second_count = len(missing_second)
            
            # 如果有缺失目录，先添加汇总统计 issue（放在最前面）
            if missing_first or missing_second:
                total_missing = missing_first_count + missing_second_count
                
                # 构建缺失目录名称列表
                missing_first_names = [item.get('first_name', '未知') for item in missing_first if isinstance(item, dict)]
                missing_second_names = [f"{item.get('first_name', '')}.{item.get('secondary_name', '未知')}" for item in missing_second if isinstance(item, dict)]
                
                # 构建建议文本
                suggestion_parts = []
                if missing_first_names:
                    suggestion_parts.append(f"一级目录（{missing_first_count}个）：{', '.join(missing_first_names)}")
                if missing_second_names:
                    suggestion_parts.append(f"二级目录（{missing_second_count}个）：{', '.join(missing_second_names[:10])}")  # 最多显示10个
                    if len(missing_second_names) > 10:
                        suggestion_parts.append(f"... 及其他 {len(missing_second_names) - 10} 个二级目录")
                
                suggestion_text = "建议补充以下缺失目录：\n" + "\n".join(suggestion_parts)
                
                # 添加汇总统计 issue
                issues.append({
                    "check_item": "completeness_check",
                    "chapter_code": "catalogue",  # 汇总 issue 归属到 catalogue 章节
                    "check_item_code": "catalogue_completeness_check",
                    "check_result": {
                        "issue_point": f"【目录缺失汇总】共缺失 {total_missing} 个目录（一级{missing_first_count}个，二级{missing_second_count}个）",
                        "location": "整篇文档",
                        "suggestion": suggestion_text,
                        "reason": f"根据标准分类表对比，文档目录结构不完整，共发现 {total_missing} 个缺失目录",
                        "risk_level": "中风险",
                        "summary": {
                            "missing_first_count": missing_first_count,
                            "missing_second_count": missing_second_count,
                            "missing_total": total_missing,
                            "missing_first_names": missing_first_names,
                            "missing_second_names": missing_second_names
                        }
                    },
                    "exist_issue": True,
                    "risk_info": {"risk_level": "medium"}
                })
            
            # 缺失一级目录 → 每个生成 issue（统一归属到 catalogue 章节）
            for item in missing_first:
                issues.append({
                    "check_item": "completeness_check",
                    "chapter_code": "catalogue",
                    "check_item_code": "catalogue_completeness_check",
                    "check_result": {
                        "issue_point": f"【目录缺失】缺失一级目录：{item.get('first_name', '')}",
                        "location": f"{item.get('first_seq', '')}. {item.get('first_name', '')}",
                        "suggestion": f"补充一级目录：{item.get('first_name', '')}",
                        "reason": "根据标准分类表，该一级目录应当出现",
                        "risk_level": "高风险"
                    },
                    "exist_issue": True,
                    "risk_info": {"risk_level": "high"}
                })
            
            # 缺失二级目录 → 统一归属到 catalogue 章节
            for item in missing_second:
                issues.append({
                    "check_item": "completeness_check",
                    "chapter_code": "catalogue",
                    "check_item_code": "catalogue_completeness_check",
                    "check_result": {
                        "issue_point": f"【目录缺失】缺失二级目录：{item.get('secondary_name', '')}",
                        "location": f"{item.get('first_seq', '')}.{item.get('second_seq', '')} {item.get('first_name', '')} > {item.get('secondary_name', '')}",
                        "suggestion": f"补充二级目录：{item.get('secondary_name', '')}",
                        "reason": f"在'{item.get('first_name', '')}'章节下，该二级目录应当出现",
                        "risk_level": "中风险"
                    },
                    "exist_issue": True,
                    "risk_info": {"risk_level": "medium"}
                })
            
            return {"issues": issues}
            
        except Exception as e:
            logger.warning(f"目录缺失检查异常: {str(e)}")
            return {"issues": []}

    async def check_outline_catalogue(
        self,
        trace_id_idx: str,
        outline_data: Dict[str, Any],
        state: Dict[str, Any],
        stage_name: str
    ) -> Dict[str, Any]:
        """
        基于文档目录(outline)的一二级分类缺失检查。

        使用模糊匹配算法，支持基于名称相似度的目录匹配。

        Args:
            trace_id_idx: 追踪ID索引
            outline_data: 包含 outline 的字典（通常来自 structured_content）
            state: 状态字典，可从中回退获取 structured_content.outline
            stage_name: 阶段名称

        Returns:
            Dict[str, Any]: 包含缺失一级、二级目录的统计结果
        """
        from .outline_catalogue_matcher import OutlineCatalogueMatcher

        start_time = time.time()
        name = "outline_catalogue_check"

        try:
            logger.info(f"[{name}] 开始目录一二级缺失检查")

            # CSV路径
            csv_path = str(
                Path(__file__).parent / 'doc_worker' / 'config' /
                'StandardCategoryTable.csv'
            )
            raw_content_csv = str(
                Path(__file__).parent / 'doc_worker' / 'config' /
                'construction_plan_standards.csv'
            )

            # 从 outline_data 或 state 中获取 chapters 列表
            outline_chapters = []
            if outline_data and isinstance(outline_data, dict):
                outline_raw = outline_data.get('outline') or outline_data
                if isinstance(outline_raw, dict):
                    outline_chapters = outline_raw.get('chapters', [])
                elif isinstance(outline_raw, list):
                    outline_chapters = outline_raw

            if not outline_chapters and state and isinstance(state, dict):
                structured = state.get('structured_content', {})
                outline_raw = structured.get('outline', {})
                if isinstance(outline_raw, dict):
                    outline_chapters = outline_raw.get('chapters', [])
                elif isinstance(outline_raw, list):
                    outline_chapters = outline_raw

            # 提取一级和二级信息
            outline_first = set()
            outline_secondary = {}
            
            for chapter in outline_chapters:
                if not isinstance(chapter, dict):
                    continue
                
                first_code = chapter.get('chapter_classification', '')
                if first_code:
                    outline_first.add(first_code)
                
                # 提取 subsections 中的二级章节
                for sub in chapter.get('subsections', []):
                    if not isinstance(sub, dict):
                        continue
                    second_code = sub.get('secondary_category_code', '')
                    if first_code and second_code:
                        outline_secondary[(first_code, second_code)] = sub.get('title', '')
            
            logger.info(f"[{name}] 获取到 {len(outline_first)} 个一级, {len(outline_secondary)} 个二级")

            # 使用模糊匹配
            matcher = OutlineCatalogueMatcher(csv_path, raw_content_csv)
            match_result = matcher.match_catalogue(
                outline_first=outline_first,
                outline_secondary=outline_secondary,
                threshold=0.6
            )
            
            catalogue_result = {
                "level": "primary_and_secondary",
                "is_complete": match_result['missing_first_count'] == 0 and match_result['missing_second_count'] == 0,
                "first_level": {
                    "total_required": len(matcher.first_names),
                    "actual_present": len(match_result['matched_first']),
                    "missing_count": match_result['missing_first_count'],
                    "missing": match_result['missing_first']
                },
                "second_level": {
                    "total_required": len(matcher.second_names),
                    "actual_present": len(match_result['matched_second']),
                    "missing_count": match_result['missing_second_count'],
                    "missing": match_result['missing_second']
                },
                "match_details": match_result['match_details']
            }

            execution_time = time.time() - start_time
            logger.info(
                f"[{name}] 检查完成，耗时: {execution_time:.2f}s, "
                f"缺失一级: {match_result['missing_first_count']} 个, "
                f"缺失二级: {match_result['missing_second_count']} 个"
            )

            return {
                "success": True,
                "execution_time": execution_time,
                "details": {
                    "name": name,
                    "missing_first_count": match_result['missing_first_count'],
                    "missing_second_count": match_result['missing_second_count'],
                    "missing_first": match_result['missing_first'],
                    "missing_second": match_result['missing_second'],
                    "catalogue_check": catalogue_result
                }
            }

        except Exception as e:
            execution_time = time.time() - start_time
            error_msg = f"[{name}] 检查失败: {str(e)}"
            logger.error(error_msg, exc_info=True)

            return {
                "success": False,
                "execution_time": execution_time,
                "error": str(e),
                "details": {
                    "name": name,
                    "missing_first_count": 0,
                    "missing_second_count": 0,
                    "missing_first": [],
                    "missing_second": [],
                    "catalogue_check": {}
                }
            }

    async def check_sensitive(self, trace_id_idx: str, review_content: str,
                            state: str, stage_name: str) -> Dict[str, Any]:
        """
        敏感信息检查

        Args:
            trace_id_idx: 追踪ID索引
            review_content: 审查内容
            state: 状态字典
            stage_name: 阶段名称

        Returns:
            Dict[str, Any]: 敏感信息检查结果
        """
        from core.construction_review.component.reviewers.utils import (
            check_sensitive_words_async,
            format_check_results
        )
        from foundation.observability.logger.loggering import review_logger as logger
        import time
        
        start_time = time.time()
        trace_id = "sensitive_check" + trace_id_idx
        first_results = await check_sensitive_words_async(review_content) # 先使用关键词匹配式审查
        
        # 判断是否检测到敏感词
        if first_results:
            logger.info(f"检测到 {len(first_results)} 个敏感词，准备送入大模型二审")
            # 有敏感词，拼接原文与敏感词列表，进入大模型二审
            # 格式化敏感词列表
            sensitive_words_info = []
            for item in first_results:
                sensitive_words_info.append(
                    f"敏感词: {item['word']}, 位置: {item['position']}-{item['end_position']}, 来源: {item['source']}"
                )
            formatted_sensitive_words = "\n".join(sensitive_words_info)
            
            logger.info(f"格式化后的敏感词信息：\n{formatted_sensitive_words}")
            
            # 调用大模型得到敏感词审查结果（通过 function_name 从 model_setting.yaml 加载模型配置）
            return await self.review("sensitive_check", trace_id, "basic", "sensitive_word_check",
                                   review_content, formatted_sensitive_words,
                                   None, state, stage_name, timeout=60, function_name="sensitive_check")
        else:
            # 没有检测到敏感词，构造返回体
            logger.info("没有检测到敏感词，未进入二审")
            from core.construction_review.component.reviewers.base_reviewer import ReviewResult
            
            execution_time = time.time() - start_time
            result = ReviewResult(
                success = True,
                details = {"name": "sensitive_check", "response": "无明显问题"},
                error_message = None,
                execution_time = execution_time
            )
            
            # 推送审查完成信息
            if state and state.get("progress_manager"):
                import asyncio
                review_result_data = {
                    'name': 'sensitive_check',
                    'success': result.success,
                    'details': result.details,
                    'error_message': result.error_message,
                    'execution_time': result.execution_time,
                    'timestamp': time.time()
                }
                asyncio.create_task(
                    state["progress_manager"].update_stage_progress(
                        callback_task_id=state["callback_task_id"],
                        stage_name=stage_name,
                        current=None,
                        status="processing",
                        message=f"sensitive_check 审查完成，未检测到敏感词，耗时: {result.execution_time:.2f}s",
                        issues=[review_result_data],
                        event_type="processing"
                    )
                )
            
            logger.info(f"sensitive_check 审查完成，未检测到敏感词，耗时: {result.execution_time:.2f}s")
            
            return result

    async def check_non_parameter_compliance(self, trace_id_idx: str, review_content: str, review_references: str,
                                         reference_source: str, state: str, stage_name: str,
                                         entity_query: str = None) -> Dict[str, Any]:
        """
        非参数合规性检查 - 安全相关/强制性条文知识库

        Args:
            trace_id_idx: 追踪ID索引
            review_content: 审查内容
            review_references: 审查参考信息
            reference_source: 参考来源
            state: 状态字典
            stage_name: 阶段名称
            entity_query: 实体组合查询条文（可选，来自 entity_results）

        Returns:
            Dict[str, Any]: 非参数合规性检查结果
        """
        reviewer_type = Stage.TECHNICAL.value['reviewer_type']
        prompt_name = Stage.TECHNICAL.value['non_parameter']
        trace_id = prompt_name+trace_id_idx

        # 如果有 entity_query，拼接到 review_content 前面
        if entity_query:
            logger.info(f"[非参数审查] 使用实体查询条文: {entity_query[:100]}...")
            combined_content = f"【实体查询条文】\n{entity_query}\n\n【待审查内容】\n{review_content}"
            logger.info(f"[非参数审查] 组合后内容长度: {len(combined_content)} (原内容: {len(review_content)}, 查询条文: {len(entity_query)})")
        else:
            combined_content = review_content

        return await self.review("non_parameter_compliance_check", trace_id, reviewer_type, prompt_name, combined_content, review_references,
                               reference_source, state, stage_name, timeout=45, function_name="completeness_review_classify")

    async def check_parameter_compliance(self, trace_id_idx: str, review_content: str, review_references: str,
                                        reference_source: str, state: str, stage_name: str,
                                        entity_query: str = None) -> Dict[str, Any]:
        """
        参数合规性检查 - 实体概念/工程术语知识库

        Args:
            trace_id_idx: 追踪ID索引
            review_content: 审查内容
            review_references: 审查参考信息
            reference_source: 参考来源
            state: 状态字典
            stage_name: 阶段名称
            entity_query: 实体组合查询条文（可选，来自 entity_results）

        Returns:
            Dict[str, Any]: 参数合规性检查结果
        """
        reviewer_type = Stage.TECHNICAL.value['reviewer_type']
        prompt_name = Stage.TECHNICAL.value['parameter']
        trace_id = prompt_name+trace_id_idx

        # 如果有 entity_query，拼接到 review_content 前面
        if entity_query:
            logger.info(f"[参数审查] 使用实体查询条文: {entity_query[:100]}...")
            combined_content = f"【实体查询条文】\n{entity_query}\n\n【待审查内容】\n{review_content}"
            logger.info(f"[参数审查] 组合后内容长度: {len(combined_content)} (原内容: {len(review_content)}, 查询条文: {len(entity_query)})")
        else:
            combined_content = review_content

        return await self.review("parameter_compliance_check", trace_id, reviewer_type, prompt_name, combined_content, review_references,
                               reference_source, state, stage_name, timeout=45, function_name="completeness_review_classify")

    async def reference_basis_reviewer(self, review_data: Dict[str, Any], trace_id: str,
                                state: dict = None, stage_name: str = None) -> Dict[str, Any]:
        """
        执行编制依据审查：调用prep_basis_reviewer中的异步审查功能

        Args:
            review_data: 待审查的编制依据数据，包含编制依据文本内容
            trace_id: 追踪ID
            state: 状态字典
            stage_name: 阶段名称

        Returns:
            审查结果字典，包含编制依据审查结果
        """
        start_time = time.time()
        try:
            logger.info(f"开始编制依据审查，trace_id: {trace_id}")

            # 提取关键数据
            basis_items: BasisItems = review_data.get('basis_items')
            review_content_text = review_data.get('content', '')
            max_concurrent = review_data.get('max_concurrent', 10)

            basis_list = []
            if basis_items and getattr(basis_items, "items", None):
                basis_list = [item.raw for item in basis_items.items if getattr(item, "raw", None)]
                review_content_text = review_content_text or "\n".join(basis_list)

            logger.info(f"提取的编制依据条目数: {len(basis_list)}")
            if basis_list:
                logger.info(f"编制依据内容预览: {basis_list[0][:50]}...")
            elif review_content_text:
                logger.info(f"编制依据内容预览(文本): {review_content_text[:50]}...")
            else:
                logger.warning("编制依据内容为空，将跳过审查")

            # 检查是否有有效的编制依据内容
            if not basis_list:
                logger.warning("没有可执行的编制依据审查任务")
                return {
                    "reference_basis_review_results": {
                        "review_results": [],
                        "review_content": review_content_text,
                        "total_basis_items": 0,
                        "valid_items": 0,
                        "standard_items": 0,
                        "execution_time": time.time() - start_time,
                        "error_message": "编制依据内容为空，无法进行审查"
                    }
                }

            # 调用prep_basis_reviewer中的异步审查方法
            logger.info("开始调用编制依据异步审查...")

            try:
                # 使用信号量控制并发
                async with self.semaphore:
                    # 从state中获取progress_manager和callback_task_id
                    progress_manager = state.get('progress_manager') if state else None
                    callback_task_id = state.get('callback_task_id') if state else None

                    # 调用带有SSE推送功能的review_all方法
                    from core.construction_review.component.reviewers.reference_basis_reviewer import BasisReviewService
                    async with BasisReviewService(max_concurrent=max_concurrent) as service:
                        reference_basis_review_results = await service.review_all(
                            basis_items,
                            collection_name="first_bfp_collection_status",
                            progress_manager=progress_manager,
                            callback_task_id=callback_task_id
                        )

                    logger.info(f"编制依据审查完成，批次数量: {len(reference_basis_review_results)}")

                    # 统计审查结果
                    total_items = 0
                    valid_items = 0
                    standard_items = 0

                    for batch in reference_basis_review_results:
                        if isinstance(batch, list):
                            total_items += len(batch)
                            for item in batch:
                                if isinstance(item, dict):
                                    valid_items += 1
                                    if item.get('is_standard', False):
                                        standard_items += 1

                    logger.info(f"审查统计 - 总编制依据: {total_items}, 有效项: {valid_items}, 标准项: {standard_items}")

            except Exception as e:
                logger.error(f"编制依据异步审查失败: {str(e)}")
                return {
                    "reference_basis_review_results": {
                        "review_results": [],
                        "review_content": review_content_text,
                        "total_basis_items": 0,
                        "valid_items": 0,
                        "standard_items": 0,
                        "execution_time": time.time() - start_time,
                        "error_message": f"编制依据审查失败: {str(e)}"
                    }
                }

            # 返回完整结果
            return {
                "reference_basis_review_results": {
                    "review_results": reference_basis_review_results,
                    "review_content": review_content_text,
                    "total_basis_items": total_items,
                    "valid_items": valid_items,
                    "standard_items": standard_items,
                    "execution_time": time.time() - start_time,
                    "error_message": None
                }
            }

        except Exception as e:
            execution_time = time.time() - start_time
            error_msg = f"编制依据审查失败: {str(e)}"
            logger.error(error_msg, exc_info=True)

            return {
                "reference_basis_review_results": {
                    "review_results": [],
                    "review_content": review_data.get('content', ''),
                    "total_basis_items": 0,
                    "valid_items": 0,
                    "standard_items": 0,
                    "execution_time": execution_time,
                    "error_message": error_msg
                }
            }
        
    async def timeliness_content_reviewer(self, review_data: Dict[str, Any], trace_id: str,
                                state: dict = None, stage_name: str = None) -> Dict[str, Any]:
        """
        执行三级分类内容时效性审查：检查tertiary_classification_details中引用的规范是否过时

        Args:
            review_data: 待审查数据，包含tertiary_classification_details
            trace_id: 追踪ID
            state: 状态字典
            stage_name: 阶段名称

        Returns:
            审查结果字典，包含内容时效性审查结果
        """
        start_time = time.time()
        try:
            logger.info(f"开始三级分类内容时效性审查，trace_id: {trace_id}")

            # 提取三级分类详情
            tertiary_details = review_data.get('tertiary_classification_details', [])
            max_concurrent = review_data.get('max_concurrent', 4)

            if not tertiary_details:
                logger.warning("三级分类详情为空，将跳过内容时效性审查")
                return {
                    "timeliness_content_review_results": {
                        "review_results": [],
                        "total_items": 0,
                        "issue_items": 0,
                        "execution_time": time.time() - start_time,
                        "error_message": None,
                        "message": "未找到三级分类详情，跳过内容时效性审查"
                    }
                }

            logger.info(f"提取到 {len(tertiary_details)} 个三级分类详情")

            # 调用内容时效性审查
            try:
                # 使用信号量控制并发
                async with self.semaphore:
                    # 从state中获取progress_manager和callback_task_id
                    progress_manager = state.get('progress_manager') if state else None
                    callback_task_id = state.get('callback_task_id') if state else None

                    # 调用内容时效性审查器
                    from core.construction_review.component.reviewers.timeliness_content_reviewer import ContentTimelinessReviewer
                    async with ContentTimelinessReviewer(max_concurrent=max_concurrent, db_pool=self.db_pool) as reviewer:
                        timeliness_content_results = await reviewer.review_tertiary_content(
                            tertiary_details=tertiary_details,
                            collection_name="first_bfp_collection_status",
                            progress_manager=progress_manager,
                            callback_task_id=callback_task_id
                        )

                    logger.info(f"内容时效性审查完成，发现问题数量: {len(timeliness_content_results)}")

                    # 统计审查结果
                    total_items = len(timeliness_content_results)
                    issue_items = sum(1 for item in timeliness_content_results if item.get('exist_issue', False))

                    logger.info(f"审查统计 - 总规范引用: {total_items}, 问题项: {issue_items}")

            except Exception as e:
                logger.error(f"内容时效性审查失败: {str(e)}")
                return {
                    "timeliness_content_review_results": {
                        "review_results": [],
                        "total_items": 0,
                        "issue_items": 0,
                        "execution_time": time.time() - start_time,
                        "error_message": f"内容时效性审查失败: {str(e)}"
                    }
                }

            # 返回完整结果
            return {
                "timeliness_content_review_results": {
                    "review_results": timeliness_content_results,
                    "total_items": total_items,
                    "issue_items": issue_items,
                    "execution_time": time.time() - start_time,
                    "error_message": None
                }
            }

        except Exception as e:
            execution_time = time.time() - start_time
            error_msg = f"内容时效性审查失败: {str(e)}"
            logger.error(error_msg, exc_info=True)

            return {
                "timeliness_content_review_results": {
                    "review_results": [],
                    "total_items": 0,
                    "issue_items": 0,
                    "execution_time": execution_time,
                    "error_message": error_msg
                }
            }

    async def timeliness_basis_reviewer(self, review_data: Dict[str, Any], trace_id: str,
                                state: dict = None, stage_name: str = None) -> Dict[str, Any]:
        """
        执行编制依据审查：调用prep_basis_reviewer中的异步审查功能

        Args:
            review_data: 待审查的编制依据数据，包含编制依据文本内容
            trace_id: 追踪ID
            state: 状态字典
            stage_name: 阶段名称

        Returns:
            审查结果字典，包含编制依据审查结果
        """
        start_time = time.time()
        try:
            logger.info(f"开始编制依据审查，trace_id: {trace_id}")

            # 提取关键数据
            basis_items: BasisItems = review_data.get('basis_items')
            review_content_text = review_data.get('content', '')
            max_concurrent = review_data.get('max_concurrent', 10)

            # 基于BasisItems计算统计信息
            basis_list = []
            if basis_items and getattr(basis_items, "items", None):
                basis_list = [item.raw for item in basis_items.items if getattr(item, "raw", None)]
                review_content_text = review_content_text or "\n".join(basis_list)

            logger.info(f"提取的编制依据条目数: {len(basis_list)}")
            if basis_list:
                logger.info(f"编制依据内容预览: {basis_list[0][:50]}...")
            elif review_content_text:
                logger.info(f"编制依据内容预览(文本): {review_content_text[:50]}...")
            else:
                logger.warning("编制依据内容为空，将跳过审查")

            # 检查是否有有效的编制依据内容
            if not basis_list:
                logger.warning("没有可执行的编制依据审查任务")
                return {
                    "timeliness_basis_review_results": {
                        "review_results": [],
                        "review_content": review_content_text,
                        "total_basis_items": 0,
                        "valid_items": 0,
                        "standard_items": 0,
                        "execution_time": time.time() - start_time,
                        "error_message": "编制依据内容为空，无法进行审查"
                    }
                }

            # 调用prep_basis_reviewer中的异步审查方法
            logger.info("开始调用编制依据异步审查...")

            try:
                # 使用信号量控制并发
                async with self.semaphore:
                    # 从state中获取progress_manager和callback_task_id
                    progress_manager = state.get('progress_manager') if state else None
                    callback_task_id = state.get('callback_task_id') if state else None

                    # 调用带有SSE推送功能的review_all方法
                    from core.construction_review.component.reviewers.timeliness_basis_reviewer import BasisReviewService
                    async with BasisReviewService(max_concurrent=max_concurrent, db_pool=self.db_pool) as service:
                        timeliness_basis_review_results = await service.review_all(
                            basis_items,
                            collection_name="first_bfp_collection_status",
                            progress_manager=progress_manager,
                            callback_task_id=callback_task_id
                        )

                    logger.info(f"编制依据审查完成，批次数量: {len(timeliness_basis_review_results)}")

                    # 统计审查结果
                    total_items = 0
                    valid_items = 0
                    standard_items = 0

                    for batch in timeliness_basis_review_results:
                        if isinstance(batch, list):
                            total_items += len(batch)
                            for item in batch:
                                if isinstance(item, dict):
                                    valid_items += 1
                                    if item.get('is_standard', False):
                                        standard_items += 1

                    logger.info(f"审查统计 - 总编制依据: {total_items}, 有效项: {valid_items}, 标准项: {standard_items}")

            except Exception as e:
                logger.error(f"编制依据异步审查失败: {str(e)}")
                return {
                    "timeliness_basis_review_results": {
                        "review_results": [],
                        "review_content": review_content_text,
                        "total_basis_items": 0,
                        "valid_items": 0,
                        "standard_items": 0,
                        "execution_time": time.time() - start_time,
                        "error_message": f"编制依据审查失败: {str(e)}"
                    }
                }

            # 返回完整结果
            return {
                "timeliness_basis_review_results": {
                    "review_results": timeliness_basis_review_results,
                    "review_content": review_content_text,
                    "total_basis_items": total_items,
                    "valid_items": valid_items,
                    "standard_items": standard_items,
                    "execution_time": time.time() - start_time,
                    "error_message": None
                }
            }

        except Exception as e:
            execution_time = time.time() - start_time
            error_msg = f"编制依据审查失败: {str(e)}"
            logger.error(error_msg, exc_info=True)

            return {
                "timeliness_basis_review_results": {
                    "review_results": [],
                    "review_content": review_data.get('content', ''),
                    "total_basis_items": 0,
                    "valid_items": 0,
                    "standard_items": 0,
                    "execution_time": execution_time,
                    "error_message": error_msg
                }
            }