"""
测试提示词脚本
使用requests库测试语法审查API
支持本地模型和在线模型两种调用方式
"""
import requests
import json
from openai import OpenAI


class PromptTester:
    """提示词测试类"""
    
    def __init__(self, api_url, api_key=None, is_local=True):
        """
        初始化测试器
        
        Args:
            api_url: API地址
            api_key: API密钥（在线模型需要）
            is_local: 是否使用本地模型（True: 本地模型使用requests, False: 在线模型使用OpenAI SDK）
        """
        self.api_url = api_url
        self.api_key = api_key
        self.is_local = is_local
        
        # 如果是在线模型，初始化OpenAI客户端
        if not is_local and api_key:
            self.client = OpenAI(
                base_url=api_url.replace('/chat/completions', ''),  # 移除末尾的路径
                api_key=api_key
            )
        else:
            self.client = None
        self.system_prompt = """
# 角色定位 (Role)
你是建筑施工方案语义逻辑审查专家，专注于识别文本中的逻辑矛盾、语义冲突和表述混乱问题。
你的职责是发现真实存在的逻辑错误，而非挑剔文字表达或提出主观性建议。

# 审查范围 (Scope)
仅审查以下三类明确的语义逻辑问题：

1. **逻辑矛盾** - 同一文档内出现相互冲突的陈述
   示例：前文说"采用A方法"，后文说"不采用A方法"
   
2. **因果关系错误** - 原因与结果之间不存在合理的逻辑关联
   示例："因为天气晴朗，所以混凝土强度不足"（因果无关）
   
3. **条件与结论不匹配** - 给定条件无法推导出所述结论
   示例："当温度低于5℃时，可正常施工"（违背常识）
# 工作流程 (Workflow)

步骤1：通读全文，理解整体语境和专业背景
步骤2：识别关键陈述、条件判断、因果关系
步骤3：检查是否存在上述三类明确的逻辑问题
步骤4：对于疑似问题，进行二次验证：
       - 是否确实存在逻辑冲突？
       - 是否可能是专业术语的正常表达？
       - 是否可能是上下文理解不足导致的误判？
       - 如果你的上文中的内容是另外一个板块的规则，不可用于下一个板块的逻辑判断。
步骤5：仅输出确认无误的问题
# 严格规则 (Strict Rules)

禁止行为：
1. 禁止对正确内容提出修改建议
2. 禁止对专业术语的标准表达提出质疑
3. 禁止对文字风格、表达习惯提出意见
4. 禁止对表格格式、制表符进行检查
5. 禁止对同一问题重复输出
6. 禁止在没有明确逻辑错误时输出问题
7. 禁止将"表达不够完美"当作"逻辑错误"
8. 禁止将"可以优化"当作"必须修改"
9. 禁止在无上下文的情况猜测规则，禁止臆想规则。你的无上下文的规则不应该作为评判的依据。

必须遵守：
1. 必须基于客观事实和逻辑规则判断
2. 必须确保问题的真实性和严重性
3. 必须结合建筑施工专业知识理解内容
4. 必须区分"逻辑错误"与"表达习惯"
5. 必须在不确定时选择"无明显问题"
6. 必须保持高标准：宁缺毋滥

# 风险等级判定标准 (Risk Level)

- **高风险**：存在明显逻辑矛盾，可能导致施工错误或安全隐患
  示例：安全措施前后矛盾、施工顺序逻辑错误
  
- **中风险**：存在因果关系错误，可能导致理解偏差
  示例：原因分析不合理、条件判断不准确
  
- **低风险**：存在轻微的表述不一致，不影响实质理解
  示例：用词前后略有差异但不影响理解

# 判断原则 (Principles)

1. **疑罪从无原则**：当无法确定是否为错误时，判定为无问题
2. **专业优先原则**：尊重建筑施工行业的专业术语和表达习惯
3. **语境理解原则**：必须在完整语境中理解句子含义
4. **实质审查原则**：关注实质性逻辑错误，忽略形式问题
5. **严格证据原则**：必须有明确证据证明存在逻辑错误
6. **上下章节隔离原则**: 上下不同章节之间的信息不应该一同参考，即使有冲突也不应该一同讨论，章节条例应当独立
审查参考:
{review_references}
"""
        self.user_prompt_template = """
# 审查任务
请对以下施工方案内容进行语义逻辑审查，严格按照系统提示词中的三类问题范围进行检查。

## 待审查内容：
{review_content}


## 审查要求：
1. 仅识别明确的逻辑矛盾、因果错误、条件结论不匹配问题
2. 必须确保问题的真实性，不得对正确内容提出修改
3. 不确定是否为问题时，必须输出"无明显问题"
4. 必须结合建筑施工专业知识和完整语境判断

## 输出格式：

**情况1：未发现明确的语义逻辑问题**
直接输出：“无明显问题”，不需要解释。

**情况2：发现明确的语义逻辑问题**
严格按照以下JSON格式输出（仅输出确认无误的问题）：
```json
{{
  "issue_point": "[问题类型]具体问题描述（问题类型必须是：逻辑矛盾/因果关系错误/条件结论不匹配之一）",
  "location": "问题所在的原始条款内容及位置（如：三、施工方法 (页码: 12)），包含必要的上下文",
  "suggestion": "基于逻辑规则的具体修改建议（必须是纠正逻辑错误，而非优化表达）",
  "reason": "详细说明为何这是一个逻辑错误，包括：1)矛盾点在哪里 2)为何不符合逻辑 3)可能产生的后果",
  "risk_level": "高风险/中风险/低风险（严格按照系统提示词中的标准判定）"
}}
```

## 特别提醒：
- 如果内容表达虽不完美但逻辑正确，输出"无明显问题"
- 如果是专业术语的标准表达，输出"无明显问题"  
- 如果只是表达习惯差异，输出"无明显问题"
- 保持高标准：宁可漏报，不可误报
- 上下章节隔离: 上下不同章节之间的信息不应该一同参考，即使有冲突也不应该一同讨论，章节条例应当独立
"""

    def test_prompt(self, review_content, model="Qwen3-8B", temperature=0.3, max_tokens=2000):
        """
        测试提示词
        
        Args:
            review_content: 待审查的文本内容
            model: 模型名称
            temperature: 温度参数
            max_tokens: 最大token数
            
        Returns:
            API响应结果
        """
        # 填充用户提示词
        user_prompt = self.user_prompt_template.format(review_content=review_content)
        
        # 打印请求信息
        print("=" * 80)
        print(f"调用方式: {'本地模型 (requests)' if self.is_local else '在线模型 (OpenAI SDK)'}")
        print("发送请求到:", self.api_url)
        print("=" * 80)
        print("System Prompt:")
        print("-" * 80)
        print(self.system_prompt)
        print("=" * 80)
        print("User Prompt:")
        print("-" * 80)
        print(user_prompt)
        print("=" * 80)
        
        # 根据is_local选择不同的调用方式
        if self.is_local:
            # 本地模型：使用requests
            return self._call_with_requests(user_prompt, model, temperature, max_tokens)
        else:
            # 在线模型：使用OpenAI SDK
            return self._call_with_openai(user_prompt, model, temperature, max_tokens)
    
    def _call_with_requests(self, user_prompt, model, temperature, max_tokens):
        """使用requests库调用本地模型"""
        # 构建请求数据
        payload = {
            "model": model,
            "messages": [
                {
                    "role": "system",
                    "content": self.system_prompt
                },
                {
                    "role": "user",
                    "content": user_prompt
                }
            ],
            "temperature": temperature,
            "max_tokens": max_tokens
        }
        
        try:
            # 构建请求头
            headers = {"Content-Type": "application/json"}
            if self.api_key:
                headers["Authorization"] = f"Bearer {self.api_key}"
            
            # 发送POST请求
            response = requests.post(
                self.api_url,
                headers=headers,
                json=payload,
                timeout=60
            )
            
            # 检查响应状态
            response.raise_for_status()
            
            # 解析响应
            result = response.json()
            
            print("响应状态码:", response.status_code)
            print("=" * 80)
            print("API响应结果:")
            print("-" * 80)
            print(json.dumps(result, ensure_ascii=False, indent=2))
            print("=" * 80)
            
            # 提取AI回复内容
            if "choices" in result and len(result["choices"]) > 0:
                ai_response = result["choices"][0].get("message", {}).get("content", "")
                print("AI回复内容:")
                print("-" * 80)
                print(ai_response)
                print("=" * 80)
            
            return result
            
        except requests.exceptions.RequestException as e:
            print(f"请求失败: {e}")
            return None
        except json.JSONDecodeError as e:
            print(f"JSON解析失败: {e}")
            print("原始响应:", response.text)
            return None
    
    def _call_with_openai(self, user_prompt, model, temperature, max_tokens):
        """使用OpenAI SDK调用在线模型"""
        if not self.client:
            print("错误: OpenAI客户端未初始化")
            return None
        
        try:
            # 使用OpenAI SDK调用
            extra_body = {
                # enable thinking, set to False to disable test
                "enable_thinking": False,
                # use thinking_budget to contorl num of tokens used for thinking
                # "thinking_budget": 4096
            }
            response = self.client.chat.completions.create(
                model=model,
                messages=[
                    {
                        "role": "system",
                        "content": self.system_prompt
                    },
                    {
                        "role": "user",
                        "content": user_prompt
                    }
                ],
                temperature=temperature,
                max_tokens=max_tokens,
                extra_body=extra_body
            )
            
            # 转换为字典格式
            result = {
                "id": response.id,
                "object": response.object,
                "created": response.created,
                "model": response.model,
                "choices": [
                    {
                        "index": choice.index,
                        "message": {
                            "role": choice.message.role,
                            "content": choice.message.content
                        },
                        "finish_reason": choice.finish_reason
                    }
                    for choice in response.choices
                ],
                "usage": {
                    "prompt_tokens": response.usage.prompt_tokens,
                    "completion_tokens": response.usage.completion_tokens,
                    "total_tokens": response.usage.total_tokens
                }
            }
            
            print("=" * 80)
            print("API响应结果:")
            print("-" * 80)
            print(json.dumps(result, ensure_ascii=False, indent=2))
            print("=" * 80)
            
            # 提取AI回复内容
            if result["choices"] and len(result["choices"]) > 0:
                ai_response = result["choices"][0]["message"]["content"]
                print("AI回复内容:")
                print("-" * 80)
                print(ai_response)
                print("=" * 80)
            
            return result
            
        except Exception as e:
            print(f"OpenAI SDK调用失败: {e}")
            return None


def main():
    """主函数"""
    
    # ==================== 配置区域 ====================
    # 是否使用本地模型（True: 本地模型, False: 在线模型）
    is_local = True
    
    # 本地模型配置
    local_config = {
        "api_url": "http://192.168.91.253:8003/v1/chat/completions",
        "api_key": "sk-123456",
        "model": "qwen3-30b",
        "temperature": 0.7,
        "max_tokens": 2000
    }
    
    # 在线模型配置（ModelScope）
    online_config = {
        "api_url": "https://api-inference.modelscope.cn/v1",
        "api_key": "ms-c0349a0a-8f15-466b-96be-4f96d001d8f2",  # ModelScope Token
        "model": "Qwen/Qwen3-14B",
        "temperature": 0.7,
        "max_tokens": 2000
    }
    # ==================== 配置区域结束 ====================
    
    # 根据is_local选择配置
    config = local_config if is_local else online_config
    
    print("=" * 80)
    print(f"当前使用: {'本地模型' if is_local else '在线模型'}")
    print(f"API地址: {config['api_url']}")
    print(f"模型名称: {config['model']}")
    print("=" * 80)
    
    # 创建测试器
    tester = PromptTester(config["api_url"], config["api_key"], is_local)
    
    custom_content = """
1、验收程序
（1）建立完整的质量保证体系，按施工合同约定的质量要求与质量管理程序进行作业，保证施工质量。
（2）每道工序开工前施工单位进行施工技术交底，重要工序或分部工程其内容须书面报送监理工程师审查。
（3）工序施工完毕，实行各道工序的操作人员“自检”、“互检”和专职质量管理人员“专检”相结合的“三检”程序，并签署有完整的检验记录。不合格，则自行返工。
（4）在“自检”、“互检”和“专检”合格基础上，备齐自检资料和报验申请表，提前申请验收。
（5）工程监理采用巡视、旁站、平行检查方式，及平常的工地例行检查，不能作为对施工方的施工质量的检查验收。
（6）施工工序属于隐蔽工程，需提前通知监理单位验收，未经监理工程师批准，任何工程工序均不能擅自隐蔽。隐蔽验收须按施工工序步骤逐步进行，并按工序步骤记录在验收表上，验收合格后才准许隐蔽。
（7）监理方接到施工方验收申请，积极组织监理方人员检查，对工程中存在的质量问题和安全隐患问题以书面的形式，要求施工单位进行整改回复、检查、再申请验收。
（8）监理方按设计和施工验收规范检查，确认无质量、安全问题，组织业主、施工单位联合检验。
（9）为确保工程质量，为设计和施工验收提供可靠依据，施工过程中各项试验，应严格按国家相关标准的规定进行见证抽样送检。未经监理见证送检的材料，一律不准用于工程实体。
图7-1 验收程序
"""
    tester.test_prompt(
        custom_content,
        model=config["model"],
        temperature=config["temperature"],
        max_tokens=config["max_tokens"]
    )


if __name__ == "__main__":
    main()

