diff --git a/core/__pycache__/__init__.cpython-310.pyc b/core/__pycache__/__init__.cpython-310.pyc index 1f64f05..31fef20 100644 Binary files a/core/__pycache__/__init__.cpython-310.pyc and b/core/__pycache__/__init__.cpython-310.pyc differ diff --git a/core/__pycache__/__init__.cpython-312.pyc b/core/__pycache__/__init__.cpython-312.pyc index cf3c617..c380f47 100644 Binary files a/core/__pycache__/__init__.cpython-312.pyc and b/core/__pycache__/__init__.cpython-312.pyc differ diff --git a/core/__pycache__/contentGen.cpython-312.pyc b/core/__pycache__/contentGen.cpython-312.pyc index aa6f51f..da08a84 100644 Binary files a/core/__pycache__/contentGen.cpython-312.pyc and b/core/__pycache__/contentGen.cpython-312.pyc differ diff --git a/main.py b/main.py index 3997178..b180aa0 100644 --- a/main.py +++ b/main.py @@ -35,11 +35,18 @@ def load_config(config_path="poster_gen_config.json"): with open(config_path, 'r', encoding='utf-8') as f: config = json.load(f) # Basic validation (can be expanded) - required_keys = ["api_url", "model", "api_key", "resource_dir", "prompts_dir", "output_dir", "num", "variants", "topic_system_prompt", "topic_user_prompt", "content_system_prompt", "image_base_dir"] + required_keys = ["api_url", "model", "api_key", "resource_dir", "output_dir", "num", "variants", "topic_system_prompt", "topic_user_prompt", "content_system_prompt", "image_base_dir"] if not all(key in config for key in required_keys): missing_keys = [key for key in required_keys if key not in config] print(f"Error: Config file '{config_path}' is missing required keys: {missing_keys}") sys.exit(1) + + # 验证prompts_dir或prompts_config至少有一个存在 + if not ("prompts_dir" in config + or "prompts_config" in config): + print(f"Error: Config file '{config_path}' must contain either 'prompts_dir' or 'prompts_config'") + sys.exit(1) + # Resolve relative paths based on config location or a defined base path if necessary # For simplicity, assuming paths in config are relative to project root or absolute return config @@ -77,7 +84,7 @@ def generate_content_and_posters_step(config, run_id, topics_list, output_handle topic_system_prompt_path=config.get("topic_system_prompt"), topic_user_prompt_path=config.get("topic_user_prompt"), content_system_prompt_path=config.get("content_system_prompt"), - prompts_dir=config.get("prompts_dir"), + prompts_config=config.get("prompts_config"), # 新的配置方式 resource_dir_config=config.get("resource_dir", []), topic_gen_num=config.get("num", 1), # Topic gen num/date used by topic prompts topic_gen_date=config.get("date", "") diff --git a/poster_gen_config.json b/poster_gen_config.json index 6718ed1..64f0c01 100644 --- a/poster_gen_config.json +++ b/poster_gen_config.json @@ -15,6 +15,34 @@ "topic_user_prompt": "./SelectPrompt/userPrompt.txt", "content_system_prompt": "./genPrompts/systemPrompt.txt", "poster_content_system_prompt": "./genPrompts/poster_content_systemPrompt.txt", + "prompts_config": [ + { + "type": "Style", + "file_path": [ + "./genPrompts/Style/攻略风文案提示词.txt", + "./genPrompts/Style/轻奢风文案提示词.txt", + "./genPrompts/Style/极力推荐风文案提示词.txt", + "./genPrompts/Style/美食风文案提示词.txt" + ] + }, + { + "type": "Demand", + "file_path": [ + "./genPrompts/Demand/学生党文旅需求.txt", + "./genPrompts/Demand/情侣向文旅需求.txt", + "./genPrompts/Demand/职场人文旅需求.txt", + "./genPrompts/Demand/亲子向文旅需求.txt", + "./genPrompts/Demand/周边游文旅需求.txt", + "./genPrompts/Demand/夕阳红文旅需求.txt" + ] + }, + { + "type": "Refer", + "file_path": [ + "./genPrompts/Refer/标题参考格式.txt" + ] + } + ], "resource_dir": [ { "type": "Object", @@ -38,7 +66,6 @@ ] } ], - "prompts_dir": "./genPrompts", "output_dir": "./result", "image_base_dir": "/root/autodl-tmp/TravelContentCreator/hotel_img", "poster_assets_base_dir": "/root/autodl-tmp/poster_baseboard_0403", diff --git a/test_prompt_manager.py b/test_prompt_manager.py new file mode 100644 index 0000000..c9d61f0 --- /dev/null +++ b/test_prompt_manager.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import json +import os +import logging +from utils.prompt_manager import PromptManager + +# 设置日志 +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +def test_prompt_manager(): + """测试新的PromptManager配置方式""" + logger.info("=== 开始测试PromptManager ===") + + # 加载配置文件 + try: + with open("poster_gen_config.json", "r", encoding="utf-8") as f: + config = json.load(f) + except Exception as e: + logger.error(f"加载配置文件失败: {e}") + return + + # 创建PromptManager实例 + try: + # 使用新的prompts_config配置 + prompt_manager = PromptManager( + topic_system_prompt_path=config.get("topic_system_prompt"), + topic_user_prompt_path=config.get("topic_user_prompt"), + content_system_prompt_path=config.get("content_system_prompt"), + prompts_config=config.get("prompts_config"), # 新的配置方式 + resource_dir_config=config.get("resource_dir", []), + topic_gen_num=config.get("num", 1), + topic_gen_date=config.get("date", "") + ) + logger.info("成功创建PromptManager实例") + except Exception as e: + logger.error(f"创建PromptManager实例失败: {e}") + return + + # 测试1: 生成topic提示词 + try: + logger.info("测试1: 生成topic提示词") + system_prompt, user_prompt = prompt_manager.get_topic_prompts() + if system_prompt and user_prompt: + logger.info(f"成功生成topic提示词: 系统提示词 ({len(system_prompt)} 字符), 用户提示词 ({len(user_prompt)} 字符)") + else: + logger.error("生成topic提示词失败,返回了None") + except Exception as e: + logger.error(f"测试topic提示词生成时出错: {e}") + + # 测试2: 测试Style文件加载 + try: + logger.info("测试2: 测试Style文件加载") + styles = ["攻略风文案提示词", "轻奢风文案提示词", "极力推荐风文案提示词", "美食风文案提示词"] + + for style in styles: + content = prompt_manager._get_style_content(style) + if content: + logger.info(f"成功加载Style文件 '{style}' ({len(content)} 字符)") + else: + logger.warning(f"未能加载Style文件 '{style}'") + except Exception as e: + logger.error(f"测试Style文件加载时出错: {e}") + + # 测试3: 测试Demand文件加载 + try: + logger.info("测试3: 测试Demand文件加载") + demands = ["学生党文旅需求", "情侣向文旅需求", "职场人文旅需求", "亲子向文旅需求", "周边游文旅需求", "夕阳红文旅需求"] + + for demand in demands: + content = prompt_manager._get_demand_content(demand) + if content: + logger.info(f"成功加载Demand文件 '{demand}' ({len(content)} 字符)") + else: + logger.warning(f"未能加载Demand文件 '{demand}'") + except Exception as e: + logger.error(f"测试Demand文件加载时出错: {e}") + + # 测试4: 测试Refer文件加载 + try: + logger.info("测试4: 测试Refer文件加载") + refer_content = prompt_manager._get_all_refer_contents() + if refer_content: + logger.info(f"成功加载所有Refer文件内容 ({len(refer_content)} 字符)") + else: + logger.warning("未能加载任何Refer文件内容") + except Exception as e: + logger.error(f"测试Refer文件加载时出错: {e}") + + # 测试5: 测试内容提示词生成 + try: + logger.info("测试5: 测试内容提示词生成") + + # 创建一个示例topic + mock_topic = { + "index": 1, + "logic": "这是一个测试的逻辑描述", + "object": "中山温泉宾馆", + "product": "", + "product_logic": "", + "style": "轻奢风文案提示词", + "style_logic": "应该用轻奢的风格来描述", + "target_audience": "职场人文旅需求", + "target_audience_logic": "针对职场人的需求" + } + + system_prompt, user_prompt = prompt_manager.get_content_prompts(mock_topic) + if system_prompt and user_prompt: + logger.info(f"成功生成内容提示词: 系统提示词 ({len(system_prompt)} 字符), 用户提示词 ({len(user_prompt)} 字符)") + + # 检查提示词中是否包含预期的内容 + expected_phrases = [ + "Demand Logic", + "Object信息", + "Style Info", + "Target Audience Info", + "Refer Info" + ] + + for phrase in expected_phrases: + if phrase in user_prompt: + logger.info(f"用户提示词中包含 '{phrase}'") + else: + logger.warning(f"用户提示词中缺少 '{phrase}'") + else: + logger.error("生成内容提示词失败,返回了None") + except Exception as e: + logger.error(f"测试内容提示词生成时出错: {e}") + + logger.info("=== 测试PromptManager完成 ===") + +if __name__ == "__main__": + test_prompt_manager() \ No newline at end of file diff --git a/utils/__pycache__/__init__.cpython-310.pyc b/utils/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..ff9a401 Binary files /dev/null and b/utils/__pycache__/__init__.cpython-310.pyc differ diff --git a/utils/__pycache__/content_generator.cpython-312.pyc b/utils/__pycache__/content_generator.cpython-312.pyc index 4afd604..af0811d 100644 Binary files a/utils/__pycache__/content_generator.cpython-312.pyc and b/utils/__pycache__/content_generator.cpython-312.pyc differ diff --git a/utils/__pycache__/prompt_manager.cpython-312.pyc b/utils/__pycache__/prompt_manager.cpython-312.pyc index 1ee4aad..c86a92e 100644 Binary files a/utils/__pycache__/prompt_manager.cpython-312.pyc and b/utils/__pycache__/prompt_manager.cpython-312.pyc differ diff --git a/utils/__pycache__/resource_loader.cpython-310.pyc b/utils/__pycache__/resource_loader.cpython-310.pyc new file mode 100644 index 0000000..d1e1097 Binary files /dev/null and b/utils/__pycache__/resource_loader.cpython-310.pyc differ diff --git a/utils/__pycache__/tweet_generator.cpython-310.pyc b/utils/__pycache__/tweet_generator.cpython-310.pyc new file mode 100644 index 0000000..d935420 Binary files /dev/null and b/utils/__pycache__/tweet_generator.cpython-310.pyc differ diff --git a/utils/__pycache__/tweet_generator.cpython-312.pyc b/utils/__pycache__/tweet_generator.cpython-312.pyc index 7a62d6a..d852dc6 100644 Binary files a/utils/__pycache__/tweet_generator.cpython-312.pyc and b/utils/__pycache__/tweet_generator.cpython-312.pyc differ diff --git a/utils/prompt_manager.py b/utils/prompt_manager.py index bcbf72f..372beb8 100644 --- a/utils/prompt_manager.py +++ b/utils/prompt_manager.py @@ -16,46 +16,352 @@ class PromptManager: topic_system_prompt_path: str, topic_user_prompt_path: str, content_system_prompt_path: str, - prompts_dir: str, - resource_dir_config: list, + prompts_dir: str = None, # 兼容旧配置 + prompts_config: list = None, # 新的配置方式 + resource_dir_config: list = None, topic_gen_num: int = 1, # Default values if needed topic_gen_date: str = "" ): self.topic_system_prompt_path = topic_system_prompt_path self.topic_user_prompt_path = topic_user_prompt_path self.content_system_prompt_path = content_system_prompt_path - self.prompts_dir = prompts_dir - self.resource_dir_config = resource_dir_config + self.prompts_dir = prompts_dir # 保留兼容旧配置 + self.prompts_config = prompts_config or [] # 新的配置方式 + self.resource_dir_config = resource_dir_config or [] self.topic_gen_num = topic_gen_num self.topic_gen_date = topic_gen_date + + # 缓存加载的文件内容 + self._style_cache = {} + self._demand_cache = {} + self._refer_cache = {} + self._system_prompt_cache = {} # 新增:系统提示词缓存 + self._user_prompt_cache = {} # 新增:用户提示词缓存 + self._dateline_cache = None # 新增:日期线缓存 + + # 初始化时预加载配置的文件 + self._preload_prompt_files() + + def _preload_prompt_files(self): + """预加载配置中的提示文件到缓存""" + # 预加载系统提示词和用户提示词文件 + if self.topic_system_prompt_path and os.path.exists(self.topic_system_prompt_path): + content = ResourceLoader.load_file_content(self.topic_system_prompt_path) + if content: + self._system_prompt_cache["topic"] = content + logging.info(f"预加载系统提示词: {self.topic_system_prompt_path}") + + if self.topic_user_prompt_path and os.path.exists(self.topic_user_prompt_path): + content = ResourceLoader.load_file_content(self.topic_user_prompt_path) + if content: + self._user_prompt_cache["topic"] = content + logging.info(f"预加载用户提示词: {self.topic_user_prompt_path}") + + if self.content_system_prompt_path and os.path.exists(self.content_system_prompt_path): + content = ResourceLoader.load_file_content(self.content_system_prompt_path) + if content: + self._system_prompt_cache["content"] = content + logging.info(f"预加载内容系统提示词: {self.content_system_prompt_path}") + + # 预加载日期线文件 + if self.topic_user_prompt_path: + user_prompt_dir = os.path.dirname(self.topic_user_prompt_path) + dateline_path = os.path.join(user_prompt_dir, "2025各月节日宣传节点时间表.md") + if os.path.exists(dateline_path): + self._dateline_cache = ResourceLoader.load_file_content(dateline_path) + logging.info(f"预加载日期线文件: {dateline_path}") + + # 加载prompts_config配置的文件 + if not self.prompts_config: + return + + for config_item in self.prompts_config: + prompt_type = config_item.get("type", "").lower() + file_paths = config_item.get("file_path", []) + + if prompt_type == "style": + for path in file_paths: + if os.path.exists(path): + filename = os.path.basename(path) + content = ResourceLoader.load_file_content(path) + if content: + self._style_cache[filename] = content + name_without_ext = os.path.splitext(filename)[0] + self._style_cache[name_without_ext] = content # 同时缓存不带扩展名的版本 + + elif prompt_type == "demand": + for path in file_paths: + if os.path.exists(path): + filename = os.path.basename(path) + content = ResourceLoader.load_file_content(path) + if content: + self._demand_cache[filename] = content + name_without_ext = os.path.splitext(filename)[0] + self._demand_cache[name_without_ext] = content # 同时缓存不带扩展名的版本 + + elif prompt_type == "refer": + for path in file_paths: + if os.path.exists(path): + filename = os.path.basename(path) + content = ResourceLoader.load_file_content(path) + if content: + self._refer_cache[filename] = content + + def _get_style_content(self, style_name): + """获取Style文件内容,优先从缓存获取,如果不存在则尝试从目录加载""" + # 首先检查缓存 + if style_name in self._style_cache: + return self._style_cache[style_name] + + # 确保有扩展名 + if not style_name.lower().endswith('.txt'): + style_file = f"{style_name}.txt" + else: + style_file = style_name + style_name = os.path.splitext(style_name)[0] # 移除扩展名 + + # 尝试模糊匹配缓存中的文件名 + for cache_key in self._style_cache.keys(): + cache_key_lower = cache_key.lower() + style_name_lower = style_name.lower() + + # 完全匹配 + if cache_key_lower == style_name_lower: + return self._style_cache[cache_key] + + # 部分匹配 + # 攻略风格 + if ("攻略" in style_name_lower or "干货" in style_name_lower) and "攻略" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Style文件: '{cache_key}' 匹配 '{style_name}'") + return self._style_cache[cache_key] + # 轻奢风格 + if "轻奢" in style_name_lower and "轻奢" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Style文件: '{cache_key}' 匹配 '{style_name}'") + return self._style_cache[cache_key] + # 推荐风格 + if ("推荐" in style_name_lower or "种草" in style_name_lower) and "推荐" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Style文件: '{cache_key}' 匹配 '{style_name}'") + return self._style_cache[cache_key] + # 美食风格 + if "美食" in style_name_lower and "美食" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Style文件: '{cache_key}' 匹配 '{style_name}'") + return self._style_cache[cache_key] + + # 如果没有在缓存中找到模糊匹配,尝试从prompts_dir加载 + if self.prompts_dir: + style_path = os.path.join(self.prompts_dir, "Style", style_file) + if os.path.exists(style_path): + content = ResourceLoader.load_file_content(style_path) + if content: + # 保存到缓存 + self._style_cache[style_name] = content + self._style_cache[style_file] = content + return content + + # 如果直接加载失败,尝试列出目录中的所有文件并进行模糊匹配 + style_dir = os.path.join(self.prompts_dir, "Style") + if os.path.isdir(style_dir): + try: + files = os.listdir(style_dir) + style_name_lower = style_name.lower() + + for file in files: + file_lower = file.lower() + # 检查关键词匹配 + matched = False + if ("攻略" in style_name_lower or "干货" in style_name_lower) and "攻略" in file_lower: + matched = True + elif "轻奢" in style_name_lower and "轻奢" in file_lower: + matched = True + elif ("推荐" in style_name_lower or "种草" in style_name_lower) and "推荐" in file_lower: + matched = True + elif "美食" in style_name_lower and "美食" in file_lower: + matched = True + + if matched: + matched_path = os.path.join(style_dir, file) + logging.info(f"模糊匹配 - 在目录中找到部分匹配的Style文件: '{file}' 匹配 '{style_name}'") + content = ResourceLoader.load_file_content(matched_path) + if content: + # 保存到缓存 + self._style_cache[style_name] = content + self._style_cache[file] = content + return content + except Exception as e: + logging.warning(f"尝试列出Style目录内容时出错: {e}") + + return None + + def _get_demand_content(self, demand_name): + """获取Demand文件内容,优先从缓存获取,如果不存在则尝试从目录加载""" + # 首先检查缓存 + if demand_name in self._demand_cache: + return self._demand_cache[demand_name] + + # 确保有扩展名 + if not demand_name.lower().endswith('.txt'): + demand_file = f"{demand_name}.txt" + else: + demand_file = demand_name + demand_name = os.path.splitext(demand_name)[0] # 移除扩展名 + + # 尝试模糊匹配缓存中的文件名 + for cache_key in self._demand_cache.keys(): + cache_key_lower = cache_key.lower() + demand_name_lower = demand_name.lower() + + # 完全匹配 + if cache_key_lower == demand_name_lower: + return self._demand_cache[cache_key] + + # 部分匹配:检查需求名称是否是缓存键的一部分,或者缓存键是否是需求名称的一部分 + # 例如"亲子家庭文旅需求"能匹配到"亲子向文旅需求" + if "亲子" in demand_name_lower and "亲子" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Demand文件: '{cache_key}' 匹配 '{demand_name}'") + return self._demand_cache[cache_key] + if "情侣" in demand_name_lower and "情侣" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Demand文件: '{cache_key}' 匹配 '{demand_name}'") + return self._demand_cache[cache_key] + if "职场" in demand_name_lower and "职场" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Demand文件: '{cache_key}' 匹配 '{demand_name}'") + return self._demand_cache[cache_key] + if "学生" in demand_name_lower and "学生" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Demand文件: '{cache_key}' 匹配 '{demand_name}'") + return self._demand_cache[cache_key] + if "银发" in demand_name_lower and "夕阳红" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Demand文件: '{cache_key}' 匹配 '{demand_name}'") + return self._demand_cache[cache_key] + if "夕阳红" in demand_name_lower and "银发" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Demand文件: '{cache_key}' 匹配 '{demand_name}'") + return self._demand_cache[cache_key] + if "周边" in demand_name_lower and "周边" in cache_key_lower: + logging.info(f"模糊匹配 - 找到部分匹配的Demand文件: '{cache_key}' 匹配 '{demand_name}'") + return self._demand_cache[cache_key] + + # 如果没有在缓存中找到模糊匹配,尝试从prompts_dir加载(向后兼容) + if self.prompts_dir: + demand_path = os.path.join(self.prompts_dir, "Demand", demand_file) + if os.path.exists(demand_path): + content = ResourceLoader.load_file_content(demand_path) + if content: + # 保存到缓存 + self._demand_cache[demand_name] = content + self._demand_cache[demand_file] = content + return content + + # 如果直接加载失败,尝试列出目录中的所有文件并进行模糊匹配 + demand_dir = os.path.join(self.prompts_dir, "Demand") + if os.path.isdir(demand_dir): + try: + files = os.listdir(demand_dir) + demand_name_lower = demand_name.lower() + + for file in files: + file_lower = file.lower() + # 检查关键词匹配 + matched = False + if "亲子" in demand_name_lower and "亲子" in file_lower: + matched = True + elif "情侣" in demand_name_lower and "情侣" in file_lower: + matched = True + elif "职场" in demand_name_lower and "职场" in file_lower: + matched = True + elif "学生" in demand_name_lower and "学生" in file_lower: + matched = True + elif ("银发" in demand_name_lower or "夕阳红" in demand_name_lower) and ("银发" in file_lower or "夕阳红" in file_lower): + matched = True + elif "周边" in demand_name_lower and "周边" in file_lower: + matched = True + + if matched: + matched_path = os.path.join(demand_dir, file) + logging.info(f"模糊匹配 - 在目录中找到部分匹配的Demand文件: '{file}' 匹配 '{demand_name}'") + content = ResourceLoader.load_file_content(matched_path) + if content: + # 保存到缓存 + self._demand_cache[demand_name] = content + self._demand_cache[file] = content + return content + except Exception as e: + logging.warning(f"尝试列出Demand目录内容时出错: {e}") + + # 如果所有尝试都失败 + logging.warning(f"未能找到Demand文件: '{demand_name}',尝试过以下位置: 缓存, {self.prompts_dir}/Demand/") + return None + + def _get_all_refer_contents(self): + """获取所有Refer文件内容""" + # 如果缓存中有内容,先使用缓存 + if self._refer_cache: + refer_content_all = "" + for filename, content in self._refer_cache.items(): + refer_content_all += f"--- Refer File: {filename} ---\n{content}\n\n" + return refer_content_all + + # 如果缓存为空,尝试从prompts_dir加载(向后兼容) + refer_content_all = "" + if self.prompts_dir: + refer_dir = os.path.join(self.prompts_dir, "Refer") + if os.path.isdir(refer_dir): + refer_files = [f for f in os.listdir(refer_dir) if os.path.isfile(os.path.join(refer_dir, f))] + for refer_file in refer_files: + refer_path = os.path.join(refer_dir, refer_file) + content = ResourceLoader.load_file_content(refer_path) + if content: + refer_content_all += f"--- Refer File: {refer_file} ---\n{content}\n\n" + # 保存到缓存 + self._refer_cache[refer_file] = content + + return refer_content_all def get_topic_prompts(self): """Constructs the system and user prompts for topic generation.""" logging.info("Constructing prompts for topic generation...") try: # --- System Prompt --- - if not self.topic_system_prompt_path: - logging.error("Topic system prompt path not provided during PromptManager initialization.") - return None, None - system_prompt = ResourceLoader.load_file_content(self.topic_system_prompt_path) + system_prompt = self._system_prompt_cache.get("topic") if not system_prompt: - logging.error(f"Failed to load topic system prompt from '{self.topic_system_prompt_path}'.") - return None, None + if not self.topic_system_prompt_path: + logging.error("Topic system prompt path not provided during PromptManager initialization.") + return None, None + system_prompt = ResourceLoader.load_file_content(self.topic_system_prompt_path) + if system_prompt: + self._system_prompt_cache["topic"] = system_prompt + else: + logging.error(f"Failed to load topic system prompt from '{self.topic_system_prompt_path}'.") + return None, None # --- User Prompt --- - if not self.topic_user_prompt_path: - logging.error("Topic user prompt path not provided during PromptManager initialization.") - return None, None - base_user_prompt = ResourceLoader.load_file_content(self.topic_user_prompt_path) - if base_user_prompt is None: - logging.error(f"Failed to load base topic user prompt from '{self.topic_user_prompt_path}'.") - return None, None + base_user_prompt = self._user_prompt_cache.get("topic") + if not base_user_prompt: + if not self.topic_user_prompt_path: + logging.error("Topic user prompt path not provided during PromptManager initialization.") + return None, None + base_user_prompt = ResourceLoader.load_file_content(self.topic_user_prompt_path) + if base_user_prompt: + self._user_prompt_cache["topic"] = base_user_prompt + else: + logging.error(f"Failed to load base topic user prompt from '{self.topic_user_prompt_path}'.") + return None, None - # --- Build the dynamic part of the user prompt (Logic moved from prepare_topic_generation) --- + # --- Build the dynamic part of the user prompt --- user_prompt_dynamic = "你拥有的创作资料如下:\n" - # Add genPrompts directory structure - if self.prompts_dir and os.path.isdir(self.prompts_dir): + # 添加prompts_config配置的文件信息 + if self.prompts_config: + for config_item in self.prompts_config: + prompt_type = config_item.get("type", "").lower() + file_paths = config_item.get("file_path", []) + + if file_paths: + user_prompt_dynamic += f"{prompt_type.capitalize()}文件列表:\n" + for path in file_paths: + filename = os.path.basename(path) + user_prompt_dynamic += f"- {filename}\n" + user_prompt_dynamic += "\n" + + # 兼容旧配置:Add genPrompts directory structure + elif self.prompts_dir and os.path.isdir(self.prompts_dir): try: gen_prompts_list = os.listdir(self.prompts_dir) for gen_prompt_folder in gen_prompts_list: @@ -70,7 +376,7 @@ class PromptManager: except OSError as e: logging.warning(f"Could not list base prompts directory {self.prompts_dir}: {e}") else: - logging.warning(f"Prompts directory '{self.prompts_dir}' not found or invalid.") + logging.warning(f"Neither prompts_config nor prompts_dir provided or valid.") # Add resource directory contents for dir_info in self.resource_dir_config: @@ -85,18 +391,21 @@ class PromptManager: logging.warning(f"Could not load resource file {file_path}") # Add dateline information (optional) - user_prompt_dir = os.path.dirname(self.topic_user_prompt_path) - dateline_path = os.path.join(user_prompt_dir, "2025各月节日宣传节点时间表.md") # Consider making this configurable - if os.path.exists(dateline_path): - dateline_content = ResourceLoader.load_file_content(dateline_path) - if dateline_content: - user_prompt_dynamic += f"\n{dateline_content}" + if self._dateline_cache: + user_prompt_dynamic += f"\n{self._dateline_cache}" + else: + user_prompt_dir = os.path.dirname(self.topic_user_prompt_path) + dateline_path = os.path.join(user_prompt_dir, "2025各月节日宣传节点时间表.md") # Consider making this configurable + if os.path.exists(dateline_path): + dateline_content = ResourceLoader.load_file_content(dateline_path) + if dateline_content: + self._dateline_cache = dateline_content + user_prompt_dynamic += f"\n{dateline_content}" # Combine dynamic part, base template, and final parameters user_prompt = user_prompt_dynamic + base_user_prompt user_prompt += f"\n选题数量:{self.topic_gen_num}\n选题日期:{self.topic_gen_date}\n" - # --- End of moved logic --- logging.info(f"Topic prompts constructed. System: {len(system_prompt)} chars, User: {len(user_prompt)} chars.") return system_prompt, user_prompt @@ -110,22 +419,20 @@ class PromptManager: logging.info(f"Constructing content prompts for topic: {topic_item.get('object', 'N/A')}...") try: # --- System Prompt --- - if not self.content_system_prompt_path: - logging.error("Content system prompt path not provided during PromptManager initialization.") - return None, None - system_prompt = ResourceLoader.load_file_content(self.content_system_prompt_path) + system_prompt = self._system_prompt_cache.get("content") if not system_prompt: - logging.error(f"Failed to load content system prompt from '{self.content_system_prompt_path}'.") - return None, None + if not self.content_system_prompt_path: + logging.error("Content system prompt path not provided during PromptManager initialization.") + return None, None + system_prompt = ResourceLoader.load_file_content(self.content_system_prompt_path) + if system_prompt: + self._system_prompt_cache["content"] = system_prompt + else: + logging.error(f"Failed to load content system prompt from '{self.content_system_prompt_path}'.") + return None, None - # --- User Prompt (Logic moved from ResourceLoader.build_user_prompt) --- + # --- User Prompt --- user_prompt = "" - prompts_dir = self.prompts_dir - resource_dir_config = self.resource_dir_config - - if not prompts_dir or not os.path.isdir(prompts_dir): - logging.warning(f"Prompts directory '{prompts_dir}' not found or invalid. Content user prompt might be incomplete.") - # Decide whether to return error or continue with potentially incomplete prompt # 1. 添加Demand部分 (直接使用 topic_item['logic'] 的描述性文本) try: @@ -145,7 +452,7 @@ class PromptManager: matched_object_basename = None # 遍历查找 Object 文件 - for dir_info in resource_dir_config: + for dir_info in self.resource_dir_config: if dir_info.get("type") == "Object": for file_path in dir_info.get("file_path", []): basename = os.path.basename(file_path) @@ -205,7 +512,7 @@ class PromptManager: # Then, load Product Info file product_file_path = None - for dir_info in resource_dir_config: + for dir_info in self.resource_dir_config: if dir_info.get("type") == "Product": for file_path in dir_info.get("file_path", []): if product_name in os.path.basename(file_path): @@ -221,76 +528,48 @@ class PromptManager: logging.warning(f"Product file could not be loaded: {product_file_path}") else: logging.warning(f"Product file path not found in config for: {product_name}") - # Removed KeyError check for product_logic as it's now optional text except KeyError: logging.warning("Warning: Missing 'product' key in topic_item for Product prompt.") except Exception as e: logging.exception("Error processing Product prompt:") - # 4. 添加Style信息 (加载文件 based on topic_item['style'] from Style/ folder) + # 4. 添加Style信息 (加载文件 based on topic_item['style']) try: - style_filename = topic_item.get('style') - if style_filename: - # Ensure .txt extension - if not style_filename.lower().endswith('.txt'): - style_file = f"{style_filename}.txt" - else: - style_file = style_filename - style_path = os.path.join(prompts_dir, "Style", style_file) # Look in Style/ subfolder - style_content = ResourceLoader.load_file_content(style_path) + style_name = topic_item.get('style') + if style_name: + style_content = self._get_style_content(style_name) if style_content: - user_prompt += f"Style Info:\n{style_content}\n" # Changed label for clarity + user_prompt += f"Style Info:\n{style_content}\n" else: - logging.warning(f"Style file not found or empty: {style_path}") + logging.warning(f"Style file not found or empty for: {style_name}") else: logging.warning("Warning: 'style' key missing or empty in topic_item.") except Exception as e: logging.exception("Error processing Style prompt:") - # 5. 添加Target Audience信息 (加载文件 based on topic_item['target_audience'] from Demand/ folder) + # 5. 添加Target Audience信息 (加载文件 based on topic_item['target_audience']) try: - target_audience_filename = topic_item.get('target_audience') - if target_audience_filename: - # Ensure .txt extension (or use the check as done for style) - if not target_audience_filename.lower().endswith('.txt'): - target_audience_file = f"{target_audience_filename}.txt" - else: - target_audience_file = target_audience_filename - # Assuming target audience files are in the 'Demand' subdirectory based on old prompt - # Load from Demand/ subfolder as confirmed - target_audience_path = os.path.join(prompts_dir, "Demand", target_audience_file) - target_audience_content = ResourceLoader.load_file_content(target_audience_path) + target_audience_name = topic_item.get('target_audience') + if target_audience_name: + target_audience_content = self._get_demand_content(target_audience_name) if target_audience_content: user_prompt += f"Target Audience Info:\n{target_audience_content}\n" else: - logging.warning(f"Target Audience file not found or empty: {target_audience_path}") + logging.warning(f"Target Audience file not found or empty for: {target_audience_name}") else: logging.warning("Warning: 'target_audience' key missing or empty in topic_item.") except Exception as e: logging.exception("Error processing Target Audience prompt:") - # 6. 添加Refer信息 (加载 Refer/ 目录下所有文件的内容) + # 6. 添加Refer信息 (加载所有Refer文件的内容) try: - refer_dir = os.path.join(prompts_dir, "Refer") - if os.path.isdir(refer_dir): - refer_content_all = "" - refer_files = [f for f in os.listdir(refer_dir) if os.path.isfile(os.path.join(refer_dir, f))] - logging.info(f"Found {len(refer_files)} files in Refer directory: {refer_files}") - for refer_file in refer_files: - refer_path = os.path.join(refer_dir, refer_file) - content = ResourceLoader.load_file_content(refer_path) - if content: - refer_content_all += f"--- Refer File: {refer_file} ---\n{content}\n\n" - else: - logging.warning(f"Could not load Refer file: {refer_path}") - if refer_content_all: - user_prompt += f"Refer Info:\n{refer_content_all}" - else: - logging.warning("No content loaded from Refer directory.") + refer_content_all = self._get_all_refer_contents() + if refer_content_all: + user_prompt += f"Refer Info:\n{refer_content_all}" else: - logging.warning(f"Refer directory not found: {refer_dir}") + logging.warning("No content loaded from Refer files.") except Exception as e: - logging.exception("Error processing Refer directory:") + logging.exception("Error processing Refer files:") # --- End of prompt construction logic --- diff --git a/utils/tweet_generator.py b/utils/tweet_generator.py index 4ac2537..8d1f759 100644 --- a/utils/tweet_generator.py +++ b/utils/tweet_generator.py @@ -289,6 +289,7 @@ def run_topic_generation_pipeline(config, run_id=None): topic_user_prompt_path = config.get("topic_user_prompt") content_sys_prompt_path = config.get("content_system_prompt") # 虽然这里不用,但 PromptManager 可能需要 prompts_dir_path = config.get("prompts_dir") + prompts_config = config.get("prompts_config") # 新增:获取prompts_config配置 resource_config = config.get("resource_dir", []) topic_num = config.get("num", 1) topic_date = config.get("date", "") @@ -299,6 +300,7 @@ def run_topic_generation_pipeline(config, run_id=None): topic_user_prompt_path=topic_user_prompt_path, content_system_prompt_path=content_sys_prompt_path, prompts_dir=prompts_dir_path, + prompts_config=prompts_config, # 新增:传入prompts_config配置 resource_dir_config=resource_config, topic_gen_num=topic_num, topic_gen_date=topic_date