mirror of
https://github.com/aljazceru/Auto-GPT.git
synced 2025-12-17 22:14:28 +01:00
By not having correct_json(json_str) in the try/except, it was still easily possible to throw Invalid JSON errors. When responses were received with no JSON at all, parsing would fail on attempting to locate the braces.
111 lines
4.0 KiB
Python
111 lines
4.0 KiB
Python
import json
|
|
from typing import Any, Dict, Union
|
|
from call_ai_function import call_ai_function
|
|
from config import Config
|
|
from json_utils import correct_json
|
|
|
|
cfg = Config()
|
|
|
|
JSON_SCHEMA = """
|
|
{
|
|
"command": {
|
|
"name": "command name",
|
|
"args":{
|
|
"arg name": "value"
|
|
}
|
|
},
|
|
"thoughts":
|
|
{
|
|
"text": "thought",
|
|
"reasoning": "reasoning",
|
|
"plan": "- short bulleted\n- list that conveys\n- long-term plan",
|
|
"criticism": "constructive self-criticism",
|
|
"speak": "thoughts summary to say to user"
|
|
}
|
|
}
|
|
"""
|
|
|
|
|
|
def fix_and_parse_json(
|
|
json_str: str,
|
|
try_to_fix_with_gpt: bool = True
|
|
) -> Union[str, Dict[Any, Any]]:
|
|
"""Fix and parse JSON string"""
|
|
try:
|
|
json_str = json_str.replace('\t', '')
|
|
return json.loads(json_str)
|
|
except json.JSONDecodeError as _: # noqa: F841
|
|
try:
|
|
json_str = correct_json(json_str)
|
|
return json.loads(json_str)
|
|
except json.JSONDecodeError as _: # noqa: F841
|
|
pass
|
|
# Let's do something manually:
|
|
# sometimes GPT responds with something BEFORE the braces:
|
|
# "I'm sorry, I don't understand. Please try again."
|
|
# {"text": "I'm sorry, I don't understand. Please try again.",
|
|
# "confidence": 0.0}
|
|
# So let's try to find the first brace and then parse the rest
|
|
# of the string
|
|
try:
|
|
brace_index = json_str.index("{")
|
|
json_str = json_str[brace_index:]
|
|
last_brace_index = json_str.rindex("}")
|
|
json_str = json_str[:last_brace_index+1]
|
|
return json.loads(json_str)
|
|
# Can throw a ValueError if there is no "{" or "}" in the json_str
|
|
except (json.JSONDecodeError, ValueError) as e: # noqa: F841
|
|
if try_to_fix_with_gpt:
|
|
print("Warning: Failed to parse AI output, attempting to fix."
|
|
"\n If you see this warning frequently, it's likely that"
|
|
" your prompt is confusing the AI. Try changing it up"
|
|
" slightly.")
|
|
# Now try to fix this up using the ai_functions
|
|
ai_fixed_json = fix_json(json_str, JSON_SCHEMA)
|
|
|
|
if ai_fixed_json != "failed":
|
|
return json.loads(ai_fixed_json)
|
|
else:
|
|
# This allows the AI to react to the error message,
|
|
# which usually results in it correcting its ways.
|
|
print("Failed to fix AI output, telling the AI.")
|
|
return json_str
|
|
else:
|
|
raise e
|
|
|
|
|
|
def fix_json(json_str: str, schema: str) -> str:
|
|
"""Fix the given JSON string to make it parseable and fully compliant with the provided schema."""
|
|
|
|
# Try to fix the JSON using GPT:
|
|
function_string = "def fix_json(json_str: str, schema:str=None) -> str:"
|
|
args = [f"'''{json_str}'''", f"'''{schema}'''"]
|
|
description_string = "Fixes the provided JSON string to make it parseable"\
|
|
" and fully compliant with the provided schema.\n If an object or"\
|
|
" field specified in the schema isn't contained within the correct"\
|
|
" JSON, it is omitted.\n This function is brilliant at guessing"\
|
|
" when the format is incorrect."
|
|
|
|
# If it doesn't already start with a "`", add one:
|
|
if not json_str.startswith("`"):
|
|
json_str = "```json\n" + json_str + "\n```"
|
|
result_string = call_ai_function(
|
|
function_string, args, description_string, model=cfg.fast_llm_model
|
|
)
|
|
if cfg.debug_mode:
|
|
print("------------ JSON FIX ATTEMPT ---------------")
|
|
print(f"Original JSON: {json_str}")
|
|
print("-----------")
|
|
print(f"Fixed JSON: {result_string}")
|
|
print("----------- END OF FIX ATTEMPT ----------------")
|
|
|
|
try:
|
|
json.loads(result_string) # just check the validity
|
|
return result_string
|
|
except: # noqa: E722
|
|
# Get the call stack:
|
|
# import traceback
|
|
# call_stack = traceback.format_exc()
|
|
# print(f"Failed to fix JSON: '{json_str}' "+call_stack)
|
|
return "failed"
|