ClaimsGPT / utils /explainability.py
Bader Alabddan
Add all production modules (schemas, logic, utils, tests)
21f1a73
"""Explainability utilities for decision transparency."""
from typing import Dict, Any, List
class DecisionExplainer:
"""Generate human-readable explanations for decisions."""
@staticmethod
def explain_decision(decision: str, factors: Dict[str, Any]) -> str:
"""Generate explanation for claim decision."""
if decision == "APPROVED":
return DecisionExplainer._explain_approval(factors)
elif decision == "REJECTED":
return DecisionExplainer._explain_rejection(factors)
elif decision == "REVIEW":
return DecisionExplainer._explain_review(factors)
else:
return "Decision could not be explained."
@staticmethod
def _explain_approval(factors: Dict[str, Any]) -> str:
"""Explain approval decision."""
parts = ["Claim APPROVED based on:"]
if factors.get("severity_score", 0) < 0.5:
parts.append("- Low severity score indicates routine claim")
if not factors.get("fraud_risk", False):
parts.append("- No fraud indicators detected")
if factors.get("coverage_valid", True):
parts.append("- Coverage rules satisfied")
if factors.get("amount_within_limits", True):
parts.append("- Claim amount within policy limits")
return "\n".join(parts)
@staticmethod
def _explain_rejection(factors: Dict[str, Any]) -> str:
"""Explain rejection decision."""
parts = ["Claim REJECTED due to:"]
if factors.get("fraud_risk", False):
signals = factors.get("fraud_signals", [])
parts.append(f"- Fraud risk detected: {', '.join(signals)}")
if not factors.get("coverage_valid", True):
parts.append("- Coverage requirements not met")
if not factors.get("amount_within_limits", True):
parts.append("- Claim amount exceeds policy limits")
if factors.get("policy_expired", False):
parts.append("- Policy expired at time of incident")
return "\n".join(parts)
@staticmethod
def _explain_review(factors: Dict[str, Any]) -> str:
"""Explain manual review requirement."""
parts = ["Claim requires MANUAL REVIEW because:"]
if factors.get("severity_score", 0) > 0.7:
parts.append("- High severity score requires expert assessment")
if factors.get("ambiguous_coverage", False):
parts.append("- Coverage determination is ambiguous")
if factors.get("high_amount", False):
parts.append("- Claim amount requires senior approval")
if factors.get("missing_documentation", False):
parts.append("- Additional documentation required")
if factors.get("edge_case", False):
parts.append("- Unusual circumstances detected")
return "\n".join(parts)
@staticmethod
def format_fraud_signals(signals: List[str]) -> str:
"""Format fraud signals for display."""
if not signals:
return "No fraud indicators detected."
return "Fraud indicators:\n" + "\n".join(f"- {signal}" for signal in signals)