MossaicMan's picture
Upload 33 files
345000b verified
import json
import re
from typing import List
from pydantic import BaseModel
# =========================
# Pydantic Model
# =========================
class BiasReport(BaseModel):
detected_biases: List[str]
risk_level: str
explanations: List[str]
mitigation_suggestions: List[str]
# =========================
# JSON Normalizer
# =========================
def normalize_llm_json(raw: str) -> dict:
"""
Extracts and parses a JSON object from noisy LLM output.
Handles markdown fences, 'json' prefixes, and extra text.
"""
if raw is None:
raise ValueError("LLM returned None")
raw = raw.strip()
if not raw:
raise ValueError("LLM returned empty output")
# Remove ```json fences
if raw.startswith("```"):
parts = raw.split("```")
if len(parts) >= 2:
raw = parts[1].strip()
# Remove leading 'json'
if raw.lower().startswith("json"):
raw = raw[4:].strip()
# Extract JSON object
match = re.search(r"\{.*\}", raw, re.DOTALL)
if not match:
raise ValueError(f"No JSON object found in LLM output:\n{raw}")
json_text = match.group()
return json.loads(json_text)
# =========================
# Bias Output Parser
# =========================
def parse_bias_output(raw: str) -> BiasReport:
"""
Normalizes and parses LLM bias analysis output into BiasReport.
Safely handles dict/list variations from the LLM.
"""
data = normalize_llm_json(raw)
# ---------- findings_explanation ----------
findings = data.get("findings_explanation", [])
if isinstance(findings, dict):
detected_biases = list(findings.keys())
explanations = list(findings.values())
elif isinstance(findings, list):
detected_biases = []
explanations = findings
else:
detected_biases = []
explanations = []
# ---------- mitigation_steps ----------
mitigation = data.get("mitigation_steps", [])
if isinstance(mitigation, dict):
mitigation_suggestions = list(mitigation.values())
elif isinstance(mitigation, list):
mitigation_suggestions = mitigation
else:
mitigation_suggestions = []
# ---------- risk level ----------
risk_level = data.get("overall_risk_level", "unknown")
return BiasReport(
detected_biases=detected_biases,
risk_level=risk_level,
explanations=explanations,
mitigation_suggestions=mitigation_suggestions,
)