360 lines
No EOL
14 KiB
Python
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() |