Spaces:
Configuration error
Configuration error
File size: 2,446 Bytes
6733714 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | import re
from typing import List, Dict, Any
class CitationValidator:
"""
Performs post-synthesis validation of legal citations.
Ensures that every Section/Rule cited by the LLM exists in the retrieved context.
"""
@staticmethod
def validate_citations(answer: str, retrieved_chunks: List[Dict[str, Any]]) -> str:
"""
Scans the answer for citations and compares them against the chunks.
Appends a verification report to the answer.
"""
# Find all mentions of "Section X" or "Sec X" or "Rule X"
citation_pattern = r"(Section|Sec|Rule)\s*(\d+[A-Z]?(\(\d+\))?)"
found_in_answer = re.findall(citation_pattern, answer, re.IGNORECASE)
# Unique normalized citations from answer
citations_to_verify = set()
for type_pref, num, _ in found_in_answer:
citations_to_verify.add(f"{type_pref.capitalize()} {num}")
# Extract all available provisions from retrieved chunks
available_provisions = set()
for chunk in retrieved_chunks:
prov = chunk.get("provision", "")
if prov:
available_provisions.add(prov.strip())
# Search the FULL chunk text for section/rule markers
chunk_text = chunk.get("text", "")
for text_match in re.finditer(citation_pattern, chunk_text, re.IGNORECASE):
available_provisions.add(f"{text_match.group(1).capitalize()} {text_match.group(2)}")
# Cross-reference
verified = []
hallucinated = []
for cit in citations_to_verify:
# Loose matching: if "Section 17" is checked, "Section 17(5)" in available is a match
matches = [avail for avail in available_provisions if cit.lower() in avail.lower() or avail.lower() in cit.lower()]
if matches:
verified.append(cit)
else:
hallucinated.append(cit)
# Log internally — never append to user-facing output
import logging
_cv_logger = logging.getLogger("citation_validator")
if hallucinated:
_cv_logger.warning(
f"Unverified citations: {hallucinated} | Verified: {verified}"
)
else:
_cv_logger.debug(f"All citations verified: {verified}")
# Return the answer unchanged — no report appended to user output
return answer
|