Cpptai / src /cpptai /responsible_ai.py
Fra150
CPPTAI v2 + Gradio demo offline (rispetta .gitignore)
c0e3412
Raw History Blame Contribute Delete
3.11 kB
"""Responsible AI auditor — bias detection and fairness checks.
Extracted from core.py into its own module for clarity and testability.
"""
from __future__ import annotations
import re
from typing import Any, Dict, List
class ResponsibleAIAuditor:
"""Audits generated outputs for protected-attribute bias and negative framing.
Maintains a vocabulary of protected terms (demographic attributes) and
negative-context keywords. Scans text for co-occurrence patterns and
returns a structured risk assessment.
"""
def __init__(self):
self.protected_terms = [
"woman", "women", "man", "men", "male", "female",
"girl", "boy", "black", "white", "asian", "latino",
"hispanic", "arab", "jewish", "muslim", "christian",
"gay", "lesbian", "bisexual", "trans", "transgender",
"disabled", "autistic", "elderly", "old", "young",
"immigrant",
]
self.negative_terms = {
"inferior", "superior", "lazy", "stupid", "criminal",
"dangerous", "dirty", "illegal", "terrorist", "untrustworthy",
}
def audit_bias_detection(self, text: str) -> Dict[str, Any]:
"""Analyse *text* for protected-attribute mentions near negative terms.
Returns a verdict dict with keys:
verdict — "pass" | "review"
risk_score — float in [0, 1]
protected_attribute_mentions — sorted list of matched terms
negative_context_hits — list of {term, negative_terms, context}
flags — human-readable notes
"""
lowered = text.lower()
mentions: List[str] = []
negative_hits: List[Dict[str, Any]] = []
words = re.findall(r"[a-zA-Z']+", lowered)
for idx, w in enumerate(words):
if w not in self.protected_terms:
continue
mentions.append(w)
start = max(0, idx - 6)
end = min(len(words), idx + 7)
window = words[start:end]
hit_terms = sorted(set(t for t in window if t in self.negative_terms))
if hit_terms:
negative_hits.append({
"term": w,
"negative_terms": hit_terms,
"context": " ".join(window),
})
unique_mentions = sorted(set(mentions))
unique_negative = len(negative_hits)
risk = 0.0
if unique_mentions:
risk = 0.3
if unique_negative:
risk = min(1.0, risk + 0.2 * unique_negative)
verdict = "pass"
flags: List[str] = []
if unique_negative:
verdict = "review"
flags.append("negative_context_near_protected_attribute")
if not unique_mentions:
flags.append("no_protected_attribute_mentions_detected")
return {
"verdict": verdict,
"risk_score": round(risk, 3),
"protected_attribute_mentions": unique_mentions,
"negative_context_hits": negative_hits,
"flags": flags,
}