athena / backend /app /utils /json_utils.py
JermaineAI's picture
Improve chart engine, insight engine, LLM client, question planner and JSON utils
2e4290e
Raw
History Blame Contribute Delete
1.55 kB
import json
import re
from typing import Any, TypeVar
from pydantic import BaseModel, ValidationError
T = TypeVar("T", bound=BaseModel)
def safe_json_loads(text: str) -> dict[str, Any]:
stripped = text.strip()
# Try direct parse first
try:
payload = json.loads(stripped)
if isinstance(payload, dict):
return payload
except json.JSONDecodeError:
pass
# Try extracting from markdown fences ```json ... ``` or ``` ... ```
fence_match = re.search(r"```(?:json)?\s*\n?(.*?)\n?```", stripped, re.DOTALL)
if fence_match:
try:
payload = json.loads(fence_match.group(1).strip())
if isinstance(payload, dict):
return payload
except json.JSONDecodeError:
pass
# Try finding the first { ... } block
brace_start = stripped.find("{")
if brace_start != -1:
brace_end = stripped.rfind("}")
if brace_end > brace_start:
try:
payload = json.loads(stripped[brace_start : brace_end + 1])
if isinstance(payload, dict):
return payload
except json.JSONDecodeError:
pass
raise ValueError("Response is not valid JSON — tried direct parse, markdown fences, and brace extraction.")
def validate_json_plan(payload: dict[str, Any], model: type[T]) -> T:
try:
return model.model_validate(payload)
except ValidationError as exc:
raise ValueError("Invalid JSON analysis plan.") from exc