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