File size: 4,404 Bytes
676c241
31b076e
676c241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1f7a6b
676c241
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a1f7a6b
676c241
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
142
143
144
145
146
147
# app.py
import os
import math
import requests
from flask import Flask, request, jsonify
from flask_cors import CORS
from langdetect import detect

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

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

app = Flask(__name__)
CORS(app)

# -----------------------------------------------------------------------------
# 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()

# -----------------------------------------------------------------------------
# Core Endpoint
# -----------------------------------------------------------------------------
@app.route("/analyze", methods=["POST"])
def analyze():
    data = request.get_json()
    text = data.get("text", "").strip()

    if not text:
        return jsonify({"error": "Empty input"}), 400

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

    # 2. Hugging Face inference
    hf_raw = hf_inference(text)

    if not isinstance(hf_raw, list):
        return jsonify({"error": "Unexpected model response", "raw": hf_raw}), 500

    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 (XAI-ready schema)
    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 (for downstream auditing)
    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 jsonify(response)

# -----------------------------------------------------------------------------
# Health Check
# -----------------------------------------------------------------------------
@app.route("/", methods=["GET"])
def index():
    return jsonify({
        "system": "HATA API",
        "capabilities": [
            "Human vs AI classification",
            "Probability calibration",
            "Uncertainty estimation",
            "Language-aware auditing",
            "Explainability-ready schema",
            "Fairness instrumentation"
        ]
    })

# -----------------------------------------------------------------------------
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)