Spaces:
Build error
Build error
| 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, | |
| ) | |