UDHOV's picture
Sync from GitHub via hub-sync
bef3cc6 verified
Raw
History Blame Contribute Delete
1.94 kB
"""
Safe JSON Parser
Provides robust JSON parsing with fallback handling for malformed LLM responses.
"""
import json
import logging
import re
from typing import Any, cast
logger = logging.getLogger(__name__)
def safe_json_parse(
raw_response: str,
default: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""
Parse JSON from LLM response with multiple fallback strategies.
Args:
raw_response: Raw string response from LLM
default: Default dict to return if all parsing attempts fail
Returns:
Parsed JSON as dict, or default value
"""
if default is None:
default = {}
if not raw_response or not raw_response.strip():
logger.warning("Empty response received for JSON parsing")
return default
# Strategy 1: Direct parse
try:
parsed = json.loads(raw_response)
return cast(dict[str, Any], parsed)
except json.JSONDecodeError:
logger.debug("Direct JSON parse failed, trying cleanup strategies")
# Strategy 2: Extract JSON object from response
# Look for {...} pattern in the response
json_pattern = r"\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}"
match = re.search(json_pattern, raw_response, re.DOTALL)
if match:
try:
parsed = json.loads(match.group(0))
return cast(dict[str, Any], parsed)
except json.JSONDecodeError:
logger.debug("Regex extraction failed")
# Strategy 3: Try to fix common JSON issues
# Remove trailing commas, fix single quotes
cleaned = raw_response
cleaned = re.sub(r",\s*}", "}", cleaned)
cleaned = re.sub(r",\s*]", "]", cleaned)
cleaned = re.sub(r"'([^']*)'", r'"\1"', cleaned)
try:
parsed = json.loads(cleaned)
return cast(dict[str, Any], parsed)
except json.JSONDecodeError:
logger.warning("All JSON parsing strategies failed, returning default")
return default