bassma-api / app.py
ziadabdullah's picture
Upload 2 files
a4e861a verified
"""
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])))