Access_gate / app.py
hudaakram's picture
Create app.py
fa2fb5f verified
# FastAPI Space: username + image -> decision, score, threshold, jwt
import os, io, json, time
import numpy as np
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.middleware.cors import CORSMiddleware
from PIL import Image
import jwt
# ---- config ----
MODELS_DIR = os.environ.get('MODELS_DIR', 'models') # put gallery/labels/threshold here
JWT_SECRET = os.environ.get('PORTAL_SECRET', 'change-me') # set a real secret in Space settings
JWT_EXP_SECS = int(os.environ.get('JWT_EXP_SECS', '600')) # 10 min
# ---- load artifacts ----
import json as _json
labels = _json.load(open(f"{MODELS_DIR}/labels.json","r",encoding="utf-8"))
gallery = np.load(f"{MODELS_DIR}/gallery_mean.npy")
thr = _json.load(open(f"{MODELS_DIR}/threshold.json","r"))["cosine_threshold"]
# ---- embedder ----
class FaceEmbedder:
def __init__(self, provider='CPUExecutionProvider'):
import insightface
from insightface.app import FaceAnalysis
self.fa = FaceAnalysis(name='buffalo_l', providers=[provider])
self.fa.prepare(ctx_id=-1, det_size=(640,640))
def __call__(self, img_rgb: np.ndarray):
faces = self.fa.get(img_rgb)
if not faces: return None
f = max(faces, key=lambda z: (z.bbox[2]-z.bbox[0])*(z.bbox[3]-z.bbox[1]))
return f.normed_embedding.astype('float32')
EMB = FaceEmbedder()
# ---- api ----
app = FastAPI(title="Access Gate")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], allow_credentials=True,
allow_methods=["*"], allow_headers=["*"]
)
def issue_token(username: str):
payload = {"sub": username, "iat": int(time.time()), "exp": int(time.time()) + JWT_EXP_SECS}
return jwt.encode(payload, JWT_SECRET, algorithm="HS256")
@app.get("/labels")
def get_labels():
return {"labels": labels}
@app.post("/verify")
async def verify(username: str = Form(...), image: UploadFile = File(...)):
# read image
arr = np.array(Image.open(io.BytesIO(await image.read())).convert("RGB"))
# checks
if username not in labels:
return {"decision": "Not Found", "score": 0.0, "threshold": thr, "reason": "Unknown user"}
emb = EMB(arr)
if emb is None:
return {"decision": "Invalid", "score": 0.0, "threshold": thr, "reason": "No face detected"}
idx = labels.index(username)
score = float(emb @ gallery[idx])
decision = "Allow" if score >= thr else "Deny"
token = issue_token(username) if decision == "Allow" else ""
return {
"decision": decision,
"score": score,
"threshold": thr,
"reason": "",
"token": token
}