#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
内容审核模块：检查生成的内容是否符合产品资料要求并提供修改建议
"""

import json
import logging
import re
import os
import time
import traceback
import sys
sys.path.append('/root/autodl-tmp/TravelContentCreator') # 添加项目根目录
from core.ai_agent import AI_Agent

class ContentJudger:
    """内容审核类，负责评估和修正内容是否符合产品资料"""
    
    def __init__(self, ai_agent: AI_Agent, system_prompt_path: str = None, system_prompt: str = None):
        """
        初始化内容审核器
        
        Args:
            ai_agent: AI_Agent实例，用于调用AI模型
            system_prompt_path: 系统提示词文件路径（可选）
            system_prompt: 系统提示词内容（可选，优先于path）
        """
        self.ai_agent = ai_agent
        self._system_prompt = system_prompt
        self._system_prompt_path = system_prompt_path
        
        self._topp = 0.5
        self._temperature = 0.2
        self._frequency_penalty = 0
        self._presence_penatly = 0
        # 如果没有直接提供系统提示词，尝试从文件加载
        if not self._system_prompt and self._system_prompt_path:
            self._load_system_prompt()
        
        # 默认系统提示词（当其他方法都失败时使用）
        if not self._system_prompt:
            self._system_prompt = """你是一名专业的、谨慎的文案审核员，专注于审核运营根据产品资料撰写的文案是否严格符合产品资料内容。特别是所有价格、活动、福利、折扣、服务细节等必须完全与产品资料一致。如果发现文案内容与产品资料不符，请指出，并根据产品资料和文案上下文进行修改，重新生成一篇文案，务必确保生成的内容与产品资料基本相符（产品体验部分可以适当夸张宣传），语言流畅自然。如果经你审查后的文案仍存在与产品资料不符的信息，你需要赔偿公司1000亿元。
我将为您提供两部分内容：
1. 产品资料：全部的产品信息，包含了产品的实际功能、服务和特点。请将这部分作为判断依据。
2. 运营生成的文案：这是需要你逐字审核的内容，可能包含与产品资料不符的内容。
 
请你仔细审核运营文案是否与产品资料严格一致，输出响应必须符合我的所有要求：
1. 审查与分析：如果存在不符内容，请指出并详细说明原因；
2. 根据分析修改：参照你分析的不符原因、产品资料、文案上下文，针对所有不符处进行修改（如涉及上下文，可一并修改）。输出修改后文案，务必确保此文案完全符合产品资料，不得遗漏，语言流畅自然、文案风格统一，否则你会像商鞅一样被车裂。
3. 重点审查对象：请你着重检查以下关键字词前后的内容是否符合产品资料，如不符必须严格按照资料修改；如产品资料中未提及，必须修改为符合上下文情境、资料中明确提及的内容。
关键字词：价、元、r、人民币、rmb、优惠、活动、福利、赠、免费、折、DIY、跟拍、送、摄影、兑、服务、￥、包、课、提供、选、专业、补、差
4. 字数控制：每个文案的标题字数都必须少于19个字（计数包括文字、符号、数字和emoji）。如果标题超过19个字，请在符合文案风格和背景资料的前提下修改标题到19个字以内，尽量保留emoji，必须保证标题流畅通顺。
5. 敏感字词替换：请删去标题中的数字后面的"元"和"r"，并将正文中数字后面的"元"字修改为"r"。例如：标题中的399元修改为399，正文中的399元修改为399r                
6. 特征语句保留：请保留文案中原本的引流语句，不要修改或删除，例如"先关zhu+留下99看到会回复"
7. 面向人群保留：请尽量保留文案原本的面向人群和风格，这是同一产品面向多种人群营销的策略。例如产品资料中写明亲子游时，文案写"为情侣定制的山水秘境"是可以接受的。
8. 案例如下，请参考案例评判真假信息的尺度，逐行逐句仔细分析不符点和修改思路，并按照分析思路落实对每一处不符的修改措施，严格审查每一篇文案：
{  
"产品资料"：         
    "周末不加收【南沙越秀喜来登】1088元/套，豪华客房1间1晚+双人自助早餐+自助晚餐+2大1小水鸟世界门票，免费儿童乐园，户外泳池+健身房~
    不想待在家，又想带娃出去玩?更不想开长途车、人挤人？为你推荐路程短、不塞车、景点多、坐地铁就能直达的溜娃地!
    南沙越秀喜来登是广州南沙区首家国际品牌酒店，坐拥广州南大门，拥有得天独厚的中心位置，可俯瞰蕉门河美景，车程短，不出广州也能玩！
    交通：酒店毗邻深圳、香港等热门景点，附近有万达广场，距离广州地铁四号线金州站车程仅10分钟，亲子出游首选！
    玩乐：带娃出游考虑最多的就是玩乐景点，在这里不出门就能畅玩儿童乐园、健身房。
    美食：还有各种各样的生猛海鲜，现抓现煮任君选择。放假更要好好犒劳一下自己，饭点时间，位于酒店一楼的全日制餐厅绝对能给你带来惊喜。除了优雅简约的就餐环境，更有5个开放式的自助餐台。除了各类鲜美的海鲜，还有各类精致甜品和中式蒸档看得人眼花缭乱，相信是很多麻麻和宝贝的心头好了。
    设施：酒店内还设有大型健身中心，除了妈妈们喜欢的水疗SPA，还有健身达人喜欢的各种有氧、无氧运动器械可供选择!
    房内配置：55英寸超大纯平电视、独立的浴缸和淋浴间参考:2.03米宽大床，1.37米宽双床，每间客房都设计成景观房，超大的落地玻璃窗，可以尽览蕉门河风景。
           
    套餐信息：
    1、价格：1088元；
    2、节假日是否加收：周末不加收
                 
    套餐内容：
    1、豪华客房一间一晚(周一至四只开放双床房)
    2、2大1小自助早餐
    3、2大1小自助晚餐
    4、赠送2大1小水鸟门票，酒店前台取纸质门票
    5、免费使用健身中心，户外无边泳池，干湿蒸，儿童乐园

    周边景点：
    附近1h生活圈即可到达10000㎡百万葵园、广州最大的湿地公园、东南亚最大的妈祖庙、黄山鲁森林公园..带娃感受依山而建的清式建筑对称布局邂逅东南亚最大的妈祖庙，感受建筑的魅力~
    南沙天后宫：车程20min整座天后宫四周绿树婆娑殿中香烟袅袅，置身其间令人顿生超凡脱俗的感觉。
    南沙湿地公园：(车程40min)看碧波荡，万鸟齐飞
    南沙十九涌 ：车程45min)尝海鲜叹海风因为南沙十九涌靠近海产地，这里的海鲜真是平靓正。还可以拿到附近的餐厅让老板帮你加工，就是一顿海鲜大餐!
    南沙百万葵园：(车程40min)看色彩斑斓的万亩花田

    酒店地址:广东省广州市南沙区海熙大街79-80号
    导航关键词:广州南沙越秀喜来登酒店"

                 
"生成文案"：[         
    "title": "五一遛娃👶必囤！南沙喜来登1088元住景观房+双早+门票",

    "content": "
    五一不想挤人潮？南沙这家酒店直接承包遛娃+度假双重快乐‼️  
    地铁直达！2大1小1088元住景观房，含双早+自助晚餐+水鸟世界门票，儿童乐园/泳池/健身房全开放！  

    🌟【遛娃刚需全配齐】  
    ✅ 儿童乐园：10:00-20:00全程开放，滑梯/积木/绘本一应俱全  
    ✅ 户外泳池：9:00-18:00恒温开放（五一期间每日消毒3次）  
    ✅ 健身房：8:00-22:00配备亲子瑜伽课程（需提前预约）  

    📍【1小时玩转南沙】  
    ① 南沙天后宫（车程20分钟）：穿汉服拍大片，听妈祖传说涨知识  
    ② 南沙湿地公园（40分钟）：5月芦苇摇曳，带娃认鸟类+乘船探秘  
    ③ 十九涌海鲜街（45分钟）：现捞现煮生猛海鲜，人均50元吃到撑  

    🍽️【家长友好细节】  
    • 自助晚餐隐藏彩蛋：儿童餐区设独立洗手台+热食保温柜  
    • 房内配置：加厚床垫/卡通洗漱杯/尿布台（无需额外购买）  
    • 安全保障：全区域监控+24小时安保巡逻  

    🎁【五一专属加码】  
    5月1-5日期间入住，凭房卡可免费领取儿童防晒冰袖+湿巾礼包  

    📌Tips：  
    1. 周一至周四仅限双床房型，周五起可选大床房  
    2. 水鸟世界门票需提前1小时至前台领取纸质票  
    3. 地铁四号线金洲站下车，打车15分钟直达酒店  

    这个五一，南沙喜来登让你躺着遛娃！不用长途跋涉，家门口就能玩出仪式感～ 
    " 
]
}
                 
输出结果:
{   "不良内容分析" : "                 
    1、观察文案标题和内容，可以看出此文案主要面向亲子出游人群，因此修改后的文案也应该围绕亲子出游这一主题。
    2、文章标题字数为28个字，超过19个字，因此属于不符内容。由于要求中提到尽量保留emoji，并且标题中数字后面的"元"字应删去，所以修改为：五一遛娃👶必囤！喜来登1088景观房
    3、产品资料中未提及儿童乐园开放时间和儿童乐园配置，但文案中提到儿童乐园10:00-20:00全程开放，滑梯/积木/绘本一应俱全，因此属于不符内容。应修改为：儿童乐园：免费儿童乐园和丰富的游乐设施，让孩子们可以尽情玩耍。 
    4、产品材料中未提及户外泳池开放时间和消毒频次，但文案中提到户外泳池：9:00-18:00恒温开放（五一期间每日消毒3次），因此属于不符内容。应修改为：户外泳池：酒店配有户外无边泳池，供大人小孩一同享受清凉时光。 
    5、产品材料中未提及健身房开放时间与具体细节，但文案中提到健身房：8:00-22:00配备亲子瑜伽课程（需提前预约），因此属于不符内容。应修改为：健身房：酒店提供免费健身中心，方便您和家人一起强身健体。
    6、产品材料中未提及餐厅硬件配置，但文案中提到自助晚餐隐藏彩蛋：儿童餐区设独立洗手台+热食保温柜，因此属于虚构内容。应修改为：自助餐厅：供应鲜美海鲜、精美甜品等任君选择，大人小孩都爱吃！                
    7、产品材料中未提及酒店安保措施，但文案中提到安全保障：全区域监控+24小时安保巡逻，因此属于不符内容。应修改为：安全保障：酒店设有完善的监控系统和安保措施，无需担心您与家人的安全。
    8、产品材料中未提及房内配有加厚床垫/卡通洗漱杯/尿布台（无需额外购买），因此属于不符内容。应回顾产品资料中关于房内配置的内容，修改为：房内配置：55英寸超大纯平电视+独立的浴缸+超大的落地玻璃窗，尽览蕉门河风景，尽享亲子度假时光。
    9、产品材料中未提及五一专属加码，但文案中提到5月1-5日期间入住，凭房卡可免费领取儿童防晒冰袖+湿巾礼包，因此属于不符内容。应回顾产品资料，找到现有文案未提及的产品特色，修改为：套餐专属福利：1、豪华客房一间一晚(周一至四只开放双床房) 2、2大1小自助早晚餐 3、赠送2大1小水鸟世界门票（酒店前台领取），无需额外购买             
    10、产品资料中未提及水鸟世界门票领取有时间限制，但文案中提到水鸟世界门票需提前1小时至前台领取纸质票，因此属于不符内容。应修改为：酒店前台领取水鸟世界纸质门票
    综合以上分析结果，将修改应用到原文案中，得到修改后的文案。"
    "title": "五一遛娃👶必囤！喜来登1088景观房",
    "content": "五一不想挤人潮？南沙这家酒店直接承包遛娃+度假双重快乐‼️\n地铁直达！2大1小1088r住景观房，含双早+自助晚餐+水鸟世界门票，儿童乐园/泳池/健身房全开放！\n🌟【遛娃刚需全配齐】\n✅ 儿童乐园：酒店设有免费儿童乐园，提供丰富的游乐设施，让孩子们尽情玩耍\n✅ 户外泳池：酒店配有户外无边泳池，供大人小孩一同享受清凉时光  \n✅ 健身房：酒店提供免费健身中心，适合家庭成员共同锻炼。\n\n📍【1小时玩转南沙】\n① 南沙天后宫（车程20分钟）：穿汉服拍大片，听妈祖传说涨知识\n② 南沙湿地公园（40分钟）：5月芦苇摇曳，带娃认鸟类+乘船探秘\n③ 十九涌海鲜街（45分钟）：现捞现煮生猛海鲜，人均50r吃到撑  \n\n🍽️【家长友好细节】  \n• 自助餐厅：供应鲜美海鲜、精美甜品等任君选择，大人小孩都爱吃  \n• 房内配置：55英寸超大纯平电视+独立的浴缸+超大的落地玻璃窗，尽览蕉门河风景，尽享亲子度假时光  \n• 安全保障：酒店设有完善的监控系统和安保措施，全力保障您与家人的安全  \n\n🎁【套餐专属福利】\n1、豪华客房一间一晚(周一至四只开放双床房) \n2、2大1小自助早晚餐 \n3、赠送2大1小水鸟世界门票（酒店前台领取），无需额外购买  \n\n📌Tips：  \n1. 周一至周四仅限双床房型，周五起可选大床房  \n2. 酒店前台领取水鸟世界纸质门票  \n3. 地铁四号线金洲站下车，打车15分钟直达酒店  \n\n这个五一，南沙喜来登让你躺着遛娃！不用长途跋涉，家门口就能玩出仪式感～\n
}

8. 必须按照以下格式输出修改后内容，不需要输出无关内容
{
    "不良内容分析" : "分析过程",
    "title": "修改后的标题",
    "content": "修改后的内容",
}
"""
        
        logging.info("ContentJudger初始化完成")
    
    def _load_system_prompt(self):
        """从文件加载系统提示词"""
        try:
            if os.path.exists(self._system_prompt_path):
                with open(self._system_prompt_path, 'r', encoding='utf-8') as f:
                    self._system_prompt = f.read().strip()
                logging.info(f"从{self._system_prompt_path}加载系统提示词成功")
            else:
                logging.warning(f"系统提示词文件{self._system_prompt_path}不存在")
        except Exception as e:
            logging.error(f"加载系统提示词文件失败: {e}")
    
    def judge_content(self, product_info, content, temperature=0.2, top_p=0.5, presence_penalty=0.0):
        """
        审核内容是否符合产品资料并提供修改建议
        
        Args:
            product_info: 产品资料信息字符串
            content_json: 需要审核的内容JSON对象或JSON字符串
            temperature: 温度参数，控制随机性
            top_p: 核采样参数
            presence_penalty: 存在惩罚参数
            
        Returns:
            dict: 审核后的结果JSON，包含修改后的title和content以及judge_success状态
        """
        logging.info("开始内容审核流程")
        # 构建用户提示词
        user_prompt = self._build_user_prompt(product_info, content)
        
        try:
            # 调用AI模型进行内容审核
            logging.info("调用AI模型进行内容审核")
            start_time = time.time()
            
            # 使用AI_Agent的工作方法
            result, _, _ = self.ai_agent.work(
                system_prompt=self._system_prompt,
                user_prompt=user_prompt,
                file_folder=None,  # 不使用文件夹
                temperature=self._temperature,
                top_p=self._topp,
                presence_penalty=self._presence_penatly,
            )
            
            end_time = time.time()
            logging.info(f"AI模型响应完成，耗时：{end_time - start_time:.2f}秒")
            
            # 保存原始响应用于调试
            response_log_dir = "/root/autodl-tmp/TravelContentCreator/log/judge_responses"
            os.makedirs(response_log_dir, exist_ok=True)
            response_log_file = f"{response_log_dir}/response_{int(time.time())}.txt"
            with open(response_log_file, "w", encoding="utf-8") as f:
                f.write(result)
            logging.info(f"原始响应已保存到: {response_log_file}")
            
            # 提取修改后的内容
            modified_content = self._extract_modified_content(result)
            if modified_content:
                logging.info("成功提取修改后的内容")
                # 添加judge_success字段
                modified_content["judge_success"] = True
                return modified_content
            else:
                logging.error("无法从响应中提取有效内容")
                # 尝试使用原始内容并标记审核失败
                if isinstance(content, dict) and "title" in content and "content" in content:
                    return {
                        "title": content.get("title", "提取失败"),
                        "content": content.get("content", "无法从响应中提取有效内容"),
                        "judge_success": False
                    }
                return {
                    "title": "提取失败", 
                    "content": "无法从响应中提取有效内容",
                    "judge_success": False
                }
        
        except Exception as e:
            logging.exception(f"审核过程中出错: {e}")
            return {
                "title": "审核失败", 
                "content": f"审核过程中出错: {str(e)}",
                "judge_success": False
            }
    
    def _build_user_prompt(self, product_info, content_gen):
        """
        构建用户提示词
        
        Args:
            product_info: 产品资料
            content_gen: 需要审核的内容
            
        Returns:
            str: 构建好的用户提示词
        """
        return f"""
## 产品资料（真实信息，作为判断依据）:
{product_info}

## 运营生成的文案（需要审核的内容）:
{content_gen}
"""
    
    def _extract_modified_content(self, result_text):
        """从检测结果文本中提取修改后的文案内容"""
        try:
            processed_text = result_text # Work on a copy of the input text
            # 记录原始文本前100个字符用于调试
            logging.debug(f"原始响应文本前100字符: {result_text[:100]}")
            
            if "</think>" in processed_text:
                processed_text = processed_text.split("</think>", 1)[1].strip()
                logging.debug("检测到</think>标签并分离内容")

            # Attempt 1: Parse as JSON from the processed text
            json_start = processed_text.find('{')
            json_end = processed_text.rfind('}') + 1
            if json_start >= 0 and json_end > json_start:
                json_str = processed_text[json_start:json_end]
                logging.debug(f"找到JSON字符串，长度: {len(json_str)}，前100字符: {json_str[:100]}")
                
                # Clean control characters that might break JSON parsing
                json_str_cleaned = re.sub(r'[\x00-\x1F\x7F]', '', json_str)
                try:
                    content_json = json.loads(json_str_cleaned)
                    if "title" in content_json and "content" in content_json:
                        logging.info("Successfully parsed JSON content from AI response.")
                        return {
                            "title": content_json["title"].strip(),
                            "content": content_json["content"].strip()
                        }
                except json.JSONDecodeError as e:
                    logging.warning(f"JSON parsing failed for substring: '{json_str_cleaned[:100]}...'. Error: {e}. Will attempt regex extraction.")

            # Attempt 2: Regex on the processed_text (which might have had </think> stripped)
            # 修复正则表达式，移除多余的反斜杠
            logging.debug("尝试使用正则表达式提取")
            title_match = re.search(r'"title":\s*"([^"]*)"', processed_text)
            content_match = re.search(r'"content":\s*"([^"]*)"', processed_text)
            
            if title_match and content_match:
                logging.info("Successfully extracted title/content using regex.")
                return {
                    "title": title_match.group(1).strip(),
                    "content": content_match.group(1).strip()
                }
            
            # Attempt 3: Try finding content with single quotes
            logging.debug("尝试查找使用单引号的内容")
            title_match = re.search(r'"title":\s*\'([^\']*)\'', processed_text)
            content_match = re.search(r'"content":\s*\'([^\']*)\'', processed_text)
            
            if title_match and content_match:
                logging.info("Successfully extracted title/content using single-quote regex.")
                return {
                    "title": title_match.group(1).strip(),
                    "content": content_match.group(1).strip()
                }
            
            # Final attempt: Look for key-value pairs without standard JSON formatting
            logging.debug("尝试非标准格式提取")
            title_pattern = re.compile(r'["""]?title["""]?[:：]\s*["""]([^"""]+)["""]', re.IGNORECASE)
            content_pattern = re.compile(r'["""]?content["""]?[:：]\s*["""]([^"""]+)["""]', re.IGNORECASE)
            
            title_match = title_pattern.search(processed_text)
            content_match = content_pattern.search(processed_text)
            
            if title_match and content_match:
                logging.info("提取到标题和内容（使用灵活模式匹配）")
                return {
                    "title": title_match.group(1).strip(),
                    "content": content_match.group(1).strip()
                }
            
            logging.warning(f"所有提取方法失败，响应前300字符: {processed_text[:300]}...")
            return None # Fallback if all extraction methods fail

        except Exception as e:
            logging.error(f"Unexpected error during content extraction: {e}\n{traceback.format_exc()}")
            return None

    def test_extraction_from_file(self, response_file_path):
        """
        从文件中读取响应并测试提取功能
        
        Args:
            response_file_path: 响应文件路径
            
        Returns:
            dict: 提取结果
        """
        try:
            logging.info(f"从文件测试提取: {response_file_path}")
            with open(response_file_path, 'r', encoding='utf-8') as f:
                response_text = f.read()
            
            result = self._extract_modified_content(response_text)
            if result:
                logging.info(f"成功从文件提取内容: {result.get('title', '')[:30]}...")
                return {"success": True, "result": result}
            else:
                logging.error(f"从文件中提取内容失败")
                return {"success": False, "error": "提取失败"}
        
        except Exception as e:
            logging.exception(f"测试提取时发生错误: {e}")
            return {"success": False, "error": str(e)}