File size: 4,327 Bytes
676c241
31b076e
676c241
 
 
6489332
676c241
 
 
 
 
 
 
6489332
 
 
676c241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6489332
676c241
6489332
 
676c241
6489332
676c241
6489332
676c241
 
 
 
 
 
 
 
6489332
676c241
 
 
 
 
 
 
 
 
 
6489332
676c241
 
 
 
 
 
 
 
 
 
6489332
676c241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1f7a6b
676c241
 
 
 
 
 
 
 
6489332
676c241
 
6489332
676c241
6489332
 
 
 
 
 
 
 
 
 
 
676c241
6489332
 
676c241
a1f7a6b
6489332
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# app.py
import os
import math
import requests
from langdetect import detect
import gradio as gr

# -----------------------------------------------------------------------------
# Configuration
# -----------------------------------------------------------------------------
HF_API_URL = "https://api-inference.huggingface.co/models/YOUR_USERNAME/YOUR_MODEL"
HF_TOKEN = os.getenv("HF_TOKEN")

if HF_TOKEN is None:
    raise ValueError("HF_TOKEN environment variable not set!")

HEADERS = {
    "Authorization": f"Bearer {HF_TOKEN}",
    "Content-Type": "application/json"
}

# -----------------------------------------------------------------------------
# Utility Functions
# -----------------------------------------------------------------------------
def entropy(probs):
    """Shannon entropy as epistemic uncertainty indicator."""
    return -sum(p * math.log2(p) for p in probs if p > 0)

def normalize_labels(hf_output):
    """
    Normalize Hugging Face output into a stable schema.
    Expected HF format:
    [
      {"label": "HUMAN", "score": 0.73},
      {"label": "AI", "score": 0.27}
    ]
    """
    result = {item["label"].lower(): float(item["score"]) for item in hf_output}
    human_p = result.get("human", 0.0)
    ai_p = result.get("ai", 0.0)
    return human_p, ai_p

def hf_inference(text):
    payload = {"inputs": text}
    r = requests.post(HF_API_URL, headers=HEADERS, json=payload, timeout=30)
    r.raise_for_status()
    return r.json()

# -----------------------------------------------------------------------------
# Gradio Prediction Function
# -----------------------------------------------------------------------------
def analyze_text(text):
    text = text.strip()
    if not text:
        return {"error": "Empty input"}

    # 1. Language detection
    try:
        language = detect(text)
    except Exception:
        language = "unknown"

    # 2. Hugging Face inference
    hf_raw = hf_inference(text)
    if not isinstance(hf_raw, list):
        return {"error": "Unexpected model response", "raw": hf_raw}

    human_p, ai_p = normalize_labels(hf_raw)

    # 3. Decision
    label = "Human" if human_p >= ai_p else "Machine"
    confidence = max(human_p, ai_p)

    # 4. Epistemic uncertainty
    H = entropy([human_p, ai_p])

    # 5. Explainability placeholder
    explainability_stub = {
        "method": "pending",
        "note": (
            "This model endpoint does not natively expose SHAP/LIME. "
            "Post-hoc explainability must be computed locally using a "
            "replicated model or proxy explainer."
        ),
        "token_attributions": []
    }

    # 6. Fairness metadata
    fairness_context = {
        "language": language,
        "human_probability": human_p,
        "ai_probability": ai_p,
        "entropy": H
    }

    response = {
        "prediction": {
            "label": label,
            "confidence": round(confidence, 4)
        },
        "probabilities": {
            "human": round(human_p, 4),
            "machine": round(ai_p, 4)
        },
        "uncertainty": {
            "entropy": round(H, 4),
            "interpretation": (
                "High entropy indicates epistemic ambiguity; "
                "classification should be treated cautiously."
            )
        },
        "linguistic_context": {
            "detected_language": language
        },
        "explainability": explainability_stub,
        "fairness_audit_fields": fairness_context
    }

    return response

# -----------------------------------------------------------------------------
# Gradio Interface
# -----------------------------------------------------------------------------
iface = gr.Interface(
    fn=analyze_text,
    inputs=gr.Textbox(lines=5, placeholder="Enter text here..."),
    outputs=gr.JSON(),
    title="HATA: Human-AI Text Attribution",
    description=(
        "Detect whether text is human-written or AI-generated.\n"
        "Supports uncertainty estimation, language-aware auditing, "
        "and XAI-ready outputs."
    )
)

# -----------------------------------------------------------------------------
# Launch Gradio App
# -----------------------------------------------------------------------------
if __name__ == "__main__":
    iface.launch(server_name="0.0.0.0", server_port=7860)