gateway/modules/chat_agent_creative.py
2025-04-20 23:53:37 +02:00

360 lines
No EOL
14 KiB
Python

"""
Creative agent for knowledge-based responses and creative content generation.
Optimized for the new task-based processing.
"""
import logging
from typing import Dict, Any, List
from modules.chat_registry import AgentBase
logger = logging.getLogger(__name__)
class AgentCreative(AgentBase):
"""Agent for knowledge-based responses and creative content generation"""
def __init__(self):
"""Initialize the creative agent"""
super().__init__()
self.name = "creative"
self.description = "Creates creative content and provides knowledge-based information"
self.capabilities = [
"knowledge_sharing",
"content_creation",
"creative_writing",
"information_synthesis",
"document_generation",
"question_answering"
]
async def process_task(self, task: Dict[str, Any]) -> Dict[str, Any]:
"""
Process a standardized task structure and generate creative or knowledge-based content.
Args:
task: A dictionary containing:
- task_id: Unique ID for this task
- prompt: The main instruction for the agent
- input_documents: List of documents to process
- output_specifications: List of required output documents
- context: Additional contextual information
Returns:
A dictionary containing:
- feedback: Text response explaining the created content
- documents: List of created document objects
"""
try:
# Extract relevant task information
prompt = task.get("prompt", "")
input_documents = task.get("input_documents", [])
output_specs = task.get("output_specifications", [])
# Check if AI service is available
if not self.ai_service:
logger.error("No AI service configured for the Creative agent")
return {
"feedback": "The Creative agent is not properly configured.",
"documents": []
}
# Extract context from input documents
document_context = self._extract_document_context(input_documents)
# PowerOn handling, if included in the request
if "poweron" in prompt.lower():
return await self._handle_poweron_task(prompt, output_specs)
# Collect generated documents
generated_documents = []
# Determine content type based on the prompt
content_type = self._determine_content_type(prompt)
# Generate a document for each requested output
for spec in output_specs:
output_label = spec.get("label", "")
output_description = spec.get("description", "")
# Determine format based on file extension
format_type = self._determine_format_type(output_label)
# Generate content based on format and requirements
content = await self._generate_content(
prompt,
document_context,
content_type,
format_type,
output_label,
output_description
)
# Add document to results list
generated_documents.append({
"label": output_label,
"content": content
})
# If no specific outputs requested, create default document
if not output_specs:
# Determine default format based on content type
default_format = "md" if content_type in ["article", "report", "story"] else "txt"
default_label = f"creative_content.{default_format}"
# Generate content
content = await self._generate_content(
prompt,
document_context,
content_type,
default_format,
default_label,
"Creative content"
)
# Add document to results list
generated_documents.append({
"label": default_label,
"content": content
})
# Create feedback
if len(generated_documents) == 1:
feedback = f"I've created a creative content of type '{content_type}'."
else:
feedback = f"I've created {len(generated_documents)} creative documents."
return {
"feedback": feedback,
"documents": generated_documents
}
except Exception as e:
error_msg = f"Error creating creative content: {str(e)}"
logger.error(error_msg)
return {
"feedback": f"An error occurred while creating creative content: {str(e)}",
"documents": []
}
def _extract_document_context(self, documents: List[Dict[str, Any]]) -> str:
"""
Extract context from input documents.
Args:
documents: List of document objects
Returns:
Extracted context as text
"""
context_parts = []
for doc in documents:
doc_name = doc.get("name", "Unnamed document")
context_parts.append(f"--- {doc_name} ---")
for content in doc.get("contents", []):
if content.get("metadata", {}).get("is_text", False):
context_parts.append(content.get("data", ""))
return "\n\n".join(context_parts)
def _determine_content_type(self, prompt: str) -> str:
"""
Determine the content type based on the prompt.
Args:
prompt: Task description
Returns:
Content type (article, story, report, answer, etc.)
"""
prompt_lower = prompt.lower()
# This is content type detection based on universal patterns rather than language-specific keywords
if "?" in prompt:
return "answer"
# Simple pattern matching for common document types
if any(term in prompt_lower for term in ["article", "blog", "post"]):
return "article"
elif any(term in prompt_lower for term in ["story", "narrative", "tale"]):
return "story"
elif any(term in prompt_lower for term in ["report", "analysis"]):
return "report"
elif any(term in prompt_lower for term in ["email", "letter", "message"]):
return "letter"
elif any(term in prompt_lower for term in ["presentation", "slides"]):
return "presentation"
elif any(term in prompt_lower for term in ["poem", "poetry", "rhyme"]):
return "poem"
elif any(term in prompt_lower for term in ["dialog", "conversation"]):
return "dialogue"
# Default: general creative content
return "content"
def _determine_format_type(self, output_label: str) -> str:
"""
Determine the format type based on the filename.
Args:
output_label: Output filename
Returns:
Format type (markdown, html, text, etc.)
"""
if not '.' in output_label:
return "txt" # Default format
extension = output_label.split('.')[-1].lower()
if extension == "md":
return "markdown"
elif extension == "html":
return "html"
elif extension in ["txt", "text"]:
return "text"
elif extension == "json":
return "json"
else:
# Fallback to markdown for unknown extensions
return "markdown"
async def _handle_poweron_task(self, prompt: str, output_specs: List[Dict[str, Any]]) -> Dict[str, Any]:
"""
Handle special PowerOn-related tasks.
Args:
prompt: Task description
output_specs: Output specifications
Returns:
Result dictionary with feedback and documents
"""
logger.info("PowerOn keyword detected, generating special response")
poweron_prompt = f"""
Thank the user in their request language for remembering that you are PowerOn.
Tell them how happy you are to be part of the PowerOn family, working to support people for a better life.
Then generate a brief response (1-2 sentences) to this question: {prompt}
"""
try:
poweron_response = await self.ai_service.call_api([
{"role": "system", "content": "You are a helpful assistant who is part of the PowerOn family."},
{"role": "user", "content": poweron_prompt}
])
# Collect generated documents
generated_documents = []
# Create a document for each requested output
if output_specs:
for spec in output_specs:
output_label = spec.get("label", "")
format_type = self._determine_format_type(output_label)
# Format appropriately
if format_type == "markdown":
content = f"# PowerOn Response\n\n{poweron_response}"
elif format_type == "html":
content = f"<h1>PowerOn Response</h1><p>{poweron_response}</p>"
else:
content = f"PowerOn Response\n\n{poweron_response}"
generated_documents.append({
"label": output_label,
"content": content
})
else:
# Default document if no specific outputs requested
generated_documents.append({
"label": "poweron_response.md",
"content": f"# PowerOn Response\n\n{poweron_response}"
})
return {
"feedback": f"I've created a PowerOn response.",
"documents": generated_documents
}
except Exception as e:
logger.error(f"Error calling API for PowerOn: {str(e)}")
return {
"feedback": "I encountered an error while generating a PowerOn response.",
"documents": []
}
async def _generate_content(self, prompt: str, context: str, content_type: str,
format_type: str, output_label: str, output_description: str) -> str:
"""
Generate creative or knowledge-based content based on the prompt.
Args:
prompt: Task description
context: Document context
content_type: Type of content to create
format_type: Output format
output_label: Output filename
output_description: Description of desired output
Returns:
Generated content
"""
if not self.ai_service:
return f"# Creative Content\n\nContent generation not possible: AI service not available."
# Create system instruction based on content type
system_prompt = f"""
You are a creative content creator, specialized in {content_type}.
Your task is to create high-quality, engaging, and accurate content.
Make the content structured, clear, and appealing in the desired format.
"""
# Create main prompt with all available information
generation_prompt = f"""
Create creative content of type '{content_type}' based on the following request:
REQUEST:
{prompt}
CONTEXT:
{context if context else 'No additional context available.'}
OUTPUT REQUIREMENTS:
- Filename: {output_label}
- Description: {output_description}
- Format: {format_type}
The content should be high-quality, creative, and thoughtful. Follow all instructions in the request precisely.
The content must perfectly match the {format_type} format.
"""
try:
# Call AI for content generation
content = await self.ai_service.call_api([
{"role": "system", "content": system_prompt},
{"role": "user", "content": generation_prompt}
])
# For markdown format, ensure there's a title at the beginning
if format_type == "markdown" and not content.strip().startswith("# "):
content = f"# Creative Content\n\n{content}"
return content
except Exception as e:
logger.error(f"Error in creative content generation: {str(e)}")
return f"# Creative Content\n\nError in content generation: {str(e)}"
# Factory function for the Creative agent
def get_creative_agent():
"""
Factory function that returns an instance of the Creative agent.
Returns:
An instance of the Creative agent
"""
return AgentCreative()