Spaces:
Sleeping
Sleeping
| """ | |
| Khasi NER service β runs the trained spaCy/RoBERTa pipeline behind a tiny | |
| JSON API. Deployed to a Hugging Face Space; called by the Khasi NLP backend | |
| on Render so the heavy model never has to live on the (small) Render box. | |
| """ | |
| import os | |
| from typing import Optional | |
| from fastapi import FastAPI, Header, HTTPException | |
| from pydantic import BaseModel | |
| import spacy | |
| # Optional shared secret. Set NER_API_KEY in the Space's "Variables and | |
| # secrets" panel β Render sends the same value in the X-Api-Key header. | |
| # If unset, the endpoint is open (fine for local dev, not production). | |
| API_KEY = os.environ.get("NER_API_KEY", "") | |
| # Load once at process boot so every request reuses the warm model. | |
| nlp = spacy.load("model-best") | |
| NER_LABELS = list(nlp.get_pipe("ner").labels) | |
| print(f"[khasi-ner] loaded β components: {nlp.pipe_names} | labels: {NER_LABELS}") | |
| app = FastAPI(title="Khasi NER", version="1.0.0") | |
| class NerRequest(BaseModel): | |
| text: str | |
| def root(): | |
| return {"service": "khasi-ner", "endpoints": ["/health", "/ner"]} | |
| def health(): | |
| return {"ok": True, "labels": NER_LABELS} | |
| def ner(req: NerRequest, x_api_key: Optional[str] = Header(default=None)): | |
| if API_KEY and x_api_key != API_KEY: | |
| raise HTTPException(status_code=401, detail="invalid api key") | |
| doc = nlp(req.text) | |
| return { | |
| "text": doc.text, | |
| "entities": [ | |
| { | |
| "text": ent.text, | |
| "label": ent.label_, | |
| "start": ent.start_char, | |
| "end": ent.end_char, | |
| } | |
| for ent in doc.ents | |
| ], | |
| } | |