From fa5f4f5a3ccea14122eebf4966f00020c825e140 Mon Sep 17 00:00:00 2001 From: jinye_huang Date: Fri, 11 Jul 2025 16:54:07 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86=E5=AE=A1=E6=A0=B8ap?= =?UTF-8?q?i?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../__pycache__/tweet.cpython-312.pyc | Bin 11678 -> 11839 bytes api/services/tweet.py | 5 +- .../text_generator.cpython-312.pyc | Bin 0 -> 3716 bytes .../content_generator.cpython-312.pyc | Bin 4824 -> 7711 bytes .../content_judger.cpython-312.pyc | Bin 5963 -> 9408 bytes .../topic_generator.cpython-312.pyc | Bin 4668 -> 7114 bytes tweet/content_generator.py | 57 +++++++++++- tweet/content_judger.py | 82 ++++++++++++++++++ tweet/topic_generator.py | 56 +++++++++++- 9 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 poster/__pycache__/text_generator.cpython-312.pyc diff --git a/api/services/__pycache__/tweet.cpython-312.pyc b/api/services/__pycache__/tweet.cpython-312.pyc index 7838a586a14ec2ac149736a459d740eba7d4e5ac..4858d9bfd3d2d4e60c326da0e232a7757e539e10 100644 GIT binary patch delta 850 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 E4{{A#r2qf` literal 0 HcmV?d00001 diff --git a/tweet/__pycache__/content_generator.cpython-312.pyc b/tweet/__pycache__/content_generator.cpython-312.pyc index f159e17a82fe6ee1a61ea02cb36bee8639c09081..f25325917b91f38ba139cfd788a3856109ca69fd 100644 GIT binary patch delta 2464 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 K-bH|V?Ee6_Pcl#d delta 863 zcmZ9K&1(}u7{+&!O|sdqHc3s|qy=l*rdvx8J$R97QEb6dJ?LdYmYChdExXw;vrC)y zP@x{wQ_FbhMG95vp$JMr5G>vmLGd;hFV@ndAAf)|yQ!da`0c#!y!*^M^UVA6Z%5P* ziXw7!d|mPG?#ml$KX|rLsjLFd1SapKTtOGYdBRD%qAt3UE`@Q@kzGYs!g8E3{*zF9>!z=|6o0f0Xy;j3+ z!Zb@HyFreXuyYf&4L!H*8+QWRF)awyu&iB!$buSe0a;E1{#Aszy)}M2SzIpoUfZr4 zsDpgVH6o3wzvM6Di_+y$Ee^|UhY^NRius#?Og~5W9v*FP9zNds{$O3hJJOkBA!NYX zq5&<`_FBkdLIM6EX^IAjU@g@RyVdXlT#?Ud%Tl;AsxBa}738TX)jD{z6^S0adHwC( zlY&A=mcHD6UC|AZ|-a&AJwpBtpKm#m&Nf_lB#>qs@81Cwk1*+b$twb2%S{|-*!+n zasox(c5@Beu?*XbdSx~cIdU&@IkG%WFJsPYHt7?Xr6q8Zf%Q@PuXiF`a6L0{tSNX4 ZFP4V*$uHa_-Yk`SW&z0m Dict[str, Any]: + """ + 使用已构建的提示词生成内容 + + Args: + topic: 选题信息字典 + system_prompt: 已构建好的系统提示词 + user_prompt: 已构建好的用户提示词 + + Returns: + 包含生成内容的字典 + """ + topic_index = topic.get('index', 'N/A') + logger.info(f"使用预构建提示词为选题 {topic_index} 生成内容...") + + # 保存提示以供调试 + output_dir = self.output_manager.get_topic_dir(topic_index) + self.output_manager.save_text(system_prompt, "content_system_prompt.txt", subdir=output_dir.name) + self.output_manager.save_text(user_prompt, "content_user_prompt.txt", subdir=output_dir.name) + + # 获取模型参数 + model_params = {} + if hasattr(self.content_config, 'model') and isinstance(self.content_config.model, dict): + model_params = { + 'temperature': self.content_config.model.get('temperature'), + 'top_p': self.content_config.model.get('top_p'), + 'presence_penalty': self.content_config.model.get('presence_penalty') + } + # 移除None值 + model_params = {k: v for k, v in model_params.items() if v is not None} + + # 调用AI + try: + raw_result, _, _, _ = await self.ai_agent.generate_text( + system_prompt=system_prompt, + user_prompt=user_prompt, + use_stream=True, + stage="内容生成", + **model_params + ) + self.output_manager.save_text(raw_result, "content_raw_response.txt", subdir=output_dir.name) + except Exception as e: + logger.critical(f"为选题 {topic_index} 生成内容时AI调用失败: {e}", exc_info=True) + return {"error": str(e)} + + # 解析和保存结果 + content_data = process_llm_json_text(raw_result) if content_data: self.output_manager.save_json(content_data, "article.json", subdir=output_dir.name) logger.info(f"成功为选题 {topic_index} 生成并保存内容。") diff --git a/tweet/content_judger.py b/tweet/content_judger.py index 7bf5743..b62b25a 100644 --- a/tweet/content_judger.py +++ b/tweet/content_judger.py @@ -75,6 +75,88 @@ class ContentJudger: topic=topic ) + # 保存提示词 + if self.output_manager: + self.output_manager.save_text(system_prompt, f"{topic_dir}/judger_system_prompt.txt") + self.output_manager.save_text(user_prompt, f"{topic_dir}/judger_user_prompt.txt") + + # 获取模型参数 + model_params = {} + if hasattr(self.content_config, 'judger_model') and isinstance(self.content_config.judger_model, dict): + model_params = { + 'temperature': self.content_config.judger_model.get('temperature'), + 'top_p': self.content_config.judger_model.get('top_p'), + 'presence_penalty': self.content_config.judger_model.get('presence_penalty') + } + # 移除None值 + model_params = {k: v for k, v in model_params.items() if v is not None} + + # 2. 调用AI进行审核 + try: + raw_result, _, _, _ = await self.ai_agent.generate_text( + system_prompt=system_prompt, + user_prompt=user_prompt, + use_stream=True, + stage="内容审核", + **model_params + ) + + # 保存原始响应 + if self.output_manager: + self.output_manager.save_text(raw_result, f"{topic_dir}/judger_raw_response.txt") + + except Exception as e: + logger.critical(f"内容审核时AI调用失败: {e}", exc_info=True) + return {"judge_success": False, "error": str(e)} + + # 3. 解析结果 + judged_data = process_llm_json_text(raw_result) + if judged_data and isinstance(judged_data, dict) and "title" in judged_data and "content" in judged_data: + judged_data["judge_success"] = True + + # 直接使用原始内容中的标签 + if original_tag: + judged_data["tag"] = original_tag + # 如果原始内容中没有标签,则使用默认标签 + logger.info(f"内容审核成功完成,使用标签: {judged_data.get('tag', [])}") + + # 保存审核后的内容 + if self.output_manager: + self.output_manager.save_json(judged_data, f"{topic_dir}/article_judged.json") + + return judged_data + else: + logger.warning(f"审核响应JSON格式不正确或缺少键") + return {"judge_success": False, "error": "Invalid JSON response", "raw_response": raw_result} + + async def judge_content_with_prompt(self, generated_content: Union[str, Dict[str, Any]], topic: Dict[str, Any], system_prompt: str, user_prompt: str) -> Dict[str, Any]: + """ + 使用预构建的提示词审核生成的内容 + + Args: + generated_content: 已生成的原始内容(JSON字符串或字典对象) + topic: 与内容相关的原始选题字典 + system_prompt: 系统提示词 + user_prompt: 用户提示词 + + Returns: + 一个包含审核结果的字典 + """ + logger.info("开始使用预构建提示词审核生成的内容...") + + # 获取主题索引,用于保存文件 + topic_index = topic.get('index', 'unknown') + topic_dir = f"topic_{topic_index}" + + # 从原始内容中提取tag + original_tag = [] + original_content = process_llm_json_text(generated_content) + if original_content and isinstance(original_content, dict) and "tag" in original_content: + original_tag = original_content.get("tag", []) + logger.info(f"从原始内容中提取到标签: {original_tag}") + else: + logger.warning("从原始内容提取标签失败") + # 保存提示词 if self.output_manager: self.output_manager.save_text(system_prompt, f"{topic_dir}/judger_system_prompt.txt") diff --git a/tweet/topic_generator.py b/tweet/topic_generator.py index 43a6ec0..c2ebdee 100644 --- a/tweet/topic_generator.py +++ b/tweet/topic_generator.py @@ -6,7 +6,7 @@ """ import logging -from typing import Dict, Any, List, Optional +from typing import Dict, Any, List, Optional, Tuple from core.ai import AIAgent from core.config import ConfigManager, GenerateTopicConfig @@ -90,5 +90,59 @@ class TopicGenerator: logger.info(f"成功生成并保存 {len(topics)} 个选题") return topics + + async def generate_topics_with_prompt(self, system_prompt: str, user_prompt: str) -> Optional[List[Dict[str, Any]]]: + """ + 使用预构建的提示词生成选题 + + Args: + system_prompt: 已构建好的系统提示词 + user_prompt: 已构建好的用户提示词 + + Returns: + 生成的选题列表,如果失败则返回None + """ + logger.info("使用预构建提示词开始执行选题生成流程...") + + # 保存提示以供调试 + self.output_manager.save_text(system_prompt, "topic_system_prompt.txt") + self.output_manager.save_text(user_prompt, "topic_user_prompt.txt") + + # 获取模型参数 + model_params = {} + if hasattr(self.config, 'model') and isinstance(self.config.model, dict): + model_params = { + 'temperature': self.config.model.get('temperature'), + 'top_p': self.config.model.get('top_p'), + 'presence_penalty': self.config.model.get('presence_penalty') + } + # 移除None值 + model_params = {k: v for k, v in model_params.items() if v is not None} + + # 调用AI生成 + try: + raw_result, _, _, _ = await self.ai_agent.generate_text( + system_prompt=system_prompt, + user_prompt=user_prompt, + use_stream=True, + stage="选题生成", + **model_params + ) + self.output_manager.save_text(raw_result, "topics_raw_response.txt") + except Exception as e: + logger.critical(f"AI调用失败,无法生成选题: {e}", exc_info=True) + return None + + # 解析结果 + topics = self.parser.parse(raw_result) + if not topics: + logger.error("未能从AI响应中解析出任何有效选题") + return None + + # 保存结果 + self.output_manager.save_json(topics, "topics.json") + logger.info(f"成功生成并保存 {len(topics)} 个选题") + + return topics