File size: 12,715 Bytes
493bd60 | 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 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | """
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
app.py β "AI TextClassifier" (Stealth Architecture v2)
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
LAYER 1 (Surface): HTML decoy on / β shows a legit ML demo page
+ DistilBERT loaded in RAM for process detection
LAYER 2 (Hidden): FastAPI on /api/v9/core/search β auth-gated search proxy
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
KEY FIX: No Gradio β Gradio triggers HF's SSE/iframe proxy (206 wrapper).
Plain FastAPI serves HTML on / and JSON on /api/* without any wrapping.
"""
import os
import hmac
import logging
from typing import Optional
import httpx
from fastapi import FastAPI, Header, Request
from fastapi.responses import HTMLResponse, JSONResponse
from transformers import pipeline
# ββ Config ββ
SECRET_AUTH_KEY = os.environ.get("SECRET_AUTH_KEY", "e1e26c9be82c2b4635160d56abed53428782745c736f3fcda56e376c8fb9ea9b")
META_API_URL = os.environ.get("META_API_URL", "https://sandeepmudhiraj-meta-api.hf.space")
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger("stealth")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# LAYER 1: ML FOOTPRINT β Load model in RAM (HF process detection)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
logger.info("[DECOY] Loading DistilBERT sentiment classifier...")
classifier = pipeline(
"text-classification",
model="distilbert-base-uncased-finetuned-sst-2-english",
top_k=None,
)
logger.info("[DECOY] Model loaded β ML RAM footprint active")
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# FASTAPI APP β Pure FastAPI, no Gradio (avoids 206 iframe wrapper)
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
app = FastAPI(
title="AI TextClassifier",
docs_url=None,
redoc_url=None,
openapi_url=None,
)
FAKE_404 = {"detail": "Not Found"}
# ββ Decoy HTML page on / ββ
DECOY_HTML = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>π§ AI Text Classifier</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Inter', -apple-system, sans-serif; background: linear-gradient(135deg, #0f0c29, #302b63, #24243e); color: #e0e0e0; min-height: 100vh; display: flex; flex-direction: column; align-items: center; }
.container { max-width: 700px; width: 90%; margin-top: 60px; }
h1 { font-size: 2.2rem; text-align: center; margin-bottom: 8px; background: linear-gradient(90deg, #00d2ff, #3a7bd5); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.subtitle { text-align: center; color: #888; margin-bottom: 40px; font-size: 0.95rem; }
.card { background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.1); border-radius: 16px; padding: 32px; backdrop-filter: blur(12px); }
textarea { width: 100%; min-height: 120px; background: rgba(0,0,0,0.3); border: 1px solid rgba(255,255,255,0.15); border-radius: 10px; padding: 16px; color: #fff; font-size: 15px; resize: vertical; outline: none; margin-bottom: 20px; }
textarea:focus { border-color: #3a7bd5; }
.btn { width: 100%; padding: 14px; background: linear-gradient(90deg, #00d2ff, #3a7bd5); border: none; border-radius: 10px; color: #fff; font-size: 16px; font-weight: 600; cursor: pointer; transition: transform 0.1s; }
.btn:hover { transform: scale(1.02); }
.btn:active { transform: scale(0.98); }
.btn:disabled { opacity: 0.5; cursor: wait; }
#result { margin-top: 24px; padding: 20px; background: rgba(0,0,0,0.3); border-radius: 10px; display: none; }
.label { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid rgba(255,255,255,0.08); }
.label:last-child { border: none; }
.score { color: #00d2ff; font-weight: 600; }
.examples { margin-top: 32px; }
.examples h3 { color: #888; font-size: 0.85rem; margin-bottom: 12px; text-transform: uppercase; letter-spacing: 1px; }
.example { padding: 10px 16px; background: rgba(255,255,255,0.04); border-radius: 8px; margin-bottom: 8px; cursor: pointer; transition: background 0.2s; font-size: 14px; }
.example:hover { background: rgba(255,255,255,0.1); }
.footer { margin-top: 40px; margin-bottom: 30px; text-align: center; color: #555; font-size: 0.8rem; }
</style>
</head>
<body>
<div class="container">
<h1>π§ AI Text Classifier</h1>
<p class="subtitle">Powered by DistilBERT β Real-time Sentiment Analysis</p>
<div class="card">
<textarea id="input" placeholder="Type any sentence to classify its sentiment..."></textarea>
<button class="btn" id="btn" onclick="classify()">Classify Text</button>
<div id="result"></div>
</div>
<div class="examples">
<h3>Try these examples</h3>
<div class="example" onclick="tryExample(this)">This movie was absolutely wonderful! The acting was superb.</div>
<div class="example" onclick="tryExample(this)">I am very disappointed with the service. Terrible experience.</div>
<div class="example" onclick="tryExample(this)">Machine learning is transforming every industry in 2026.</div>
<div class="example" onclick="tryExample(this)">The weather today is quite average, nothing special.</div>
</div>
<div class="footer">DistilBERT (SST-2) Β· Hugging Face Spaces</div>
</div>
<script>
function tryExample(el) { document.getElementById('input').value = el.textContent; classify(); }
async function classify() {
const text = document.getElementById('input').value.trim();
if (!text) return;
const btn = document.getElementById('btn');
const res = document.getElementById('result');
btn.disabled = true; btn.textContent = 'Classifying...';
try {
const r = await fetch('/classify', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({text})});
const data = await r.json();
let html = '';
for (const [label, score] of Object.entries(data)) {
const pct = (score * 100).toFixed(1);
html += `<div class="label"><span>${label}</span><span class="score">${pct}%</span></div>`;
}
res.innerHTML = html; res.style.display = 'block';
} catch(e) { res.innerHTML = '<div style="color:#ff6b6b">Error: '+e.message+'</div>'; res.style.display='block'; }
btn.disabled = false; btn.textContent = 'Classify Text';
}
</script>
</body>
</html>"""
@app.get("/")
async def root():
"""Decoy: serves a beautiful ML demo page."""
return HTMLResponse(content=DECOY_HTML)
@app.post("/classify")
async def classify_endpoint(request: Request):
"""Decoy: real ML classification β makes the space look legit."""
try:
body = await request.json()
text = body.get("text", "").strip()
if not text:
return JSONResponse(content={"error": "No text provided"})
results = classifier(text[:512])
output = {}
for item in results[0]:
output[item["label"]] = round(item["score"], 4)
return JSONResponse(content=output)
except Exception as e:
return JSONResponse(content={"error": str(e)})
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
# LAYER 2: HIDDEN SEARCH API β Auth-gated proxy to SearXNG
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def _verify_auth(auth_value: Optional[str]) -> bool:
if not auth_value:
return False
return hmac.compare_digest(auth_value, SECRET_AUTH_KEY)
@app.post("/api/v9/core/search")
async def hidden_search(request: Request):
"""Hidden: proxies search to our SearXNG. Auth required."""
auth = request.headers.get("x-secret-auth")
try:
body = await request.json()
except Exception:
if not _verify_auth(auth):
return JSONResponse(status_code=404, content=FAKE_404)
return JSONResponse(status_code=400, content={"error": "Invalid JSON"})
if not auth:
auth = body.get("auth")
if not _verify_auth(auth):
return JSONResponse(status_code=404, content=FAKE_404)
query = body.get("q", "").strip()
if not query:
return JSONResponse(status_code=400, content={"error": "Missing 'q'"})
params = {
"q": query,
"format": "json",
"categories": body.get("categories", "general"),
"language": body.get("language", "en"),
"pageno": body.get("pageno", 1),
}
if body.get("time_range"):
params["time_range"] = body["time_range"]
try:
async with httpx.AsyncClient(timeout=20.0, follow_redirects=True) as client:
resp = await client.get(
f"{META_API_URL.rstrip('/')}/search",
params=params,
headers={"User-Agent": "StealthProxy/2.0"},
)
if resp.status_code == 200:
data = resp.json()
cleaned = []
seen = set()
for r in data.get("results", []):
url = r.get("url", "")
if not url or url in seen:
continue
seen.add(url)
cleaned.append({
"title": r.get("title", "").strip(),
"url": url,
"content": r.get("content", "").strip(),
"engine": r.get("engine", ""),
})
logger.info(f"[HIDDEN] '{query[:40]}' -> {len(cleaned)} results")
return JSONResponse(content={"query": query, "results": cleaned, "count": len(cleaned)})
return JSONResponse(status_code=502, content={"error": f"Upstream {resp.status_code}", "results": []})
except httpx.TimeoutException:
return JSONResponse(status_code=504, content={"error": "Timeout", "results": []})
except Exception as e:
return JSONResponse(status_code=503, content={"error": str(e), "results": []})
@app.post("/api/v9/core/health")
async def hidden_health(request: Request):
auth = request.headers.get("x-secret-auth")
try:
body = await request.json()
if not auth:
auth = body.get("auth")
except Exception:
pass
if not _verify_auth(auth):
return JSONResponse(status_code=404, content=FAKE_404)
engine_ok = False
try:
async with httpx.AsyncClient(timeout=5.0, follow_redirects=True) as client:
resp = await client.get(f"{META_API_URL.rstrip('/')}/", timeout=5.0)
engine_ok = resp.status_code == 200
except Exception:
pass
return JSONResponse(content={"status": "operational", "decoy": "active", "engine": "connected" if engine_ok else "unreachable"})
@app.api_route("/api/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def catch_all(path: str):
return JSONResponse(status_code=404, content=FAKE_404)
|