""" Bassma v2 inference endpoint — FastAPI on HuggingFace Spaces. Pure model server. The Telegram bot lives on Vercel; that side calls this /verify endpoint with a shared API key. Endpoints: GET / — health check (also used by keep-alive cron) POST /verify — JSON API for the Next.js frontend AND Vercel bot route Env (set as Space Secrets in the HF UI): HF_TOKEN — read token to pull the private model at startup BASSMA_API_KEY — shared secret with anything that calls /verify (frontend, Vercel /api/telegram, etc.) """ import os import numpy as np from fastapi import FastAPI, Header, HTTPException from pydantic import BaseModel from sentence_transformers import SentenceTransformer MODEL_ID = "ziadabdullah/bassma-v1" HF_TOKEN = os.environ.get("HF_TOKEN") API_KEY = os.environ.get("BASSMA_API_KEY") print("Loading model...", flush=True) model = SentenceTransformer(MODEL_ID, token=HF_TOKEN) print("Model loaded.", flush=True) def normalize(text: str) -> str: return ( text.replace("آ", "ا").replace("أ", "ا").replace("إ", "ا") .replace("ٱ", "ا").replace("ـ", "").strip() ) class VerifyRequest(BaseModel): text_a: str text_b: str class VerifyResponse(BaseModel): similarity: float app = FastAPI(title="Bassma v2") @app.get("/") def health(): return {"status": "ok", "model": MODEL_ID} @app.post("/verify", response_model=VerifyResponse) def verify(req: VerifyRequest, x_api_key: str = Header(default="")): if API_KEY and x_api_key != API_KEY: raise HTTPException(status_code=401, detail="invalid api key") if len(req.text_a.strip()) < 50 or len(req.text_b.strip()) < 50: raise HTTPException(status_code=400, detail="texts too short") embs = model.encode( [normalize(req.text_a), normalize(req.text_b)], normalize_embeddings=True, convert_to_numpy=True, ) return VerifyResponse(similarity=float(np.dot(embs[0], embs[1])))