basic workflow running
This commit is contained in:
parent
1711abf100
commit
811ed72615
19 changed files with 372 additions and 271 deletions
3
app.py
3
app.py
|
|
@ -28,7 +28,8 @@ from modules.auth import (
|
|||
|
||||
# Import models - import generically for INITIALIZATION, even if dummy!
|
||||
import modules.gateway_model as gateway_model
|
||||
import modules.lucydom_interface as lucydom_model
|
||||
|
||||
#from modules.lucydom_interface import get_lucydom_interface as dom_interface
|
||||
|
||||
|
||||
def init_logging():
|
||||
|
|
|
|||
|
|
@ -52,3 +52,4 @@ Agent_Webcrawler_MAX_SEARCH_RESULTS = 5
|
|||
# Agent Coder configuration
|
||||
Agent_Coder_INSTALL_TIMEOUT = 180
|
||||
Agent_Coder_EXECUTION_TIMEOUT = 60
|
||||
Agent_Coder_EXECUTION_RETRY = 5
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ class ChatService:
|
|||
"Content-Type": "application/json"
|
||||
}
|
||||
)
|
||||
|
||||
logger.info(f"OpenAI Connector initialized with model: {self.model_name}")
|
||||
|
||||
async def call_api(self, messages: List[Dict[str, Any]], temperature: float = None, max_tokens: int = None) -> str:
|
||||
|
|
|
|||
|
|
@ -14,14 +14,25 @@ from datetime import datetime
|
|||
from typing import Dict, Any, List, Optional, Union
|
||||
|
||||
# Required imports
|
||||
from connectors.connector_aichat_openai import ChatService
|
||||
from modules.chat_registry import get_agent_registry
|
||||
from modules.lucydom_interface import get_lucydom_interface, GLOBAL_SETTINGS
|
||||
from modules.lucydom_interface import get_lucydom_interface as dom_interface
|
||||
from modules.chat_content_extraction import get_document_contents
|
||||
|
||||
# Configure logger
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Global settings for the workflow management
|
||||
GLOBAL_WorkflowLabels = {
|
||||
"system_name": "AI Assistant", # Default system name for logs
|
||||
"workflow_status_messages": {
|
||||
"init": "Workflow initialized",
|
||||
"running": "Running workflow",
|
||||
"waiting": "Waiting for input",
|
||||
"completed": "Workflow completed",
|
||||
"error": "Error in workflow"
|
||||
}
|
||||
}
|
||||
|
||||
class ChatManager:
|
||||
"""
|
||||
Manages the processing of chat requests, agent execution, and
|
||||
|
|
@ -38,13 +49,9 @@ class ChatManager:
|
|||
"""
|
||||
self.mandate_id = mandate_id
|
||||
self.user_id = user_id
|
||||
self.ai_service = ChatService()
|
||||
self.lucy_interface = get_lucydom_interface(mandate_id, user_id)
|
||||
self.mydom = dom_interface(mandate_id, user_id)
|
||||
self.agent_registry = get_agent_registry()
|
||||
self.agent_registry.set_ai_service(self.ai_service)
|
||||
|
||||
# Set AI service in lucy interface for language support
|
||||
self.lucy_interface.set_ai_service(self.ai_service)
|
||||
self.agent_registry.set_mydom(self.mydom)
|
||||
|
||||
### Chat Management
|
||||
|
||||
|
|
@ -73,9 +80,9 @@ class ChatManager:
|
|||
obj_workplan = project_manager_response.get("obj_workplan", [])
|
||||
obj_user_response = project_manager_response.get("obj_user_response", "")
|
||||
|
||||
# Get detected language and set it in the lucy interface
|
||||
# Get detected language and set it in the mydom interface
|
||||
user_language = project_manager_response.get("user_language", "en")
|
||||
self.lucy_interface.set_user_language(user_language)
|
||||
self.mydom.set_user_language(user_language)
|
||||
|
||||
# 4. Save the response as a message in the workflow and add log entries
|
||||
response_message = {
|
||||
|
|
@ -203,7 +210,7 @@ JSON_OUTPUT = {{
|
|||
}}
|
||||
# Multiple agent tasks can be added here and should build logically on each other
|
||||
],
|
||||
"obj_user_response": "Information to the user about how his request will be solved.",
|
||||
"obj_user_response": "Information to the user about how his request will be solved, in the language of the user's request.",
|
||||
"user_language": "en" # Language code (e.g., en, de, fr, es) based on the user's request
|
||||
}}
|
||||
|
||||
|
|
@ -227,9 +234,9 @@ JSON_OUTPUT = {{
|
|||
4. If you use label for an existing file
|
||||
"""
|
||||
|
||||
# Call the AI service through lucy_interface for language support
|
||||
# Call the AI service through mydom for language support
|
||||
logger.debug(f"Planning prompt: {prompt}")
|
||||
project_manager_output = await self.lucy_interface.call_ai([
|
||||
project_manager_output = await self.mydom.call_ai([
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are an experienced project manager who analyzes user requests and creates work plans. You pay very careful attention to ensure that all document dependencies are correct and that no non-existent documents are defined as inputs. The output follows strictly the specified format."
|
||||
|
|
@ -318,8 +325,8 @@ JSON_OUTPUT = {{
|
|||
matching_documents.append(doc_ref)
|
||||
break
|
||||
|
||||
# Use the lucy_interface for language-aware AI calls
|
||||
final_prompt = await self.lucy_interface.call_ai([
|
||||
# Use the mydom for language-aware AI calls
|
||||
final_prompt = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a project manager, who delivers results to a user."},
|
||||
{"role": "user", "content": f"""
|
||||
Give the final short feedback to the user with reference to the initial statement (obj_user_response). Provide a list of delivered files (files_delivered). If in the list of delivered files (files_delivered) some files from the original list (files_promised) are not available, then just give a comment on this, otherwise task is completed.
|
||||
|
|
@ -359,7 +366,7 @@ JSON_OUTPUT = {{
|
|||
"""
|
||||
current_time = datetime.now().isoformat()
|
||||
|
||||
if workflow_id is None or not self.lucy_interface.get_workflow(workflow_id):
|
||||
if workflow_id is None or not self.mydom.get_workflow(workflow_id):
|
||||
# Create new workflow
|
||||
new_workflow_id = str(uuid.uuid4()) if workflow_id is None else workflow_id
|
||||
workflow = {
|
||||
|
|
@ -390,13 +397,13 @@ JSON_OUTPUT = {{
|
|||
"last_activity": workflow["last_activity"],
|
||||
"message_ids": workflow["message_ids"] # Include message_ids
|
||||
}
|
||||
self.lucy_interface.create_workflow(workflow_db)
|
||||
self.mydom.create_workflow(workflow_db)
|
||||
|
||||
self.log_add(workflow, GLOBAL_SETTINGS["workflow_status_messages"]["init"], level="info", progress=0)
|
||||
self.log_add(workflow, GLOBAL_WorkflowLabels["workflow_status_messages"]["init"], level="info", progress=0)
|
||||
return workflow
|
||||
else:
|
||||
# Load existing workflow
|
||||
workflow = self.lucy_interface.load_workflow_state(workflow_id)
|
||||
workflow = self.mydom.load_workflow_state(workflow_id)
|
||||
|
||||
# Ensure message_ids exists
|
||||
if "message_ids" not in workflow:
|
||||
|
|
@ -404,7 +411,7 @@ JSON_OUTPUT = {{
|
|||
workflow["message_ids"] = [msg["id"] for msg in workflow.get("messages", [])]
|
||||
|
||||
# Update in database
|
||||
self.lucy_interface.update_workflow(workflow_id, {"message_ids": workflow["message_ids"]})
|
||||
self.mydom.update_workflow(workflow_id, {"message_ids": workflow["message_ids"]})
|
||||
|
||||
# Update status and increment round counter
|
||||
workflow["status"] = "running"
|
||||
|
|
@ -422,9 +429,9 @@ JSON_OUTPUT = {{
|
|||
"last_activity": workflow["last_activity"],
|
||||
"current_round": workflow["current_round"]
|
||||
}
|
||||
self.lucy_interface.update_workflow(workflow_id, workflow_update)
|
||||
self.mydom.update_workflow(workflow_id, workflow_update)
|
||||
|
||||
self.log_add(workflow, GLOBAL_SETTINGS["workflow_status_messages"]["running"], level="info", progress=0)
|
||||
self.log_add(workflow, GLOBAL_WorkflowLabels["workflow_status_messages"]["running"], level="info", progress=0)
|
||||
return workflow
|
||||
|
||||
def workflow_finish(self, workflow: Dict[str, Any]) -> Dict[str, Any]:
|
||||
|
|
@ -448,9 +455,9 @@ JSON_OUTPUT = {{
|
|||
workflow["last_activity"] = workflow_update["last_activity"]
|
||||
|
||||
# Save workflow state to database - only relevant fields, not the messages list
|
||||
self.lucy_interface.update_workflow(workflow["id"], workflow_update)
|
||||
self.mydom.update_workflow(workflow["id"], workflow_update)
|
||||
|
||||
self.log_add(workflow, GLOBAL_SETTINGS["workflow_status_messages"]["completed"], level="info", progress=100)
|
||||
self.log_add(workflow, GLOBAL_WorkflowLabels["workflow_status_messages"]["completed"], level="info", progress=100)
|
||||
return workflow
|
||||
|
||||
async def workflow_summarize(self, workflow: Dict[str, Any], message_user: Dict[str, Any]) -> str:
|
||||
|
|
@ -583,8 +590,8 @@ JSON_OUTPUT = {{
|
|||
# Extract and provide only the relevant information as requested.
|
||||
"""
|
||||
|
||||
# Call the AI service through lucy_interface for language support
|
||||
processed_data = await self.lucy_interface.call_ai([
|
||||
# Call the AI service through mydom for language support
|
||||
processed_data = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a document processing assistant. Extract only the relevant information as requested."},
|
||||
{"role": "user", "content": ai_prompt}
|
||||
])
|
||||
|
|
@ -660,7 +667,7 @@ JSON_OUTPUT = {{
|
|||
"workflow_round": workflow.get("current_round", 1),
|
||||
"agent_type": agent_name,
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"language": self.lucy_interface.user_language # Pass language to agent
|
||||
"language": self.mydom.user_language # Pass language to agent
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -668,7 +675,7 @@ JSON_OUTPUT = {{
|
|||
try:
|
||||
# Process the task using the agent's standardized interface
|
||||
logger.debug("TASK: "+self.parse_json2text(agent_task))
|
||||
logger.debug(f"Agent '{agent_name}' AI service available: {agent.ai_service is not None}")
|
||||
logger.debug(f"Agent '{agent_name}' AI service available: {agent.mydom is not None}")
|
||||
|
||||
agent_results = await agent.process_task(agent_task)
|
||||
|
||||
|
|
@ -753,7 +760,7 @@ JSON_OUTPUT = {{
|
|||
file_content = content
|
||||
|
||||
# Save file to database
|
||||
file_meta = self.lucy_interface.save_uploaded_file(file_content, label)
|
||||
file_meta = self.mydom.save_uploaded_file(file_content, label)
|
||||
|
||||
if file_meta and "id" in file_meta:
|
||||
file_id = file_meta["id"]
|
||||
|
|
@ -827,14 +834,14 @@ JSON_OUTPUT = {{
|
|||
workflow["last_activity"] = current_time
|
||||
|
||||
# Save to database - first the message itself
|
||||
self.lucy_interface.create_workflow_message(message)
|
||||
self.mydom.create_workflow_message(message)
|
||||
|
||||
# Then save the workflow with updated references
|
||||
workflow_update = {
|
||||
"last_activity": current_time,
|
||||
"message_ids": workflow["message_ids"] # Update the message_ids field
|
||||
}
|
||||
self.lucy_interface.update_workflow(workflow["id"], workflow_update)
|
||||
self.mydom.update_workflow(workflow["id"], workflow_update)
|
||||
|
||||
return message
|
||||
|
||||
|
|
@ -853,8 +860,8 @@ JSON_OUTPUT = {{
|
|||
content = message.get("content", "")
|
||||
|
||||
try:
|
||||
# Use the lucy_interface for language-aware AI calls
|
||||
content_summary = await self.lucy_interface.call_ai([
|
||||
# Use the mydom for language-aware AI calls
|
||||
content_summary = await self.mydom.call_ai([
|
||||
{"role": "system", "content": f"You are a chat message summarizer. Create a very concise summary (2-3 sentences, maximum 300 characters)"},
|
||||
{"role": "user", "content": content}
|
||||
])
|
||||
|
|
@ -890,8 +897,8 @@ JSON_OUTPUT = {{
|
|||
is_text = content.get("metadata", {}).get("is_text", False)
|
||||
|
||||
try:
|
||||
# Use the lucy_interface for language-aware AI calls
|
||||
summary = await self.lucy_interface.call_ai([
|
||||
# Use the mydom for language-aware AI calls
|
||||
summary = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a content summarizer. Create very concise summary (1-2 sentences, maximum 200 characters) about this file."},
|
||||
{"role": "user", "content": f"Summarize this {content_type} content briefly:\n\n{data}"}
|
||||
])
|
||||
|
|
@ -921,7 +928,7 @@ JSON_OUTPUT = {{
|
|||
for file_id in file_ids:
|
||||
try:
|
||||
# Check if the file exists
|
||||
file = self.lucy_interface.get_file(file_id)
|
||||
file = self.mydom.get_file(file_id)
|
||||
if not file:
|
||||
logger.warning(f"File with ID {file_id} not found")
|
||||
continue
|
||||
|
|
@ -932,7 +939,7 @@ JSON_OUTPUT = {{
|
|||
continue
|
||||
|
||||
# Load file content
|
||||
file_content = self.lucy_interface.get_file_data(file_id)
|
||||
file_content = self.mydom.get_file_data(file_id)
|
||||
if file_content is None:
|
||||
logger.warning(f"No content found for file with ID {file_id}")
|
||||
continue
|
||||
|
|
@ -1047,7 +1054,7 @@ JSON_OUTPUT = {{
|
|||
data = data.encode('utf-8')
|
||||
|
||||
# Save file in the database
|
||||
file_meta = self.lucy_interface.save_uploaded_file(data, name)
|
||||
file_meta = self.mydom.save_uploaded_file(data, name)
|
||||
if file_meta and "id" in file_meta:
|
||||
# Update the Document with the File-ID
|
||||
document["file_id"] = file_meta["id"]
|
||||
|
|
@ -1123,7 +1130,7 @@ JSON_OUTPUT = {{
|
|||
workflow_status = workflow.get("status", "running")
|
||||
|
||||
# Set agent_name from global settings
|
||||
agent_name = GLOBAL_SETTINGS.get("system_name", "AI Assistant")
|
||||
agent_name = GLOBAL_WorkflowLabels.get("system_name", "AI Assistant")
|
||||
|
||||
# Create log entry
|
||||
log_entry = {
|
||||
|
|
@ -1144,7 +1151,7 @@ JSON_OUTPUT = {{
|
|||
workflow["logs"].append(log_entry)
|
||||
|
||||
# Save in database
|
||||
self.lucy_interface.create_workflow_log(log_entry)
|
||||
self.mydom.create_workflow_log(log_entry)
|
||||
|
||||
# Also log in logger
|
||||
if level == "info":
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ class AgentAnalyst(AgentBase):
|
|||
# Set default visualization settings
|
||||
plt.style.use('seaborn-v0_8-whitegrid')
|
||||
|
||||
def set_dependencies(self, ai_service=None):
|
||||
def set_dependencies(self, mydom=None):
|
||||
"""Set external dependencies for the agent."""
|
||||
self.ai_service = ai_service
|
||||
self.mydom = mydom
|
||||
|
||||
async def process_task(self, task: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
@ -56,7 +56,7 @@ class AgentAnalyst(AgentBase):
|
|||
output_specs = task.get("output_specifications", [])
|
||||
|
||||
# Check AI service
|
||||
if not self.ai_service:
|
||||
if not self.mydom:
|
||||
return {
|
||||
"feedback": "The Analyst agent requires an AI service to function.",
|
||||
"documents": []
|
||||
|
|
@ -105,9 +105,9 @@ class AgentAnalyst(AgentBase):
|
|||
documents.append(document)
|
||||
|
||||
# Generate feedback
|
||||
feedback = f"Analysis complete. Created {len(documents)} documents based on your requirements."
|
||||
feedback = f"{analysis_plan.get('analysis_approach')}"
|
||||
if analysis_plan.get("key_insights"):
|
||||
feedback += f"\n\nKey insights: {analysis_plan.get('key_insights')}"
|
||||
feedback += f"\n\n{analysis_plan.get('key_insights')}"
|
||||
|
||||
return {
|
||||
"feedback": feedback,
|
||||
|
|
@ -251,12 +251,11 @@ class AgentAnalyst(AgentBase):
|
|||
|
||||
Only return valid JSON. No preamble or explanations.
|
||||
"""
|
||||
|
||||
try:
|
||||
response = await self.ai_service.call_api([
|
||||
response = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a data analysis expert. Respond with valid JSON only."},
|
||||
{"role": "user", "content": analysis_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
|
||||
# Extract JSON from response
|
||||
json_start = response.find('{')
|
||||
|
|
@ -375,10 +374,10 @@ class AgentAnalyst(AgentBase):
|
|||
|
||||
try:
|
||||
# Get visualization code from AI
|
||||
viz_code = await self.ai_service.call_api([
|
||||
viz_code = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a data visualization expert. Provide only executable Python code."},
|
||||
{"role": "user", "content": viz_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
|
||||
# Clean code
|
||||
viz_code = viz_code.replace("```python", "").replace("```", "").strip()
|
||||
|
|
@ -504,10 +503,10 @@ class AgentAnalyst(AgentBase):
|
|||
|
||||
try:
|
||||
# Get data processing code from AI
|
||||
data_code = await self.ai_service.call_api([
|
||||
data_code = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a data processing expert. Provide only executable Python code."},
|
||||
{"role": "user", "content": data_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
|
||||
# Clean code
|
||||
data_code = data_code.replace("```python", "").replace("```", "").strip()
|
||||
|
|
@ -630,10 +629,10 @@ class AgentAnalyst(AgentBase):
|
|||
|
||||
try:
|
||||
# Get document content from AI
|
||||
document_content = await self.ai_service.call_api([
|
||||
document_content = await self.mydom.call_ai([
|
||||
{"role": "system", "content": f"You are a data analysis expert creating a {format_type} document."},
|
||||
{"role": "user", "content": analysis_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
|
||||
# Clean HTML or Markdown if needed
|
||||
if format_type in ["md", "markdown"] and not document_content.strip().startswith("#"):
|
||||
|
|
|
|||
|
|
@ -33,12 +33,13 @@ class AgentCoder(AgentBase):
|
|||
]
|
||||
|
||||
# Executor settings
|
||||
self.executor_timeout = APP_CONFIG.get("Agent_Coder_EXECUTION_TIMEOUT") # seconds
|
||||
self.executor_timeout = int(APP_CONFIG.get("Agent_Coder_EXECUTION_TIMEOUT")) # seconds
|
||||
self.execution_retry_limit = int(APP_CONFIG.get("Agent_Coder_EXECUTION_RETRY")) # max retries
|
||||
self.temp_dir = None
|
||||
|
||||
def set_dependencies(self, ai_service=None):
|
||||
def set_dependencies(self, mydom=None):
|
||||
"""Set external dependencies for the agent."""
|
||||
self.ai_service = ai_service
|
||||
self.mydom = mydom
|
||||
|
||||
async def process_task(self, task: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
@ -58,7 +59,7 @@ class AgentCoder(AgentBase):
|
|||
output_specs = task.get("output_specifications", [])
|
||||
|
||||
# Check if AI service is available
|
||||
if not self.ai_service:
|
||||
if not self.mydom:
|
||||
logger.error("No AI service configured for the Coder agent")
|
||||
return {
|
||||
"feedback": "The Coder agent is not properly configured.",
|
||||
|
|
@ -121,13 +122,13 @@ class AgentCoder(AgentBase):
|
|||
"documents": quick_completion.get("documents", [])
|
||||
}
|
||||
else:
|
||||
logger.debug(f"Code to generate, quick check responded: {quick_completion.get("prompt", "(no answer)")}")
|
||||
logger.debug(f"Code to generate, quick check responded: {quick_completion.get('prompt', '(no answer)')}")
|
||||
|
||||
# If quick completion not possible, continue with code generation and execution
|
||||
logger.info("Generating code to solve the task")
|
||||
|
||||
# 4. Generate code using AI
|
||||
code, requirements = await self._generate_code(prompt, document_data)
|
||||
code, requirements = await self._generate_code(prompt)
|
||||
|
||||
if not code:
|
||||
return {
|
||||
|
|
@ -136,21 +137,69 @@ class AgentCoder(AgentBase):
|
|||
}
|
||||
|
||||
# 5. Replace the placeholder with actual input_files data
|
||||
document_data_json = json.dumps(document_data)
|
||||
document_data_json = repr(document_data)
|
||||
code_with_data = code.replace("input_files = \"=== JSONLOAD ===\"", f"input_files = {document_data_json}")
|
||||
|
||||
# 6. Execute code and get results
|
||||
# 6. Execute code with retry logic
|
||||
retry_count = 0
|
||||
max_retries = self.execution_retry_limit
|
||||
execution_history = []
|
||||
|
||||
while retry_count <= max_retries:
|
||||
execution_result = self._execute_code(code_with_data, requirements)
|
||||
execution_history.append({
|
||||
"attempt": retry_count + 1,
|
||||
"code": code_with_data,
|
||||
"result": execution_result
|
||||
})
|
||||
|
||||
# Check if execution was successful
|
||||
if execution_result.get("success", False):
|
||||
logger.info(f"Code execution succeeded on attempt {retry_count + 1}")
|
||||
break
|
||||
|
||||
# If we've reached max retries, exit the loop
|
||||
if retry_count >= max_retries:
|
||||
logger.info(f"Reached maximum retry limit ({max_retries}). Giving up.")
|
||||
break
|
||||
|
||||
# Log the error and attempt to improve the code
|
||||
error = execution_result.get("error", "Unknown error")
|
||||
logger.info(f"Execution attempt {retry_count + 1} failed: {error}. Attempting to improve code.")
|
||||
|
||||
# Generate improved code based on error
|
||||
improved_code, improved_requirements = await self._improve_code(
|
||||
original_code=code_with_data,
|
||||
error=error,
|
||||
execution_result=execution_result,
|
||||
attempt=retry_count + 1
|
||||
)
|
||||
|
||||
if improved_code:
|
||||
code_with_data = improved_code
|
||||
requirements = improved_requirements
|
||||
logger.info(f"Code improved for retry {retry_count + 2}")
|
||||
else:
|
||||
logger.warning("Failed to improve code, using original code for retry")
|
||||
|
||||
retry_count += 1
|
||||
|
||||
# 7. Process results and create output documents
|
||||
documents = []
|
||||
|
||||
# Always add the code document
|
||||
# Always add the final code document
|
||||
documents.append({
|
||||
"label": "generated_code.py",
|
||||
"content": code_with_data
|
||||
})
|
||||
|
||||
# Add execution history document
|
||||
execution_history_str = json.dumps(execution_history, indent=2)
|
||||
documents.append({
|
||||
"label": "execution_history.json",
|
||||
"content": execution_history_str
|
||||
})
|
||||
|
||||
# Create documents based on execution results
|
||||
if execution_result.get("success", False):
|
||||
result_data = execution_result.get("result")
|
||||
|
|
@ -179,6 +228,9 @@ class AgentCoder(AgentBase):
|
|||
"content": execution_result.get("output", "")
|
||||
})
|
||||
|
||||
if retry_count > 0:
|
||||
feedback = f"Code executed successfully after {retry_count + 1} attempts. Generated output files based on specifications."
|
||||
else:
|
||||
feedback = "Code executed successfully. Generated output files based on specifications."
|
||||
else:
|
||||
# Execution failed
|
||||
|
|
@ -187,6 +239,10 @@ class AgentCoder(AgentBase):
|
|||
"label": "execution_error.txt",
|
||||
"content": f"Error executing code:\n\n{error}"
|
||||
})
|
||||
|
||||
if retry_count > 0:
|
||||
feedback = f"Error during code execution after {retry_count + 1} attempts: {error}"
|
||||
else:
|
||||
feedback = f"Error during code execution: {error}"
|
||||
|
||||
return {
|
||||
|
|
@ -194,6 +250,81 @@ class AgentCoder(AgentBase):
|
|||
"documents": documents
|
||||
}
|
||||
|
||||
async def _improve_code(self, original_code: str, error: str, execution_result: Dict[str, Any], attempt: int) -> Tuple[str, List[str]]:
|
||||
"""
|
||||
Improve code based on execution error.
|
||||
|
||||
Args:
|
||||
original_code: The code that failed to execute
|
||||
error: The error message
|
||||
execution_result: Complete execution result dictionary
|
||||
attempt: Current attempt number
|
||||
|
||||
Returns:
|
||||
Tuple of (improved_code, requirements)
|
||||
"""
|
||||
# Create prompt for code improvement
|
||||
improvement_prompt = f"""
|
||||
Fix the following Python code that failed during execution. This is attempt {attempt} to fix the code.
|
||||
|
||||
ORIGINAL CODE:
|
||||
{original_code}
|
||||
|
||||
ERROR MESSAGE:
|
||||
{error}
|
||||
|
||||
STDOUT:
|
||||
{execution_result.get('output', '')}
|
||||
|
||||
INSTRUCTIONS:
|
||||
1. Fix all errors identified in the error message
|
||||
2. Diagnose and fix any logical issues
|
||||
3. Pay special attention to:
|
||||
- Type conversions and data handling
|
||||
- Error handling and edge cases
|
||||
- Resource management (file handles, etc.)
|
||||
- Syntax errors and typos
|
||||
4. Keep the input_files handling logic intact
|
||||
5. Maintain the same overall structure and purpose
|
||||
|
||||
OUTPUT:
|
||||
- Your improved code MUST still define a 'result' variable as a dictionary
|
||||
- Each output file should be a key in the result dictionary
|
||||
- DO NOT remove the input_files assignment line structure
|
||||
|
||||
REQUIREMENTS:
|
||||
Required packages should be specified as:
|
||||
# REQUIREMENTS: library==version,library2>=version
|
||||
- You may add/remove requirements as needed to fix the code
|
||||
|
||||
Return ONLY Python code without explanations or markdown.
|
||||
"""
|
||||
|
||||
# Call AI service
|
||||
messages = [
|
||||
{"role": "system", "content": "You are an expert Python code debugger. Provide only fixed Python code without explanations or formatting."},
|
||||
{"role": "user", "content": improvement_prompt}
|
||||
]
|
||||
|
||||
try:
|
||||
improved_content = await self.mydom.call_ai(messages, temperature=0.2)
|
||||
|
||||
# Extract code and requirements
|
||||
improved_code = self._clean_code(improved_content)
|
||||
|
||||
# Extract requirements
|
||||
requirements = []
|
||||
for line in improved_code.split('\n'):
|
||||
if line.strip().startswith("# REQUIREMENTS:"):
|
||||
req_str = line.replace("# REQUIREMENTS:", "").strip()
|
||||
requirements = [r.strip() for r in req_str.split(',') if r.strip()]
|
||||
break
|
||||
|
||||
return improved_code, requirements
|
||||
except Exception as e:
|
||||
logger.error(f"Error improving code: {str(e)}")
|
||||
return None, []
|
||||
|
||||
async def _check_quick_completion(self, prompt: str, content_extraction: List[Dict], output_specs: List[Dict]) -> Dict:
|
||||
"""
|
||||
Check if the task can be completed without writing and executing code.
|
||||
|
|
@ -245,7 +376,7 @@ Only return valid JSON. Your entire response must be parseable as JSON.
|
|||
"""
|
||||
|
||||
# Call AI service
|
||||
logger.debug("Checking if task can be completed without code execution")
|
||||
logger.debug(f"Checking if task can be completed without code execution: {check_prompt}")
|
||||
messages = [
|
||||
{"role": "system", "content": "You are an AI assistant that determines if tasks require code execution. Reply with JSON only."},
|
||||
{"role": "user", "content": check_prompt}
|
||||
|
|
@ -253,7 +384,7 @@ Only return valid JSON. Your entire response must be parseable as JSON.
|
|||
|
||||
try:
|
||||
# Use a lower temperature for more deterministic response
|
||||
response = await self.ai_service.call_api(messages, temperature=0.1)
|
||||
response = await self.mydom.call_ai(messages, produce_user_answer = True, temperature=0.1)
|
||||
|
||||
# Parse response as JSON
|
||||
if response:
|
||||
|
|
@ -279,7 +410,7 @@ Only return valid JSON. Your entire response must be parseable as JSON.
|
|||
# Default to requiring code execution
|
||||
return None
|
||||
|
||||
async def _generate_code(self, prompt: str, input_files: List) -> Tuple[str, List[str]]:
|
||||
async def _generate_code(self, prompt: str) -> Tuple[str, List[str]]:
|
||||
"""
|
||||
Generate Python code from a prompt with the input_files placeholder.
|
||||
|
||||
|
|
@ -297,20 +428,19 @@ Generate Python code to solve the following task:
|
|||
TASK:
|
||||
{prompt}
|
||||
|
||||
IMPORTANT:
|
||||
- All input files are provided in the 'input_files' variable as a list of [filename, data, is_base64].
|
||||
- The 'input_files' variable is already defined at the top of your code, DO NOT modify it.
|
||||
- For each file, you can access:
|
||||
- filename: The name of the file (e.g., "image.png")
|
||||
- data: The content of the file (base64 encoded or plain text)
|
||||
- is_base64: Boolean flag indicating if the data is base64 encoded
|
||||
INPUT FILES:
|
||||
- 'input_files' variable is provided as [[filename, data, is_base64], ...]
|
||||
- For text files (is_base64=False): use data directly as string
|
||||
- For binary files (is_base64=True): use base64.b64decode(data)
|
||||
|
||||
- To use a file's data:
|
||||
- For text files (when is_base64=False): Use the data directly as a string
|
||||
- For binary files (when is_base64=True): Use base64.b64decode(data) to get bytes
|
||||
|
||||
- Do not perform any additional base64 detection - rely on the is_base64 flag
|
||||
CODE QUALITY:
|
||||
- Use explicit type conversions where needed (int/float/str)
|
||||
- Implement feature detection, not version checks
|
||||
- Handle errors gracefully with appropriate fallbacks
|
||||
- Follow latest API conventions for libraries
|
||||
- Validate inputs before processing
|
||||
|
||||
OUTPUT:
|
||||
- Your code MUST define a 'result' variable as a dictionary to store outputs.
|
||||
- Each output file should be a key in the result dictionary.
|
||||
- For example: result = {{"output.txt": "output text", "results.json": json_string}}
|
||||
|
|
@ -318,10 +448,13 @@ IMPORTANT:
|
|||
Your code must start with:
|
||||
input_files = "=== JSONLOAD ===" # DO NOT CHANGE THIS LINE
|
||||
|
||||
REQUIREMENTS:
|
||||
Required packages should be specified as:
|
||||
# REQUIREMENTS: package1,package2,package3
|
||||
# REQUIREMENTS: library==version,library2>=version
|
||||
- Specify exact versions for critical libraries
|
||||
- Use constraint operators (==,>=,<=) as needed
|
||||
|
||||
Return ONLY Python code without explanations or markdown formatting.
|
||||
Return ONLY Python code without explanations or markdown.
|
||||
"""
|
||||
|
||||
# Call AI service
|
||||
|
|
@ -330,7 +463,7 @@ Return ONLY Python code without explanations or markdown formatting.
|
|||
{"role": "user", "content": ai_prompt}
|
||||
]
|
||||
|
||||
generated_content = await self.ai_service.call_api(messages, temperature=0.1)
|
||||
generated_content = await self.mydom.call_ai(messages, temperature=0.1)
|
||||
|
||||
# Extract code and requirements
|
||||
code = self._clean_code(generated_content)
|
||||
|
|
@ -372,20 +505,23 @@ Return ONLY Python code without explanations or markdown formatting.
|
|||
|
||||
# 2. Install requirements if provided
|
||||
if requirements:
|
||||
logger.debug(f"Installing requirements: {requirements}")
|
||||
logger.info(f"Installing requirements: {requirements}")
|
||||
|
||||
# Create requirements.txt
|
||||
req_file = os.path.join(self.temp_dir, "requirements.txt")
|
||||
with open(req_file, "w") as f:
|
||||
f.write("\n".join(requirements))
|
||||
|
||||
x="\n".join(requirements)
|
||||
logger.info(f"Requirements file: {x}.")
|
||||
|
||||
# Install requirements
|
||||
try:
|
||||
pip_result = subprocess.run(
|
||||
[python_exe, "-m", "pip", "install", "-r", req_file],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=APP_CONFIG.get("Agent_Coder_INSTALL_TIMEOUT")
|
||||
timeout=int(APP_CONFIG.get("Agent_Coder_INSTALL_TIMEOUT"))
|
||||
)
|
||||
if pip_result.returncode != 0:
|
||||
logger.debug(f"Error installing requirements: {pip_result.stderr}")
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ class AgentDocumentation(AgentBase):
|
|||
"knowledge_organization"
|
||||
]
|
||||
|
||||
def set_dependencies(self, ai_service=None):
|
||||
def set_dependencies(self, mydom=None):
|
||||
"""Set external dependencies for the agent."""
|
||||
self.ai_service = ai_service
|
||||
self.mydom = mydom
|
||||
|
||||
async def process_task(self, task: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
@ -48,7 +48,7 @@ class AgentDocumentation(AgentBase):
|
|||
output_specs = task.get("output_specifications", [])
|
||||
|
||||
# Check AI service
|
||||
if not self.ai_service:
|
||||
if not self.mydom:
|
||||
return {
|
||||
"feedback": "The Documentation agent requires an AI service to function.",
|
||||
"documents": []
|
||||
|
|
@ -201,7 +201,7 @@ class AgentDocumentation(AgentBase):
|
|||
"""
|
||||
|
||||
try:
|
||||
response = await self.ai_service.call_api([
|
||||
response = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a documentation expert. Respond with valid JSON only."},
|
||||
{"role": "user", "content": analysis_prompt}
|
||||
])
|
||||
|
|
@ -371,10 +371,10 @@ class AgentDocumentation(AgentBase):
|
|||
The introduction should be professional and engaging, formatted according to {format_type} standards.
|
||||
"""
|
||||
|
||||
introduction = await self.ai_service.call_api([
|
||||
introduction = await self.mydom.call_ai([
|
||||
{"role": "system", "content": f"You are a documentation expert creating an introduction in {format_type} format."},
|
||||
{"role": "user", "content": intro_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
|
||||
# Step 2: Generate executive summary (if applicable)
|
||||
if document_type in ["report", "whitepaper", "case study"]:
|
||||
|
|
@ -397,10 +397,10 @@ class AgentDocumentation(AgentBase):
|
|||
Keep the summary focused and impactful, approximately 200-300 words.
|
||||
"""
|
||||
|
||||
executive_summary = await self.ai_service.call_api([
|
||||
executive_summary = await self.mydom.call_ai([
|
||||
{"role": "system", "content": f"You are a documentation expert creating an executive summary in {format_type} format."},
|
||||
{"role": "user", "content": summary_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
else:
|
||||
executive_summary = ""
|
||||
|
||||
|
|
@ -447,10 +447,10 @@ class AgentDocumentation(AgentBase):
|
|||
Be thorough in your coverage of this section, providing substantive content.
|
||||
"""
|
||||
|
||||
section_content = await self.ai_service.call_api([
|
||||
section_content = await self.mydom.call_ai([
|
||||
{"role": "system", "content": f"You are a documentation expert creating detailed content for the {section_title} section."},
|
||||
{"role": "user", "content": section_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
|
||||
sections.append(section_content)
|
||||
|
||||
|
|
@ -474,10 +474,10 @@ class AgentDocumentation(AgentBase):
|
|||
The conclusion should be professional and impactful, formatted according to {format_type} standards.
|
||||
"""
|
||||
|
||||
conclusion = await self.ai_service.call_api([
|
||||
conclusion = await self.mydom.call_ai([
|
||||
{"role": "system", "content": f"You are a documentation expert creating a conclusion in {format_type} format."},
|
||||
{"role": "user", "content": conclusion_prompt}
|
||||
])
|
||||
], produce_user_answer = True)
|
||||
|
||||
# Step 5: Assemble the complete document
|
||||
if format_type in ["md", "markdown"]:
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ class AgentWebcrawler(AgentBase):
|
|||
self.search_engine = APP_CONFIG.get("Agent_Webcrawler_SEARCH_ENGINE", "https://html.duckduckgo.com/html/?q=")
|
||||
self.user_agent = APP_CONFIG.get("Agent_Webcrawler_USER_AGENT", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
|
||||
|
||||
def set_dependencies(self, ai_service=None):
|
||||
def set_dependencies(self, mydom=None):
|
||||
"""Set external dependencies for the agent."""
|
||||
self.ai_service = ai_service
|
||||
self.mydom = mydom
|
||||
|
||||
async def process_task(self, task: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
@ -63,7 +63,7 @@ class AgentWebcrawler(AgentBase):
|
|||
output_specs = task.get("output_specifications", [])
|
||||
|
||||
# Check AI service
|
||||
if not self.ai_service:
|
||||
if not self.mydom:
|
||||
return {
|
||||
"feedback": "The Webcrawler agent requires an AI service to function effectively.",
|
||||
"documents": []
|
||||
|
|
@ -134,7 +134,7 @@ class AgentWebcrawler(AgentBase):
|
|||
|
||||
try:
|
||||
# Get research plan from AI
|
||||
response = await self.ai_service.call_api([
|
||||
response = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You are a web research planning expert. Create precise research plans in JSON format only."},
|
||||
{"role": "user", "content": research_prompt}
|
||||
])
|
||||
|
|
@ -295,8 +295,8 @@ class AgentWebcrawler(AgentBase):
|
|||
Only include information actually found in the content. No fabrications or assumptions.
|
||||
"""
|
||||
|
||||
if self.ai_service:
|
||||
summary = await self.ai_service.call_api([
|
||||
if self.mydom:
|
||||
summary = await self.mydom.call_ai([
|
||||
{"role": "system", "content": "You summarize web content accurately and concisely, focusing only on what is actually in the content."},
|
||||
{"role": "user", "content": summary_prompt}
|
||||
])
|
||||
|
|
@ -449,7 +449,7 @@ class AgentWebcrawler(AgentBase):
|
|||
|
||||
try:
|
||||
# Generate report with AI
|
||||
report_content = await self.ai_service.call_api([
|
||||
report_content = await self.mydom.call_ai([
|
||||
{"role": "system", "content": f"You create professional research reports in {template_format} format."},
|
||||
{"role": "user", "content": report_prompt}
|
||||
])
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ class AgentBase:
|
|||
self.name = "base-agent"
|
||||
self.description = "Basic agent functionality"
|
||||
self.capabilities = []
|
||||
self.ai_service = None
|
||||
self.mydom = None
|
||||
|
||||
def set_dependencies(self, ai_service=None):
|
||||
def set_dependencies(self, mydom=None):
|
||||
"""Set external dependencies for the agent."""
|
||||
self.ai_service = ai_service
|
||||
self.mydom = mydom
|
||||
|
||||
def get_agent_info(self) -> Dict[str, Any]:
|
||||
"""
|
||||
|
|
@ -88,7 +88,7 @@ class AgentRegistry:
|
|||
raise RuntimeError("Singleton instance already exists - use get_instance()")
|
||||
|
||||
self.agents = {}
|
||||
self.ai_service = None
|
||||
self.mydom = None
|
||||
self._load_agents()
|
||||
|
||||
def _load_agents(self):
|
||||
|
|
@ -146,16 +146,16 @@ class AgentRegistry:
|
|||
except Exception as e:
|
||||
logger.error(f"Error loading agent from module {module_name}: {e}")
|
||||
|
||||
def set_ai_service(self, ai_service):
|
||||
def set_mydom(self, mydom):
|
||||
"""Set the AI service for all agents."""
|
||||
self.ai_service = ai_service
|
||||
self.mydom = mydom
|
||||
self.update_agent_dependencies()
|
||||
|
||||
def update_agent_dependencies(self):
|
||||
"""Update dependencies for all registered agents."""
|
||||
for agent_id, agent in self.agents.items():
|
||||
if hasattr(agent, 'set_dependencies'):
|
||||
agent.set_dependencies(ai_service=self.ai_service)
|
||||
agent.set_dependencies(mydom=self.mydom)
|
||||
|
||||
def register_agent(self, agent):
|
||||
"""
|
||||
|
|
@ -167,7 +167,7 @@ class AgentRegistry:
|
|||
agent_id = getattr(agent, 'name', "unknown_agent")
|
||||
# Initialize agent with dependencies
|
||||
if hasattr(agent, 'set_dependencies'):
|
||||
agent.set_dependencies(ai_service=self.ai_service)
|
||||
agent.set_dependencies(mydom=self.mydom)
|
||||
self.agents[agent_id] = agent
|
||||
logger.debug(f"Agent '{agent.name}' registered")
|
||||
|
||||
|
|
@ -182,8 +182,8 @@ class AgentRegistry:
|
|||
if agent_identifier in self.agents:
|
||||
agent = self.agents[agent_identifier]
|
||||
# Ensure the agent has the AI service
|
||||
if hasattr(agent, 'set_dependencies') and self.ai_service:
|
||||
agent.set_dependencies(ai_service=self.ai_service)
|
||||
if hasattr(agent, 'set_dependencies') and self.mydom:
|
||||
agent.set_dependencies(mydom=self.mydom)
|
||||
return agent
|
||||
logger.error(f"Agent with identifier '{agent_identifier}' not found")
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Interface to LucyDOM database.
|
||||
Interface to LucyDOM database and AI Connectors.
|
||||
Uses the JSON connector for data access with added language support.
|
||||
"""
|
||||
|
||||
|
|
@ -12,9 +12,12 @@ from typing import Dict, Any, List, Optional, Union
|
|||
import importlib
|
||||
import hashlib
|
||||
|
||||
# DYNAMIC PART: Connectors to the Interface
|
||||
from connectors.connector_db_json import DatabaseConnector
|
||||
from modules.configuration import APP_CONFIG
|
||||
from connectors.connector_aichat_openai import ChatService
|
||||
|
||||
# Basic Configurations
|
||||
from modules.configuration import APP_CONFIG
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Custom exceptions for file handling
|
||||
|
|
@ -132,18 +135,12 @@ class LucyDOMInterface:
|
|||
|
||||
# Language support methods
|
||||
|
||||
def set_ai_service(self, ai_service):
|
||||
"""Set the AI service for API calls"""
|
||||
self.ai_service = ai_service
|
||||
|
||||
def set_user_language(self, language_code: str):
|
||||
"""Set the user's preferred language"""
|
||||
self.user_language = language_code
|
||||
logger.info(f"User language set to: {language_code}")
|
||||
|
||||
async def call_ai(self, messages: List[Dict[str, str]],
|
||||
produce_user_answer: bool = False,
|
||||
temperature: float = None) -> str:
|
||||
async def call_ai(self, messages: List[Dict[str, str]], produce_user_answer: bool = False, temperature: float = None) -> str:
|
||||
"""
|
||||
Enhanced AI service call with language support
|
||||
|
||||
|
|
@ -161,14 +158,15 @@ class LucyDOMInterface:
|
|||
|
||||
# Add language instruction for user-facing responses
|
||||
if produce_user_answer and self.user_language:
|
||||
ltext= f"Please respond in '{self.user_language}' language."
|
||||
if messages and messages[0]["role"] == "system":
|
||||
if "language" not in messages[0]["content"].lower():
|
||||
messages[0]["content"] = f"Please respond in {self.user_language} language. {messages[0]['content']}"
|
||||
messages[0]["content"] = f"{ltext} {messages[0]['content']}"
|
||||
else:
|
||||
# Insert a system message with language instruction
|
||||
messages.insert(0, {
|
||||
"role": "system",
|
||||
"content": f"Please respond in {self.user_language} language."
|
||||
"content": ltext
|
||||
})
|
||||
|
||||
# Call the AI service
|
||||
|
|
@ -636,7 +634,7 @@ class LucyDOMInterface:
|
|||
self.create_file_data(db_file["id"], file_content)
|
||||
|
||||
# Debug: Export file to static folder
|
||||
if logger.isEnabledFor(logging.DEBUG): self._export_file_to_static(file_content, db_file["id"], file_name)
|
||||
self._export_file_to_static(file_content, db_file["id"], file_name) # DEBUG TODO
|
||||
|
||||
# Debug: Verify database record was created
|
||||
if not db_file:
|
||||
|
|
@ -1174,7 +1172,7 @@ class LucyDOMInterface:
|
|||
"message": log.get("message", ""),
|
||||
"type": log.get("type", "info"),
|
||||
"timestamp": log.get("timestamp", self._get_current_timestamp()),
|
||||
"agent_name": log.get("agent_name", GLOBAL_SETTINGS.get("system_name", "AI Assistant")),
|
||||
"agent_name": log.get("agent_name", "(undefined)"),
|
||||
"status": log.get("status", "running"),
|
||||
"progress": log.get("progress", 50)
|
||||
}
|
||||
|
|
@ -1250,17 +1248,6 @@ class LucyDOMInterface:
|
|||
logger.error(f"Error loading workflow state: {str(e)}")
|
||||
return None
|
||||
|
||||
# Global settings for the LucyDOM interface
|
||||
GLOBAL_SETTINGS = {
|
||||
"system_name": "AI Assistant", # Default system name for logs
|
||||
"workflow_status_messages": {
|
||||
"init": "Workflow initialized",
|
||||
"running": "Running workflow",
|
||||
"waiting": "Waiting for input",
|
||||
"completed": "Workflow completed",
|
||||
"error": "Error in workflow"
|
||||
}
|
||||
}
|
||||
|
||||
# Singleton factory for LucyDOMInterface instances per context
|
||||
_lucydom_interfaces = {}
|
||||
|
|
@ -1272,7 +1259,12 @@ def get_lucydom_interface(mandate_id: int = 0, user_id: int = 0) -> LucyDOMInter
|
|||
"""
|
||||
context_key = f"{mandate_id}_{user_id}"
|
||||
if context_key not in _lucydom_interfaces:
|
||||
_lucydom_interfaces[context_key] = LucyDOMInterface(mandate_id, user_id)
|
||||
# Create new interface instance
|
||||
interface = LucyDOMInterface(mandate_id, user_id)
|
||||
# Initialize AI service
|
||||
ai_service = ChatService()
|
||||
interface.ai_service = ai_service # Directly set the attribute
|
||||
_lucydom_interfaces[context_key] = interface
|
||||
return _lucydom_interfaces[context_key]
|
||||
|
||||
# Init
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ class FileData(BaseModel):
|
|||
id: int = Field(description="Unique ID of the data object")
|
||||
data: str = Field(description="Binary content of the file as base64 string")
|
||||
|
||||
|
||||
# Workflow model classes
|
||||
|
||||
class DocumentContent(BaseModel):
|
||||
|
|
@ -99,7 +100,7 @@ class DataStats(BaseModel):
|
|||
bytes_sent: Optional[int] = Field(None, description="Bytes sent")
|
||||
bytes_received: Optional[int] = Field(None, description="Bytes received")
|
||||
|
||||
class Message(BaseModel):
|
||||
class WorkflowMessage(BaseModel):
|
||||
"""Message object in the workflow"""
|
||||
id: str = Field(description="Unique ID of the message")
|
||||
workflow_id: str = Field(description="Reference to the parent workflow")
|
||||
|
|
@ -116,6 +117,19 @@ class Message(BaseModel):
|
|||
content: Optional[str] = Field(None, description="Text content of the message")
|
||||
agent_name: Optional[str] = Field(None, description="Name of the agent used")
|
||||
|
||||
class WorkflowLog(BaseModel):
|
||||
"""Log entry for a workflow"""
|
||||
id: str = Field(description="Unique ID of the log entry")
|
||||
workflow_id: str = Field(description="ID of the associated workflow")
|
||||
message: str = Field(description="Log message content")
|
||||
type: str = Field(description="Type of log ('info', 'warning', 'error')")
|
||||
timestamp: str = Field(description="Timestamp of the log entry")
|
||||
agent_name: str = Field(description="Name of the agent that created the log")
|
||||
status: str = Field(description="Status of the workflow at log time")
|
||||
progress: Optional[int] = Field(None, description="Progress value (0-100)")
|
||||
mandate_id: Optional[int] = Field(None, description="ID of the mandate")
|
||||
user_id: Optional[int] = Field(None, description="ID of the user")
|
||||
|
||||
class Workflow(BaseModel):
|
||||
"""Workflow object for multi-agent system"""
|
||||
id: str = Field(description="Unique ID of the workflow")
|
||||
|
|
@ -125,11 +139,13 @@ class Workflow(BaseModel):
|
|||
status: str = Field(description="Status of the workflow ('running', 'completed')")
|
||||
started_at: str = Field(description="Start timestamp")
|
||||
last_activity: str = Field(description="Timestamp of the last activity")
|
||||
data_stats: Optional[Dict[str, Any]] = Field(None, description="Total statistics")
|
||||
current_round: int = Field(default=1, description="Current round/iteration of the workflow")
|
||||
message_ids: List[str] = Field(default=[], description="List of message IDs in this workflow")
|
||||
|
||||
data_stats: Optional[Dict[str, Any]] = Field(None, description="Total statistics")
|
||||
messages: List[Message] = Field(default=[], description="Message history")
|
||||
logs: List[Dict[str, Any]] = Field(default=[], description="Log entries")
|
||||
messages: List[WorkflowMessage] = Field(default=[], description="Message history (in-memory representation)")
|
||||
logs: List[WorkflowLog] = Field(default=[], description="Log entries (in-memory representation)")
|
||||
|
||||
|
||||
# Request models for the API
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ FRONTEND:
|
|||
PRIO1:
|
||||
|
||||
|
||||
CHECK: If pictures not displayed to check utf-8 encoding in the base64 string!!
|
||||
|
||||
STOP File export to static folder ("TODO)
|
||||
|
||||
add connector to myoutlook
|
||||
|
||||
todo an agent for "code writing and editing" connected to the codebase, working in loops over each document...
|
||||
|
|
@ -26,8 +30,6 @@ Split big files into content-parts
|
|||
|
||||
PRIO2:
|
||||
|
||||
implement cleanup routines for files in lucydom_interface (File_Management_CLEANUP_INTERVAL): temp older than interval, all orphaned
|
||||
|
||||
Integrate NDA Text as modal form - Data governance agreement by login with checkbox
|
||||
|
||||
frontend to react
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
This is a test text file for the ChatManager workflow.
|
||||
It contains some information for testing document processing.
|
||||
|
||||
The ChatManager should be able to process this file
|
||||
and extract relevant information from it.
|
||||
|
||||
This file serves as an example for text-based documents that can be
|
||||
used in a chat workflow.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 284 B |
|
|
@ -1,52 +0,0 @@
|
|||
# REQUIREMENTS: Pillow
|
||||
|
||||
from PIL import Image
|
||||
|
||||
def calculate_image_pixels(image_path):
|
||||
try:
|
||||
with Image.open(image_path) as img:
|
||||
width, height = img.size
|
||||
total_pixels = width * height
|
||||
return total_pixels
|
||||
except Exception as e:
|
||||
print(f"Error calculating image pixels: {e}")
|
||||
return None
|
||||
|
||||
def calculate_text_characters(text_path):
|
||||
try:
|
||||
with open(text_path, 'r', encoding='utf-8') as file:
|
||||
text = file.read()
|
||||
total_characters = len(text)
|
||||
return total_characters
|
||||
except Exception as e:
|
||||
print(f"Error calculating text characters: {e}")
|
||||
return None
|
||||
|
||||
def main():
|
||||
image_path = 'test_image'
|
||||
text_path = 'test_document'
|
||||
|
||||
# Calculate total pixels in the image
|
||||
total_pixels = calculate_image_pixels(image_path)
|
||||
|
||||
# Calculate total characters in the text document
|
||||
total_characters = calculate_text_characters(text_path)
|
||||
|
||||
# Prepare the result dictionary
|
||||
result = {
|
||||
'total_pixels': total_pixels,
|
||||
'total_characters': total_characters
|
||||
}
|
||||
|
||||
# Write the result to a text file
|
||||
try:
|
||||
with open('result.txt', 'w') as result_file:
|
||||
result_file.write(str(result))
|
||||
except Exception as e:
|
||||
print(f"Error writing result to file: {e}")
|
||||
|
||||
# Output the result
|
||||
print(result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
Execution error:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "C:\Users\pmots\AppData\Local\Temp\code_exec_itmq0xhw\code_9cc3911d.py", line 3, in <module>
|
||||
from PIL import Image
|
||||
ModuleNotFoundError: No module named 'PIL'
|
||||
50
test2.py
50
test2.py
|
|
@ -1,50 +0,0 @@
|
|||
from PIL import Image
|
||||
|
||||
def calculate_image_pixels(image_path):
|
||||
try:
|
||||
with Image.open(image_path) as img:
|
||||
width, height = img.size
|
||||
total_pixels = width * height
|
||||
return total_pixels
|
||||
except Exception as e:
|
||||
print(f"Error calculating image pixels: {e}")
|
||||
return None
|
||||
|
||||
def calculate_text_characters(text_path):
|
||||
try:
|
||||
with open(text_path, 'r', encoding='utf-8') as file:
|
||||
text = file.read()
|
||||
total_characters = len(text)
|
||||
return total_characters
|
||||
except Exception as e:
|
||||
print(f"Error calculating text characters: {e}")
|
||||
return None
|
||||
|
||||
def main():
|
||||
image_path = 'test_image'
|
||||
text_path = 'test_document'
|
||||
|
||||
# Calculate total pixels in the image
|
||||
total_pixels = calculate_image_pixels(image_path)
|
||||
|
||||
# Calculate total characters in the text document
|
||||
total_characters = calculate_text_characters(text_path)
|
||||
|
||||
# Prepare the result dictionary
|
||||
result = {
|
||||
'total_pixels': total_pixels,
|
||||
'total_characters': total_characters
|
||||
}
|
||||
|
||||
# Write the result to a text file
|
||||
try:
|
||||
with open('result.txt', 'w') as result_file:
|
||||
result_file.write(str(result))
|
||||
except Exception as e:
|
||||
print(f"Error writing result to file: {e}")
|
||||
|
||||
# Output the result
|
||||
print(result)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -13,7 +13,7 @@ from datetime import datetime
|
|||
|
||||
# Configure logging
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG,
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(name)s - %(message)s',
|
||||
handlers=[logging.StreamHandler()]
|
||||
)
|
||||
|
|
@ -112,7 +112,7 @@ async def run_chat_workflow(mandate_id: int, user_id: int, file_ids: List[int])
|
|||
|
||||
# Create user request
|
||||
user_input = {
|
||||
"prompt": "Bitte zähle mir zusammen wieviele Pixel das Bild hat und wieviele Zeichen der Text der Dokumente hat",
|
||||
"prompt": "Bitte integriere den Text der Datei ins angefügte Bild",
|
||||
"list_file_id": file_ids
|
||||
}
|
||||
|
||||
|
|
|
|||
66
testcode.py
Normal file
66
testcode.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
input_files = [['test_document.txt', 'CiAgICBUaGlzIGlzIGEgdGVzdCB0ZXh0IGZpbGUgZm9yIHRoZSBDaGF0TWFuYWdlciB3b3JrZmxvdy4KICAgIEl0IGNvbnRhaW5zIHNvbWUgaW5mb3JtYXRpb24gZm9yIHRlc3RpbmcgZG9jdW1lbnQgcHJvY2Vzc2luZy4KICAgIAogICAgVGhlIENoYXRNYW5hZ2VyIHNob3VsZCBiZSBhYmxlIHRvIHByb2Nlc3MgdGhpcyBmaWxlCiAgICBhbmQgZXh0cmFjdCByZWxldmFudCBpbmZvcm1hdGlvbiBmcm9tIGl0LgogICAgCiAgICBUaGlzIGZpbGUgc2VydmVzIGFzIGFuIGV4YW1wbGUgZm9yIHRleHQtYmFzZWQgZG9jdW1lbnRzIHRoYXQgY2FuIGJlCiAgICB1c2VkIGluIGEgY2hhdCB3b3JrZmxvdy4KICAgIA==', True], ['test_document.txt', '\n This is a test text file for the ChatManager workflow.\n It contains some information for testing document processing.\n \n The ChatManager should be able to process this file\n and extract relevant information from it.\n \n This file serves as an example for text-based documents that can be\n used in a chat workflow.\n ', False], ['test_image.png', 'iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAA40lEQVR4nO3QsQEAIAyAsOr/P+sLZU9mJs4btu66xKzCrMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArMCswKzArNn7il4Bx2GaB88AAAAASUVORK5CYII=', True], ['test_image.png', 'Image (100x100, PNG, RGB)', False]] # DO NOT CHANGE THIS LINE
|
||||
|
||||
# REQUIREMENTS: Pillow==10.0.0
|
||||
|
||||
import base64
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
import io
|
||||
|
||||
# Initialize result dictionary
|
||||
result = {}
|
||||
|
||||
# Helper function to decode base64 data
|
||||
def decode_base64(data: str) -> bytes:
|
||||
return base64.b64decode(data)
|
||||
|
||||
# Extract input files
|
||||
text_data = None
|
||||
image_data = None
|
||||
|
||||
for file_info in input_files:
|
||||
filename, data, is_base64 = file_info
|
||||
if filename == 'test_document.txt' and not is_base64:
|
||||
text_data = data
|
||||
elif filename == 'test_image.png' and is_base64:
|
||||
image_data = decode_base64(data)
|
||||
|
||||
# Validate inputs
|
||||
if text_data is None:
|
||||
raise ValueError("Text data not found in input files.")
|
||||
if image_data is None:
|
||||
raise ValueError("Image data not found in input files.")
|
||||
|
||||
# Load image
|
||||
image = Image.open(io.BytesIO(image_data))
|
||||
|
||||
# Prepare to draw on the image
|
||||
draw = ImageDraw.Draw(image)
|
||||
|
||||
# Use a basic font
|
||||
try:
|
||||
font = ImageFont.truetype("arial", 15)
|
||||
except IOError:
|
||||
font = ImageFont.load_default()
|
||||
|
||||
# Define text position
|
||||
text_position = (10, 10)
|
||||
|
||||
# Overlay text onto image
|
||||
draw.text(text_position, text_data, font=font, fill=(255, 255, 255))
|
||||
|
||||
# Save the resulting image to a bytes buffer
|
||||
output_buffer = io.BytesIO()
|
||||
image.save(output_buffer, format='PNG')
|
||||
output_buffer.seek(0)
|
||||
|
||||
#result['integrated_image.png'] = base64.b64encode(output_buffer.getvalue()).decode('utf-8')
|
||||
# binary_data = base64.b64decode(pic_str)
|
||||
binary_data=output_buffer.getvalue()
|
||||
|
||||
# Write the binary data to a file
|
||||
with open("./static/test_output.png", "wb") as f:
|
||||
f.write(binary_data)
|
||||
|
||||
print("OK")
|
||||
# Output the result dictionary
|
||||
result
|
||||
Loading…
Reference in a new issue