42 lines
1.3 KiB
Python
42 lines
1.3 KiB
Python
"""Validate JSON without inventing facts or repairing values from benchmark gold."""
|
|
import json
|
|
import re
|
|
from typing import Literal
|
|
from pydantic import BaseModel, ConfigDict
|
|
|
|
|
|
class Claim(BaseModel):
|
|
model_config = ConfigDict(extra='forbid', strict=True)
|
|
person: str
|
|
title: str | None = None
|
|
year: int | None = None
|
|
start_year: int | None = None
|
|
keyword: str | None = None
|
|
category: str | None = None
|
|
document_author: str | None = None
|
|
|
|
|
|
class Answer(BaseModel):
|
|
model_config = ConfigDict(extra='forbid', strict=True)
|
|
answer: str
|
|
status: Literal['ok','no_answer','ambiguous','error']
|
|
claims: list[Claim]
|
|
source_urls: list[str]
|
|
count: int | None = None
|
|
|
|
|
|
def parse_answer(text: str) -> tuple[dict, bool]:
|
|
try:
|
|
data=json.loads(text.strip())
|
|
normalized=False
|
|
except json.JSONDecodeError:
|
|
# Exactly one complete JSON fence can be unwrapped. Never replace quotes,
|
|
# append missing braces, extract fragments or silently alter assertions.
|
|
blocks=re.findall(r'```(?:json)?\s*\n([\s\S]*?)```',text,flags=re.IGNORECASE)
|
|
if len(blocks)!=1:
|
|
raise
|
|
data=json.loads(blocks[0].strip())
|
|
normalized=True
|
|
parsed=Answer.model_validate(data)
|
|
return parsed.model_dump(exclude_none=True),normalized
|