From 132c1cf0abb28dc12e73ea71e8ec0b89e21b97d1 Mon Sep 17 00:00:00 2001 From: Aron Weiler Date: Sun, 10 Dec 2023 00:41:50 -0800 Subject: [PATCH 1/3] Refactor code and add documentation --- src/utilities/configuration_utilities.py | 27 +++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/utilities/configuration_utilities.py b/src/utilities/configuration_utilities.py index e6c725e5..0cd058af 100644 --- a/src/utilities/configuration_utilities.py +++ b/src/utilities/configuration_utilities.py @@ -3,13 +3,29 @@ def get_tool_configuration(configuration: dict, func_name: str) -> dict: + """ + Retrieve the tool-specific configuration. + + Parameters: + configuration (dict): The main configuration dictionary containing all tool configurations. + func_name (str): The name of the function for which to retrieve the configuration. + + Returns: + dict: The configuration dictionary for the specified function or the default configuration if not found. + """ if func_name in configuration["tool_configurations"]: return configuration["tool_configurations"][func_name] return configuration["tool_configurations"]["default"] -def get_app_config_path(): +def get_app_config_path() -> str: + """ + Get the file system path to the application configuration file. + + Returns: + str: The path to the application configuration file, either from the environment variable or the default path. + """ app_config_path = os.environ.get( "APP_CONFIG_PATH", "configurations/app_configs/config.json", @@ -18,8 +34,13 @@ def get_app_config_path(): return app_config_path -def get_app_configuration(): - """Loads the configuration from the path""" +def get_app_configuration() -> dict: + """ + Load the application configuration from the configuration file. + + Returns: + dict: The application configuration loaded from the file. + """ app_config_path = get_app_config_path() return ApplicationConfigurationLoader.from_file(app_config_path) From 0bbfeac7fc5bc81d07b08fad169c835fb7892c9e Mon Sep 17 00:00:00 2001 From: Aron Weiler Date: Sun, 10 Dec 2023 00:49:04 -0800 Subject: [PATCH 2/3] Refactor code and add documentation --- src/ai/system_info.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/ai/system_info.py b/src/ai/system_info.py index 40d704b5..4d128469 100644 --- a/src/ai/system_info.py +++ b/src/ai/system_info.py @@ -2,9 +2,23 @@ from tzlocal import get_localzone -def get_system_information(location: str): - +def get_system_information(location: str) -> str: + """ + Get the system information including the current date/time, time zone, and location. -# Get the local time zone in IANA format + :param location: The location of the user as a string. + :return: A formatted string containing the date/time, time zone, and location. + """ + # Get the local time zone in IANA format local_timezone = get_localzone() - return f"User's Current Date/Time: {datetime.now().strftime('%m/%d/%Y %H:%M:%S')}.\nUser's Current Time Zone: {local_timezone}.\nUser's Current Location: {location}" + current_datetime = datetime.now().strftime('%m/%d/%Y %H:%M:%S') + + # Format the system information string + system_info = ( + f"User's Current Date/Time: {current_datetime}. +" + f"User's Current Time Zone: {local_timezone}. +" + f"User's Current Location: {location}" + ) + return system_info From fecff646ea44ae0a98a07e6f283d16b323ebb639 Mon Sep 17 00:00:00 2001 From: Aron Weiler Date: Sun, 10 Dec 2023 01:09:11 -0800 Subject: [PATCH 3/3] Refactor code and commit to auto-refactoring branch --- src/utilities/parsing_utilities.py | 100 ++++++++++++++--------------- 1 file changed, 48 insertions(+), 52 deletions(-) diff --git a/src/utilities/parsing_utilities.py b/src/utilities/parsing_utilities.py index b187fa08..643a97f9 100644 --- a/src/utilities/parsing_utilities.py +++ b/src/utilities/parsing_utilities.py @@ -3,70 +3,66 @@ import os import logging -from langchain.schema.language_model import BaseLanguageModel from src.utilities.json_repair import JsonRepair -logging.basicConfig(level=os.getenv("LOGGING_LEVEL", "INFO")) +# Configure logging +logging.basicConfig(level=logging.getLevelName(os.getenv('LOGGING_LEVEL', 'INFO'))) logger = logging.getLogger(__name__) -def parse_json(text: str, llm: BaseLanguageModel) -> dict: - - # So.... - text = text.strip() - - # Hey look, another random thing to handle - text = text.replace("``` json", "```json") - # Handle JSON code blocks (whole response) - if text.startswith("```json") and text.endswith("```"): - text = text[7:-3] +# Constants +JSON_CODE_BLOCK_START = '```json' +JSON_CODE_BLOCK_END = '```' + + +def extract_json_block(text): + """ + Extract JSON from code blocks. - # Fucking... - text = text.strip() + :param text: String containing the text with potential JSON code blocks. + :return: The extracted JSON string if found, otherwise None. + """ + pattern = re.compile(r'```(?:json)?\n(.*?)```', re.DOTALL) + try: + match = pattern.search(text) + return match.group(1).strip() if match else None + except re.error as e: + logger.error(f'Regex error occurred: {e}') + return None - # Sometimes there are two lines of ``` code block nonsense - if text.startswith("```"): - text = text[3:] - if text.endswith("```"): - text = text[:-3] +def parse_json(text: str) -> dict: + """ + Parse a JSON string, repairing it if necessary. - # Annoying... + :param text: String containing the JSON to parse. + :return: A dictionary representation of the JSON. + """ text = text.strip() - # Handle JSON code blocks (inside other text within a response) - pattern = re.compile(r"```(?:json)?\n(.*?)```", re.DOTALL) + # Check if the entire text is a JSON code block + if text.startswith(JSON_CODE_BLOCK_START) and text.endswith(JSON_CODE_BLOCK_END): + text = text[len(JSON_CODE_BLOCK_START):-len(JSON_CODE_BLOCK_END)].strip() + + # Extract JSON from within the text + json_block = extract_json_block(text) + if json_block is not None: + text = json_block + # Attempt to parse the JSON try: - action_match = pattern.search(text) - if action_match is not None: - logger.info("Handling JSON found inside of a code block...") - # Handles the json inside of the code block - text = action_match.group(1).strip() - response = json.loads(text, strict=False) - return response - elif (text.strip().startswith("{") and text.strip().endswith("}")) or (text.strip().startswith("[") and text.strip().endswith("]")): - logger.info("Handling JSON that is not inside of a code block...") - # Handles JSON responses that are not in code blocks - return json.loads(text.strip(), strict=False) - else: - # Just return this as the answer?? - logger.warning("Gave up on handling JSON, returning text as final_answer...") - return {"final_answer": text} - except Exception as e: + return json.loads(text, strict=False) + except json.JSONDecodeError as e: + logger.warning('Failed to parse JSON, trying to repair it...') try: - logger.warning("Failed to parse JSON, trying to repair it...") # Try to repair the JSON - text = JsonRepair(text).repair() - return parse_json(text, None) - except Exception as e: - # Last-ditch effort, try to use the LLM to fix the JSON - logger.warning("Failed to repair JSON, trying to use LLM to fix it...") - if llm: - llm_fixed_json = llm.predict( - f"The following is badly formatted JSON, please fix it (only fix the JSON, do not otherwise modify the content):\n{text}\n\nAI: Sure, here is the fixed JSON (without modifying the content):\n" - ) - return parse_json(llm_fixed_json, None) - else: - logger.error("Failed to parse JSON, and no LLM was provided to try to fix it.") - raise Exception(f"Could not parse LLM output: {text}") from e + repaired_text = JsonRepair(text).repair() + return json.loads(repaired_text, strict=False) + except json.JSONDecodeError as e: + error_msg = f'Failed to repair JSON. Original text: {text}, Error: {e}' + logger.error(error_msg) + raise ValueError(error_msg) from e + + # Fallback if the text is not JSON + logger.warning('Gave up on handling JSON, returning text as final_answer...') + return {'final_answer': text}