2025-04-22 14:19:21 +08:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
"""
|
|
|
|
|
Manages the construction of prompts for different AI generation tasks.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import os
|
|
|
|
|
import traceback
|
2025-04-22 17:36:29 +08:00
|
|
|
import logging # Add logging
|
2025-04-22 14:19:21 +08:00
|
|
|
from .resource_loader import ResourceLoader # Use relative import within the same package
|
|
|
|
|
|
|
|
|
|
class PromptManager:
|
|
|
|
|
"""Handles the loading and construction of prompts."""
|
|
|
|
|
|
2025-04-22 18:14:31 +08:00
|
|
|
def __init__(self,
|
|
|
|
|
topic_system_prompt_path: str,
|
|
|
|
|
topic_user_prompt_path: str,
|
|
|
|
|
content_system_prompt_path: str,
|
|
|
|
|
prompts_dir: str,
|
|
|
|
|
resource_dir_config: list,
|
|
|
|
|
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.topic_gen_num = topic_gen_num
|
|
|
|
|
self.topic_gen_date = topic_gen_date
|
2025-04-22 14:19:21 +08:00
|
|
|
|
|
|
|
|
def get_topic_prompts(self):
|
|
|
|
|
"""Constructs the system and user prompts for topic generation."""
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.info("Constructing prompts for topic generation...")
|
2025-04-22 14:19:21 +08:00
|
|
|
try:
|
|
|
|
|
# --- System Prompt ---
|
2025-04-22 18:14:31 +08:00
|
|
|
if not self.topic_system_prompt_path:
|
|
|
|
|
logging.error("Topic system prompt path not provided during PromptManager initialization.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
2025-04-22 18:14:31 +08:00
|
|
|
system_prompt = ResourceLoader.load_file_content(self.topic_system_prompt_path)
|
2025-04-22 14:19:21 +08:00
|
|
|
if not system_prompt:
|
2025-04-22 18:14:31 +08:00
|
|
|
logging.error(f"Failed to load topic system prompt from '{self.topic_system_prompt_path}'.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
# --- User Prompt ---
|
2025-04-22 18:14:31 +08:00
|
|
|
if not self.topic_user_prompt_path:
|
|
|
|
|
logging.error("Topic user prompt path not provided during PromptManager initialization.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
2025-04-22 18:14:31 +08:00
|
|
|
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}'.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
# --- Build the dynamic part of the user prompt (Logic moved from prepare_topic_generation) ---
|
|
|
|
|
user_prompt_dynamic = "你拥有的创作资料如下:\n"
|
|
|
|
|
|
|
|
|
|
# Add genPrompts directory structure
|
2025-04-22 18:14:31 +08:00
|
|
|
if self.prompts_dir and os.path.isdir(self.prompts_dir):
|
2025-04-22 14:19:21 +08:00
|
|
|
try:
|
2025-04-22 18:14:31 +08:00
|
|
|
gen_prompts_list = os.listdir(self.prompts_dir)
|
2025-04-22 14:19:21 +08:00
|
|
|
for gen_prompt_folder in gen_prompts_list:
|
2025-04-22 18:14:31 +08:00
|
|
|
folder_path = os.path.join(self.prompts_dir, gen_prompt_folder)
|
2025-04-22 14:19:21 +08:00
|
|
|
if os.path.isdir(folder_path):
|
|
|
|
|
try:
|
|
|
|
|
# List files, filter out subdirs if needed
|
|
|
|
|
gen_prompts_files = [f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))]
|
|
|
|
|
user_prompt_dynamic += f"{gen_prompt_folder}\n{gen_prompts_files}\n"
|
|
|
|
|
except OSError as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Could not list directory {folder_path}: {e}")
|
2025-04-22 14:19:21 +08:00
|
|
|
except OSError as e:
|
2025-04-22 18:14:31 +08:00
|
|
|
logging.warning(f"Could not list base prompts directory {self.prompts_dir}: {e}")
|
2025-04-22 14:19:21 +08:00
|
|
|
else:
|
2025-04-22 18:14:31 +08:00
|
|
|
logging.warning(f"Prompts directory '{self.prompts_dir}' not found or invalid.")
|
2025-04-22 14:19:21 +08:00
|
|
|
|
|
|
|
|
# Add resource directory contents
|
2025-04-22 18:14:31 +08:00
|
|
|
for dir_info in self.resource_dir_config:
|
2025-04-22 14:19:21 +08:00
|
|
|
source_type = dir_info.get("type", "UnknownType")
|
|
|
|
|
source_file_paths = dir_info.get("file_path", [])
|
|
|
|
|
for file_path in source_file_paths:
|
|
|
|
|
# Use ResourceLoader's static method
|
|
|
|
|
file_content = ResourceLoader.load_file_content(file_path)
|
|
|
|
|
if file_content:
|
|
|
|
|
user_prompt_dynamic += f"{source_type}信息:\n{os.path.basename(file_path)}\n{file_content}\n\n"
|
|
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Could not load resource file {file_path}")
|
2025-04-22 14:19:21 +08:00
|
|
|
|
|
|
|
|
# Add dateline information (optional)
|
2025-04-22 18:14:31 +08:00
|
|
|
user_prompt_dir = os.path.dirname(self.topic_user_prompt_path)
|
2025-04-22 14:19:21 +08:00
|
|
|
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}"
|
|
|
|
|
|
|
|
|
|
# Combine dynamic part, base template, and final parameters
|
|
|
|
|
user_prompt = user_prompt_dynamic + base_user_prompt
|
|
|
|
|
|
2025-04-22 18:14:31 +08:00
|
|
|
user_prompt += f"\n选题数量:{self.topic_gen_num}\n选题日期:{self.topic_gen_date}\n"
|
2025-04-22 14:19:21 +08:00
|
|
|
# --- End of moved logic ---
|
|
|
|
|
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.info(f"Topic prompts constructed. System: {len(system_prompt)} chars, User: {len(user_prompt)} chars.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return system_prompt, user_prompt
|
|
|
|
|
|
|
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error constructing topic prompts:")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
def get_content_prompts(self, topic_item):
|
|
|
|
|
"""Constructs the system and user prompts for content generation based on a topic item."""
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.info(f"Constructing content prompts for topic: {topic_item.get('object', 'N/A')}...")
|
2025-04-22 14:19:21 +08:00
|
|
|
try:
|
|
|
|
|
# --- System Prompt ---
|
2025-04-22 18:14:31 +08:00
|
|
|
if not self.content_system_prompt_path:
|
|
|
|
|
logging.error("Content system prompt path not provided during PromptManager initialization.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
2025-04-22 18:14:31 +08:00
|
|
|
system_prompt = ResourceLoader.load_file_content(self.content_system_prompt_path)
|
2025-04-22 14:19:21 +08:00
|
|
|
if not system_prompt:
|
2025-04-22 18:14:31 +08:00
|
|
|
logging.error(f"Failed to load content system prompt from '{self.content_system_prompt_path}'.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
|
|
|
|
|
|
|
|
|
# --- User Prompt (Logic moved from ResourceLoader.build_user_prompt) ---
|
|
|
|
|
user_prompt = ""
|
2025-04-22 18:14:31 +08:00
|
|
|
prompts_dir = self.prompts_dir
|
|
|
|
|
resource_dir_config = self.resource_dir_config
|
2025-04-22 14:19:21 +08:00
|
|
|
|
|
|
|
|
if not prompts_dir or not os.path.isdir(prompts_dir):
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Prompts directory '{prompts_dir}' not found or invalid. Content user prompt might be incomplete.")
|
2025-04-22 14:19:21 +08:00
|
|
|
# Decide whether to return error or continue with potentially incomplete prompt
|
|
|
|
|
|
2025-04-22 15:12:46 +08:00
|
|
|
# 1. 添加Demand部分 (直接使用 topic_item['logic'] 的描述性文本)
|
2025-04-22 14:19:21 +08:00
|
|
|
try:
|
2025-04-22 15:12:46 +08:00
|
|
|
demand_description = topic_item.get('logic')
|
|
|
|
|
if demand_description:
|
|
|
|
|
user_prompt += f"Demand Logic:\n{demand_description}\n"
|
2025-04-22 15:02:00 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning("Warning: 'logic' key missing or empty in topic_item for Demand prompt.")
|
2025-04-22 14:19:21 +08:00
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error processing Demand description:")
|
2025-04-22 14:19:21 +08:00
|
|
|
|
|
|
|
|
# 2. 添加Object信息 (based on topic_item['object'])
|
|
|
|
|
try:
|
|
|
|
|
object_name_base = topic_item['object'] # This might be '景点信息-XXX.txt'
|
|
|
|
|
object_file_path = None
|
|
|
|
|
# Find the full path for the object file from config
|
|
|
|
|
for dir_info in resource_dir_config:
|
|
|
|
|
if dir_info.get("type") == "Object":
|
|
|
|
|
for file_path in dir_info.get("file_path", []):
|
|
|
|
|
# Match basename, assuming topic_item['object'] is the basename
|
2025-04-22 15:02:00 +08:00
|
|
|
# if os.path.basename(file_path) == object_name_base:
|
|
|
|
|
# Use containment check instead of exact match
|
|
|
|
|
if object_name_base in os.path.basename(file_path):
|
2025-04-22 14:19:21 +08:00
|
|
|
object_file_path = file_path
|
|
|
|
|
break
|
|
|
|
|
if object_file_path: break
|
|
|
|
|
|
|
|
|
|
if object_file_path:
|
|
|
|
|
object_content = ResourceLoader.load_file_content(object_file_path)
|
|
|
|
|
if object_content:
|
2025-04-22 17:36:29 +08:00
|
|
|
user_prompt += f"Object Info:\n{object_content}\n"
|
2025-04-22 14:19:21 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Object file could not be loaded: {object_file_path}")
|
2025-04-22 14:19:21 +08:00
|
|
|
else:
|
|
|
|
|
# If basename match fails, maybe topic_item['object'] is just 'XXX'?
|
|
|
|
|
# Try finding based on substring? This might be ambiguous.
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Object file path not found in config matching object: {topic_item.get('object')}")
|
2025-04-22 14:19:21 +08:00
|
|
|
except KeyError:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning("Warning: 'object' key missing in topic_item for Object prompt.")
|
2025-04-22 14:19:21 +08:00
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error processing Object prompt:")
|
2025-04-22 14:19:21 +08:00
|
|
|
|
2025-04-22 15:12:46 +08:00
|
|
|
# 3. 添加Product信息 (if applicable)
|
2025-04-22 14:19:21 +08:00
|
|
|
try:
|
|
|
|
|
product_name = topic_item.get('product')
|
2025-04-22 15:12:46 +08:00
|
|
|
product_logic_description = topic_item.get('product_logic') # Directly use this description
|
|
|
|
|
if product_name:
|
|
|
|
|
# Add Product Logic description first (if available)
|
|
|
|
|
if product_logic_description:
|
|
|
|
|
user_prompt += f"Product Logic:\n{product_logic_description}\n"
|
2025-04-22 15:02:00 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Warning: 'product_logic' key missing or empty for product '{product_name}'.")
|
2025-04-22 15:12:46 +08:00
|
|
|
|
|
|
|
|
# Then, load Product Info file
|
2025-04-22 14:19:21 +08:00
|
|
|
product_file_path = None
|
|
|
|
|
for dir_info in resource_dir_config:
|
|
|
|
|
if dir_info.get("type") == "Product":
|
|
|
|
|
for file_path in dir_info.get("file_path", []):
|
2025-04-22 15:02:00 +08:00
|
|
|
if product_name in os.path.basename(file_path):
|
2025-04-22 14:19:21 +08:00
|
|
|
product_file_path = file_path
|
|
|
|
|
break
|
|
|
|
|
if product_file_path: break
|
|
|
|
|
|
|
|
|
|
if product_file_path:
|
|
|
|
|
product_content = ResourceLoader.load_file_content(product_file_path)
|
|
|
|
|
if product_content:
|
2025-04-22 15:12:46 +08:00
|
|
|
user_prompt += f"Product Info:\n{product_content}\n"
|
2025-04-22 14:19:21 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Product file could not be loaded: {product_file_path}")
|
2025-04-22 14:19:21 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Product file path not found in config for: {product_name}")
|
2025-04-22 15:12:46 +08:00
|
|
|
# Removed KeyError check for product_logic as it's now optional text
|
2025-04-22 17:36:29 +08:00
|
|
|
except KeyError:
|
|
|
|
|
logging.warning("Warning: Missing 'product' key in topic_item for Product prompt.")
|
2025-04-22 14:19:21 +08:00
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error processing Product prompt:")
|
2025-04-22 14:19:21 +08:00
|
|
|
|
2025-04-22 15:12:46 +08:00
|
|
|
# 4. 添加Style信息 (加载文件 based on topic_item['style'] from Style/ folder)
|
2025-04-22 14:19:21 +08:00
|
|
|
try:
|
2025-04-22 15:12:46 +08:00
|
|
|
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)
|
|
|
|
|
if style_content:
|
|
|
|
|
user_prompt += f"Style Info:\n{style_content}\n" # Changed label for clarity
|
|
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Style file not found or empty: {style_path}")
|
2025-04-22 14:19:21 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning("Warning: 'style' key missing or empty in topic_item.")
|
2025-04-22 14:19:21 +08:00
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error processing Style prompt:")
|
2025-04-22 14:19:21 +08:00
|
|
|
|
2025-04-22 15:12:46 +08:00
|
|
|
# 5. 添加Target Audience信息 (加载文件 based on topic_item['target_audience'] from Demand/ folder)
|
2025-04-22 14:19:21 +08:00
|
|
|
try:
|
2025-04-22 15:12:46 +08:00
|
|
|
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)
|
|
|
|
|
if target_audience_content:
|
|
|
|
|
user_prompt += f"Target Audience Info:\n{target_audience_content}\n"
|
|
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Target Audience file not found or empty: {target_audience_path}")
|
2025-04-22 15:02:00 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning("Warning: 'target_audience' key missing or empty in topic_item.")
|
2025-04-22 15:12:46 +08:00
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error processing Target Audience prompt:")
|
2025-04-22 15:12:46 +08:00
|
|
|
|
|
|
|
|
# 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))]
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.info(f"Found {len(refer_files)} files in Refer directory: {refer_files}")
|
2025-04-22 15:12:46 +08:00
|
|
|
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:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Could not load Refer file: {refer_path}")
|
2025-04-22 15:12:46 +08:00
|
|
|
if refer_content_all:
|
|
|
|
|
user_prompt += f"Refer Info:\n{refer_content_all}"
|
|
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning("No content loaded from Refer directory.")
|
2025-04-22 14:19:21 +08:00
|
|
|
else:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.warning(f"Refer directory not found: {refer_dir}")
|
2025-04-22 14:19:21 +08:00
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error processing Refer directory:")
|
2025-04-22 15:12:46 +08:00
|
|
|
|
|
|
|
|
# --- End of prompt construction logic ---
|
2025-04-22 14:19:21 +08:00
|
|
|
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.info(f"Content prompts constructed. System: {len(system_prompt)} chars, User: {len(user_prompt)} chars.")
|
2025-04-22 14:19:21 +08:00
|
|
|
return system_prompt, user_prompt
|
|
|
|
|
|
|
|
|
|
except KeyError as e:
|
|
|
|
|
# Catch potential KeyErrors from accessing topic_item if a required key is missing early on
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.error(f"Error constructing content prompts: Missing essential key '{e}' in topic_item: {topic_item}")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|
|
|
|
|
except Exception as e:
|
2025-04-22 17:36:29 +08:00
|
|
|
logging.exception("Error constructing content prompts:")
|
2025-04-22 14:19:21 +08:00
|
|
|
return None, None
|