Feature/enable intuitive logs for community challenge step 1 (#3695)
parent
479c7468b4
commit
26c6cfeefd
|
@ -1,3 +1,5 @@
|
|||
from datetime import datetime
|
||||
|
||||
from colorama import Fore, Style
|
||||
|
||||
from autogpt.app import execute_command, get_command
|
||||
|
@ -6,6 +8,11 @@ from autogpt.json_utils.json_fix_llm import fix_json_using_multiple_techniques
|
|||
from autogpt.json_utils.utilities import LLM_DEFAULT_RESPONSE_FORMAT, validate_json
|
||||
from autogpt.llm import chat_with_ai, create_chat_completion, create_chat_message
|
||||
from autogpt.llm.token_counter import count_string_tokens
|
||||
from autogpt.log_cycle.log_cycle import (
|
||||
FULL_MESSAGE_HISTORY_FILE_NAME,
|
||||
NEXT_ACTION_FILE_NAME,
|
||||
LogCycleHandler,
|
||||
)
|
||||
from autogpt.logs import logger, print_assistant_thoughts
|
||||
from autogpt.speech import say_text
|
||||
from autogpt.spinner import Spinner
|
||||
|
@ -68,22 +75,33 @@ class Agent:
|
|||
self.system_prompt = system_prompt
|
||||
self.triggering_prompt = triggering_prompt
|
||||
self.workspace = Workspace(workspace_directory, cfg.restrict_to_workspace)
|
||||
self.created_at = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
self.cycle_count = 0
|
||||
self.log_cycle_handler = LogCycleHandler()
|
||||
|
||||
def start_interaction_loop(self):
|
||||
# Interaction Loop
|
||||
cfg = Config()
|
||||
loop_count = 0
|
||||
self.cycle_count = 0
|
||||
command_name = None
|
||||
arguments = None
|
||||
user_input = ""
|
||||
|
||||
while True:
|
||||
# Discontinue if continuous limit is reached
|
||||
loop_count += 1
|
||||
self.cycle_count += 1
|
||||
self.log_cycle_handler.log_count_within_cycle = 0
|
||||
self.log_cycle_handler.log_cycle(
|
||||
self.config.ai_name,
|
||||
self.created_at,
|
||||
self.cycle_count,
|
||||
self.full_message_history,
|
||||
FULL_MESSAGE_HISTORY_FILE_NAME,
|
||||
)
|
||||
if (
|
||||
cfg.continuous_mode
|
||||
and cfg.continuous_limit > 0
|
||||
and loop_count > cfg.continuous_limit
|
||||
and self.cycle_count > cfg.continuous_limit
|
||||
):
|
||||
logger.typewriter_log(
|
||||
"Continuous Limit Reached: ", Fore.YELLOW, f"{cfg.continuous_limit}"
|
||||
|
@ -122,6 +140,13 @@ class Agent:
|
|||
|
||||
except Exception as e:
|
||||
logger.error("Error: \n", str(e))
|
||||
self.log_cycle_handler.log_cycle(
|
||||
self.config.ai_name,
|
||||
self.created_at,
|
||||
self.cycle_count,
|
||||
assistant_reply_json,
|
||||
NEXT_ACTION_FILE_NAME,
|
||||
)
|
||||
|
||||
if not cfg.continuous_mode and self.next_action_count == 0:
|
||||
# ### GET USER AUTHORIZATION TO EXECUTE COMMAND ###
|
||||
|
|
|
@ -8,6 +8,7 @@ from autogpt.llm.api_manager import ApiManager
|
|||
from autogpt.llm.base import Message
|
||||
from autogpt.llm.llm_utils import create_chat_completion
|
||||
from autogpt.llm.token_counter import count_message_tokens
|
||||
from autogpt.log_cycle.log_cycle import PROMPT_NEXT_ACTION_FILE_NAME
|
||||
from autogpt.logs import logger
|
||||
from autogpt.memory_management.store_memory import (
|
||||
save_memory_trimmed_from_context_window,
|
||||
|
@ -231,6 +232,13 @@ def chat_with_ai(
|
|||
logger.debug(f"{message['role'].capitalize()}: {message['content']}")
|
||||
logger.debug("")
|
||||
logger.debug("----------- END OF CONTEXT ----------------")
|
||||
agent.log_cycle_handler.log_cycle(
|
||||
agent.config.ai_name,
|
||||
agent.created_at,
|
||||
agent.cycle_count,
|
||||
current_context,
|
||||
PROMPT_NEXT_ACTION_FILE_NAME,
|
||||
)
|
||||
|
||||
# TODO: use a model defined elsewhere, so that model can contain
|
||||
# temperature and other settings we care about
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import json
|
||||
import logging
|
||||
|
||||
|
||||
class JsonFileHandler(logging.FileHandler):
|
||||
def __init__(self, filename, mode="a", encoding=None, delay=False):
|
||||
super().__init__(filename, mode, encoding, delay)
|
||||
|
||||
def emit(self, record):
|
||||
json_data = json.loads(self.format(record))
|
||||
with open(self.baseFilename, "w", encoding="utf-8") as f:
|
||||
json.dump(json_data, f, ensure_ascii=False, indent=4)
|
||||
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
class JsonFormatter(logging.Formatter):
|
||||
def format(self, record):
|
||||
return record.msg
|
|
@ -0,0 +1,80 @@
|
|||
import json
|
||||
import os
|
||||
from typing import Any, Dict, Union
|
||||
|
||||
from autogpt.logs import logger
|
||||
|
||||
DEFAULT_PREFIX = "agent"
|
||||
FULL_MESSAGE_HISTORY_FILE_NAME = "full_message_history.json"
|
||||
PROMPT_NEXT_ACTION_FILE_NAME = "prompt_next_action.json"
|
||||
NEXT_ACTION_FILE_NAME = "next_action.json"
|
||||
|
||||
|
||||
class LogCycleHandler:
|
||||
"""
|
||||
A class for logging cycle data.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.log_count_within_cycle = 0
|
||||
|
||||
@staticmethod
|
||||
def create_directory_if_not_exists(directory_path: str) -> None:
|
||||
if not os.path.exists(directory_path):
|
||||
os.makedirs(directory_path, exist_ok=True)
|
||||
|
||||
def create_outer_directory(self, ai_name: str, created_at: str) -> str:
|
||||
log_directory = logger.get_log_directory()
|
||||
|
||||
if os.environ.get("OVERWRITE_DEBUG") == "1":
|
||||
outer_folder_name = "auto_gpt"
|
||||
else:
|
||||
ai_name_short = ai_name[:15] if ai_name else DEFAULT_PREFIX
|
||||
outer_folder_name = f"{created_at}_{ai_name_short}"
|
||||
|
||||
outer_folder_path = os.path.join(log_directory, "DEBUG", outer_folder_name)
|
||||
self.create_directory_if_not_exists(outer_folder_path)
|
||||
|
||||
return outer_folder_path
|
||||
|
||||
def create_inner_directory(self, outer_folder_path: str, cycle_count: int) -> str:
|
||||
nested_folder_name = str(cycle_count).zfill(3)
|
||||
nested_folder_path = os.path.join(outer_folder_path, nested_folder_name)
|
||||
self.create_directory_if_not_exists(nested_folder_path)
|
||||
|
||||
return nested_folder_path
|
||||
|
||||
def create_nested_directory(
|
||||
self, ai_name: str, created_at: str, cycle_count: int
|
||||
) -> str:
|
||||
outer_folder_path = self.create_outer_directory(ai_name, created_at)
|
||||
nested_folder_path = self.create_inner_directory(outer_folder_path, cycle_count)
|
||||
|
||||
return nested_folder_path
|
||||
|
||||
def log_cycle(
|
||||
self,
|
||||
ai_name: str,
|
||||
created_at: str,
|
||||
cycle_count: int,
|
||||
data: Union[Dict[str, Any], Any],
|
||||
file_name: str,
|
||||
) -> None:
|
||||
"""
|
||||
Log cycle data to a JSON file.
|
||||
|
||||
Args:
|
||||
data (Any): The data to be logged.
|
||||
file_name (str): The name of the file to save the logged data.
|
||||
"""
|
||||
nested_folder_path = self.create_nested_directory(
|
||||
ai_name, created_at, cycle_count
|
||||
)
|
||||
|
||||
json_data = json.dumps(data, ensure_ascii=False, indent=4)
|
||||
log_file_path = os.path.join(
|
||||
nested_folder_path, f"{self.log_count_within_cycle}_{file_name}"
|
||||
)
|
||||
|
||||
logger.log_json(json_data, log_file_path)
|
||||
self.log_count_within_cycle += 1
|
|
@ -5,9 +5,11 @@ import random
|
|||
import re
|
||||
import time
|
||||
from logging import LogRecord
|
||||
from typing import Any
|
||||
|
||||
from colorama import Fore, Style
|
||||
|
||||
from autogpt.log_cycle.json_handler import JsonFileHandler, JsonFormatter
|
||||
from autogpt.singleton import Singleton
|
||||
from autogpt.speech import say_text
|
||||
|
||||
|
@ -74,6 +76,11 @@ class Logger(metaclass=Singleton):
|
|||
self.logger.addHandler(error_handler)
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
self.json_logger = logging.getLogger("JSON_LOGGER")
|
||||
self.json_logger.addHandler(self.file_handler)
|
||||
self.json_logger.addHandler(error_handler)
|
||||
self.json_logger.setLevel(logging.DEBUG)
|
||||
|
||||
self.speak_mode = False
|
||||
self.chat_plugins = []
|
||||
|
||||
|
@ -152,6 +159,26 @@ class Logger(metaclass=Singleton):
|
|||
|
||||
self.typewriter_log("DOUBLE CHECK CONFIGURATION", Fore.YELLOW, additionalText)
|
||||
|
||||
def log_json(self, data: Any, file_name: str) -> None:
|
||||
# Define log directory
|
||||
this_files_dir_path = os.path.dirname(__file__)
|
||||
log_dir = os.path.join(this_files_dir_path, "../logs")
|
||||
|
||||
# Create a handler for JSON files
|
||||
json_file_path = os.path.join(log_dir, file_name)
|
||||
json_data_handler = JsonFileHandler(json_file_path)
|
||||
json_data_handler.setFormatter(JsonFormatter())
|
||||
|
||||
# Log the JSON data using the custom file handler
|
||||
self.json_logger.addHandler(json_data_handler)
|
||||
self.json_logger.debug(data)
|
||||
self.json_logger.removeHandler(json_data_handler)
|
||||
|
||||
def get_log_directory(self):
|
||||
this_files_dir_path = os.path.dirname(__file__)
|
||||
log_dir = os.path.join(this_files_dir_path, "../logs")
|
||||
return os.path.abspath(log_dir)
|
||||
|
||||
|
||||
"""
|
||||
Output stream to console using simulated typing
|
||||
|
@ -199,12 +226,16 @@ class AutoGptFormatter(logging.Formatter):
|
|||
if hasattr(record, "color"):
|
||||
record.title_color = (
|
||||
getattr(record, "color")
|
||||
+ getattr(record, "title")
|
||||
+ getattr(record, "title", "")
|
||||
+ " "
|
||||
+ Style.RESET_ALL
|
||||
)
|
||||
else:
|
||||
record.title_color = getattr(record, "title")
|
||||
record.title_color = getattr(record, "title", "")
|
||||
|
||||
# Add this line to set 'title' to an empty string if it doesn't exist
|
||||
record.title = getattr(record, "title", "")
|
||||
|
||||
if hasattr(record, "msg"):
|
||||
record.message_no_color = remove_color_codes(getattr(record, "msg"))
|
||||
else:
|
||||
|
|
Loading…
Reference in New Issue