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
2025-04-22 18:41:20 +08:00
# 2. Object Info - 先列出所有可用文件,再注入匹配文件的内容
2025-04-22 14:19:21 +08:00
try :
2025-04-22 18:41:20 +08:00
object_name_from_topic = topic_item . get ( ' object ' ) # e.g., "尚书第建筑群"
object_file_basenames = [ ]
matched_object_file_path = None
matched_object_basename = None
# 遍历查找 Object 文件
2025-04-22 14:19:21 +08:00
for dir_info in resource_dir_config :
if dir_info . get ( " type " ) == " Object " :
for file_path in dir_info . get ( " file_path " , [ ] ) :
2025-04-22 18:41:20 +08:00
basename = os . path . basename ( file_path )
object_file_basenames . append ( basename )
# 尝试匹配当前 topic 的 object (仅当尚未找到匹配时)
if object_name_from_topic and not matched_object_file_path :
cleaned_resource_name = basename
if cleaned_resource_name . startswith ( " 景点信息- " ) :
cleaned_resource_name = cleaned_resource_name [ len ( " 景点信息- " ) : ]
if cleaned_resource_name . endswith ( " .txt " ) :
cleaned_resource_name = cleaned_resource_name [ : - len ( " .txt " ) ]
if cleaned_resource_name and cleaned_resource_name in object_name_from_topic :
matched_object_file_path = file_path
matched_object_basename = basename
# 注意:这里不 break, 继续收集所有文件名
# 构建提示词 - Part 1: 文件列表
if object_file_basenames :
user_prompt + = " Object信息: \n "
# user_prompt += f"{object_file_basenames}\n\n" # 直接打印列表可能不够清晰
for fname in object_file_basenames :
user_prompt + = f " - { fname } \n "
user_prompt + = " \n " # 加一个空行
logging . info ( f " Listed { len ( object_file_basenames ) } available object files. " )
2025-04-22 14:19:21 +08:00
else :
2025-04-22 18:41:20 +08:00
logging . warning ( " No resource directory entry found with type ' Object ' , or it has no file paths. " )
# 构建提示词 - Part 2: 注入匹配文件内容
if matched_object_file_path :
logging . info ( f " Attempting to load content for matched object file: { matched_object_basename } " )
matched_object_content = ResourceLoader . load_file_content ( matched_object_file_path )
if matched_object_content :
user_prompt + = f " { matched_object_basename } : \n { matched_object_content } \n \n "
logging . info ( f " Successfully loaded and injected content for: { matched_object_basename } " )
else :
logging . warning ( f " Object file matched ( { matched_object_basename } ) but could not be loaded or is empty. " )
elif object_name_from_topic : # 只有当 topic 中指定了 object 但没找到匹配文件时才警告
logging . warning ( f " Could not find a matching Object resource file to inject content for ' { object_name_from_topic } ' . Only the list of files was provided. " )
except KeyError :
logging . warning ( " Warning: ' object ' key potentially missing in topic_item. " )
2025-04-22 14:19:21 +08:00
except Exception as e :
2025-04-22 18:41:20 +08:00
logging . exception ( " Error processing Object prompt section: " )
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