""" Prompt Templates Module Manages prompt templates for different AI tools and providers Includes system for storing, loading, and managing user-created prompts """ import os import json import uuid import logging from typing import Dict, Any, List, Optional from datetime import datetime # Setup logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger("prompts") class PromptTemplate: """Represents a prompt template that can be used with AI providers""" def __init__(self, id: str = None, name: str = "", description: str = "", template: str = "", system_message: str = "", category: str = "", is_public: bool = False, created_by: str = "system", created_at: str = None, price: float = 0.0, parameters: Dict[str, Any] = None, provider_defaults: Dict[str, Any] = None): """Initialize a prompt template""" self.id = id or str(uuid.uuid4()) self.name = name self.description = description self.template = template self.system_message = system_message self.category = category self.is_public = is_public self.created_by = created_by self.created_at = created_at or datetime.now().isoformat() self.price = price self.parameters = parameters or {} self.provider_defaults = provider_defaults or {} def to_dict(self) -> Dict[str, Any]: """Convert template to dictionary""" return { "id": self.id, "name": self.name, "description": self.description, "template": self.template, "system_message": self.system_message, "category": self.category, "is_public": self.is_public, "created_by": self.created_by, "created_at": self.created_at, "price": self.price, "parameters": self.parameters, "provider_defaults": self.provider_defaults } @classmethod def from_dict(cls, data: Dict[str, Any]) -> 'PromptTemplate': """Create template from dictionary""" return cls( id=data.get("id"), name=data.get("name", ""), description=data.get("description", ""), template=data.get("template", ""), system_message=data.get("system_message", ""), category=data.get("category", ""), is_public=data.get("is_public", False), created_by=data.get("created_by", "system"), created_at=data.get("created_at"), price=data.get("price", 0.0), parameters=data.get("parameters", {}), provider_defaults=data.get("provider_defaults", {}) ) def render(self, variables: Dict[str, Any] = None) -> Dict[str, str]: """ Render the prompt template with the provided variables Returns both the rendered prompt and system message """ variables = variables or {} prompt = self.template system = self.system_message # Replace variables in the template for key, value in variables.items(): placeholder = "{" + key + "}" prompt = prompt.replace(placeholder, str(value)) system = system.replace(placeholder, str(value)) return { "prompt": prompt, "system_message": system } class PromptTemplateManager: """Manages prompt templates, including default and user-created ones""" def __init__(self, templates_dir: str = None): """Initialize the prompt template manager""" self.templates_dir = templates_dir or os.path.join(os.path.dirname(__file__), "templates") self.user_templates_dir = os.path.join(self.templates_dir, "user") # Create directories if they don't exist os.makedirs(self.templates_dir, exist_ok=True) os.makedirs(self.user_templates_dir, exist_ok=True) # Load default templates self.default_templates = self._load_default_templates() # Load user templates self.user_templates = self._load_user_templates() def _load_default_templates(self) -> Dict[str, PromptTemplate]: """Load default templates from files""" templates = {} # Define default templates if no files exist yet default_templates = { "general_chat": PromptTemplate( id="general_chat", name="General Chat", description="A general-purpose chat prompt", template="Please answer the following question or respond to the message: {input}", system_message="You are a helpful assistant that provides accurate and concise responses.", category="general", created_by="system" ), "creative_writing": PromptTemplate( id="creative_writing", name="Creative Writing", description="Generate creative writing based on a premise", template="Write a {genre} {format} about {topic}.", system_message="You are a creative writer with expertise in different genres and formats.", category="creative", created_by="system", parameters={ "genre": {"type": "string", "description": "Genre of the writing", "default": "science fiction"}, "format": {"type": "string", "description": "Format of the writing", "default": "short story"}, "topic": {"type": "string", "description": "Topic or premise", "required": True} } ), "code_assistant": PromptTemplate( id="code_assistant", name="Code Assistant", description="Generate or debug code in various languages", template="I need help with the following code task in {language}:\n\n{task}\n\n{code}", system_message="You are an expert programmer. Provide well-commented, efficient, and correct code solutions.", category="development", created_by="system", parameters={ "language": {"type": "string", "description": "Programming language", "required": True}, "task": {"type": "string", "description": "Description of the coding task", "required": True}, "code": {"type": "string", "description": "Existing code (if any)", "default": ""} }, provider_defaults={ "openai": {"model": "gpt-4-turbo"}, "deepseek": {"model": "deepseek-coder"} } ), "image_prompt": PromptTemplate( id="image_prompt", name="Image Generation", description="Detailed prompt for image generation", template="{subject} {style}, {details}, {quality}", system_message="", category="images", created_by="system", parameters={ "subject": {"type": "string", "description": "Main subject of the image", "required": True}, "style": {"type": "string", "description": "Art style", "default": "digital art"}, "details": {"type": "string", "description": "Additional details", "default": "detailed, vibrant colors"}, "quality": {"type": "string", "description": "Quality descriptors", "default": "high quality, 4k, trending on artstation"} }, provider_defaults={ "openai": {"model": "dall-e-3"} } ) } # Save default templates if they don't exist for template_id, template in default_templates.items(): template_path = os.path.join(self.templates_dir, f"{template_id}.json") if not os.path.exists(template_path): with open(template_path, "w") as f: json.dump(template.to_dict(), f, indent=2) templates[template_id] = template return templates def _load_user_templates(self) -> Dict[str, PromptTemplate]: """Load user-created templates""" templates = {} try: # List all JSON files in user_templates_dir for filename in os.listdir(self.user_templates_dir): if filename.endswith(".json"): template_path = os.path.join(self.user_templates_dir, filename) with open(template_path, "r") as f: template_data = json.load(f) template = PromptTemplate.from_dict(template_data) templates[template.id] = template except Exception as e: logger.error(f"Error loading user templates: {e}") return templates def get_all_templates(self) -> List[PromptTemplate]: """Get all available templates (default + user)""" all_templates = list(self.default_templates.values()) # Add public user templates and user's own templates for template in self.user_templates.values(): if template.is_public: all_templates.append(template) return all_templates def get_user_templates(self, user_id: str) -> List[PromptTemplate]: """Get templates created by a specific user""" return [t for t in self.user_templates.values() if t.created_by == user_id] def get_template(self, template_id: str) -> Optional[PromptTemplate]: """Get a specific template by ID""" if template_id in self.default_templates: return self.default_templates[template_id] if template_id in self.user_templates: return self.user_templates[template_id] return None def create_template(self, template: PromptTemplate) -> PromptTemplate: """Create a new user template""" # Ensure unique ID if template.id in self.default_templates or template.id in self.user_templates: template.id = str(uuid.uuid4()) # Save template to file template_path = os.path.join(self.user_templates_dir, f"{template.id}.json") with open(template_path, "w") as f: json.dump(template.to_dict(), f, indent=2) # Add to user templates self.user_templates[template.id] = template return template def update_template(self, template: PromptTemplate) -> Optional[PromptTemplate]: """Update an existing user template""" if template.id not in self.user_templates: logger.error(f"Template {template.id} not found or not a user template") return None # Save updated template template_path = os.path.join(self.user_templates_dir, f"{template.id}.json") with open(template_path, "w") as f: json.dump(template.to_dict(), f, indent=2) # Update in memory self.user_templates[template.id] = template return template def delete_template(self, template_id: str, user_id: str) -> bool: """Delete a user template""" if template_id not in self.user_templates: logger.error(f"Template {template_id} not found or not a user template") return False # Check ownership template = self.user_templates[template_id] if template.created_by != user_id and user_id != "admin": logger.error(f"User {user_id} does not own template {template_id}") return False # Delete template file template_path = os.path.join(self.user_templates_dir, f"{template_id}.json") try: os.remove(template_path) del self.user_templates[template_id] return True except Exception as e: logger.error(f"Error deleting template {template_id}: {e}") return False def get_templates_by_category(self, category: str) -> List[PromptTemplate]: """Get templates by category""" all_templates = self.get_all_templates() return [t for t in all_templates if t.category.lower() == category.lower()] def get_public_templates(self) -> List[PromptTemplate]: """Get all public templates created by users""" return [t for t in self.user_templates.values() if t.is_public] # Example usage if __name__ == "__main__": # Initialize manager manager = PromptTemplateManager() # Get all templates all_templates = manager.get_all_templates() print(f"Loaded {len(all_templates)} templates") # Create a new template new_template = PromptTemplate( name="SEO Content", description="Generate SEO-optimized content for websites", template="Write SEO-optimized content about {topic} targeting the keyword {keyword}. {tone} tone, {length} words.", system_message="You are an expert SEO content writer who creates engaging, well-researched content that ranks well in search engines.", category="marketing", created_by="user123", is_public=True, parameters={ "topic": {"type": "string", "description": "Main topic", "required": True}, "keyword": {"type": "string", "description": "Target keyword", "required": True}, "tone": {"type": "string", "description": "Content tone", "default": "professional"}, "length": {"type": "number", "description": "Content length in words", "default": 500} } ) created = manager.create_template(new_template) print(f"Created new template: {created.id} - {created.name}") # Test rendering a template code_template = manager.get_template("code_assistant") if code_template: rendered = code_template.render({ "language": "Python", "task": "Create a function to calculate Fibonacci numbers", "code": "def fibonacci(n):\n # TODO: Implement" }) print("\nRendered prompt:") print(rendered["prompt"]) print("\nSystem message:")