| """This module contains functions to fix JSON strings using general programmatic approaches, suitable for addressing | |
| common JSON formatting issues.""" | |
| from __future__ import annotations | |
| import contextlib | |
| import json | |
| import re | |
| from typing import Optional | |
| from autogpt.config import Config | |
| from autogpt.json_utils.utilities import extract_char_position | |
| CFG = Config() | |
| def fix_invalid_escape(json_to_load: str, error_message: str) -> str: | |
| """Fix invalid escape sequences in JSON strings. | |
| Args: | |
| json_to_load (str): The JSON string. | |
| error_message (str): The error message from the JSONDecodeError | |
| exception. | |
| Returns: | |
| str: The JSON string with invalid escape sequences fixed. | |
| """ | |
| while error_message.startswith("Invalid \\escape"): | |
| bad_escape_location = extract_char_position(error_message) | |
| json_to_load = ( | |
| json_to_load[:bad_escape_location] + json_to_load[bad_escape_location + 1 :] | |
| ) | |
| try: | |
| json.loads(json_to_load) | |
| return json_to_load | |
| except json.JSONDecodeError as e: | |
| if CFG.debug_mode: | |
| print("json loads error - fix invalid escape", e) | |
| error_message = str(e) | |
| return json_to_load | |
| def balance_braces(json_string: str) -> Optional[str]: | |
| """ | |
| Balance the braces in a JSON string. | |
| Args: | |
| json_string (str): The JSON string. | |
| Returns: | |
| str: The JSON string with braces balanced. | |
| """ | |
| open_braces_count = json_string.count("{") | |
| close_braces_count = json_string.count("}") | |
| while open_braces_count > close_braces_count: | |
| json_string += "}" | |
| close_braces_count += 1 | |
| while close_braces_count > open_braces_count: | |
| json_string = json_string.rstrip("}") | |
| close_braces_count -= 1 | |
| with contextlib.suppress(json.JSONDecodeError): | |
| json.loads(json_string) | |
| return json_string | |
| def add_quotes_to_property_names(json_string: str) -> str: | |
| """ | |
| Add quotes to property names in a JSON string. | |
| Args: | |
| json_string (str): The JSON string. | |
| Returns: | |
| str: The JSON string with quotes added to property names. | |
| """ | |
| def replace_func(match: re.Match) -> str: | |
| return f'"{match[1]}":' | |
| property_name_pattern = re.compile(r"(\w+):") | |
| corrected_json_string = property_name_pattern.sub(replace_func, json_string) | |
| try: | |
| json.loads(corrected_json_string) | |
| return corrected_json_string | |
| except json.JSONDecodeError as e: | |
| raise e | |
| def correct_json(json_to_load: str) -> str: | |
| """ | |
| Correct common JSON errors. | |
| Args: | |
| json_to_load (str): The JSON string. | |
| """ | |
| try: | |
| if CFG.debug_mode: | |
| print("json", json_to_load) | |
| json.loads(json_to_load) | |
| return json_to_load | |
| except json.JSONDecodeError as e: | |
| if CFG.debug_mode: | |
| print("json loads error", e) | |
| error_message = str(e) | |
| if error_message.startswith("Invalid \\escape"): | |
| json_to_load = fix_invalid_escape(json_to_load, error_message) | |
| if error_message.startswith( | |
| "Expecting property name enclosed in double quotes" | |
| ): | |
| json_to_load = add_quotes_to_property_names(json_to_load) | |
| try: | |
| json.loads(json_to_load) | |
| return json_to_load | |
| except json.JSONDecodeError as e: | |
| if CFG.debug_mode: | |
| print("json loads error - add quotes", e) | |
| error_message = str(e) | |
| if balanced_str := balance_braces(json_to_load): | |
| return balanced_str | |
| return json_to_load | |