Download app.py from Ramosh99/test: direct link, hf CLI and curl.
- Browser
- Download file 4.62 kB
-
https://huggingface.co/spaces/Ramosh99/test/resolve/main/app.py
- Command line
-
hf download hf://spaces/Ramosh99/test/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Ramosh99/test/resolve/main/app.py
4.62 kB
| import spaces | |
| import os | |
| import gradio as gr | |
| from transformers import pipeline | |
| from fastapi import HTTPException | |
| from pydantic import BaseModel, ConfigDict | |
| from typing import List | |
| # ββ Model ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ner = pipeline( | |
| "ner", | |
| model="Ramosh99/mixcode_pii_detector", | |
| aggregation_strategy="average", | |
| token=os.getenv("HF_TOKEN"), | |
| ) | |
| # ββ Core inference (ZeroGPU β GPU used only during inference call) ββββββββββββββ | |
| def detect_pii(text: str): | |
| """Run NER and return structured PII results (used by REST API).""" | |
| if not text.strip(): | |
| return {"text": text, "entities": []} | |
| raw = ner(text) | |
| entities = [] | |
| for item in raw: | |
| label = item.get("entity_group", "") | |
| if label.startswith(("B-", "I-")): | |
| label = label[2:] | |
| entities.append({ | |
| "entity": label, | |
| "start": item["start"], | |
| "end": item["end"], | |
| "score": round(float(item["score"]), 4), | |
| }) | |
| return {"text": text, "entities": entities} | |
| def detect_pii_ui(text: str): | |
| """Return list-of-tuples for Gradio HighlightedText (used by UI).""" | |
| res = detect_pii(text) | |
| entities = sorted(res["entities"], key=lambda x: x["start"]) | |
| if not entities: | |
| return [(text, None)] | |
| result, last = [], 0 | |
| for ent in entities: | |
| if ent["start"] > last: | |
| result.append((text[last:ent["start"]], None)) | |
| result.append((text[ent["start"]:ent["end"]], ent["entity"])) | |
| last = ent["end"] | |
| if last < len(text): | |
| result.append((text[last:], None)) | |
| return result | |
| # ββ Gradio Interface βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| demo = gr.Interface( | |
| fn=detect_pii_ui, | |
| inputs=gr.Textbox( | |
| label="Input Text", | |
| placeholder="Enter Sinhala-English codemixed text...", | |
| lines=4, | |
| ), | |
| outputs=gr.HighlightedText(label="Detected PII Entities"), | |
| title="Sinhala-English Codemix PII Detector", | |
| description=( | |
| "Detects PII entities (PERSON, ORG, PHONE, EMAIL, NIC, etc.) in " | |
| "Sinhala-English code-mixed text.\n\n" | |
| "**REST API:** `POST /api/detect` Β· `GET /api/health` Β· Docs: `/docs`" | |
| ), | |
| examples=[ | |
| ["Mage name Kamal, man wada karanne MAS Holdings eke, phone 071-1234567"], | |
| ["ΰΆΈΰΆΰ· email address kamal.perera@gmail.com, NIC number 199912345678"], | |
| ["I live in Colombo and my phone number is 0771234567"], | |
| ], | |
| flagging_mode="never", | |
| ) | |
| # ββ Launch Gradio β properly registers @spaces.GPU with ZeroGPU βββββββββββββββ | |
| gr_app, _local_url, _share_url = demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| prevent_thread_lock=True, | |
| show_api=False, | |
| ) | |
| # ββ REST API routes (added to Gradio's internal FastAPI app) βββββββββββββββββββ | |
| class DetectRequest(BaseModel): | |
| model_config = ConfigDict( | |
| json_schema_extra={"example": {"text": "Mage name Kamal, phone 071-1234567"}} | |
| ) | |
| text: str | |
| class Entity(BaseModel): | |
| entity: str | |
| start: int | |
| end: int | |
| score: float | |
| class DetectResponse(BaseModel): | |
| text: str | |
| entities: List[Entity] | |
| redacted_text: str | |
| def health_check(): | |
| return {"status": "ok", "model": "Ramosh99/mixcode_pii_detector"} | |
| async def api_detect_pii(request: DetectRequest): | |
| if not request.text.strip(): | |
| raise HTTPException(status_code=422, detail="Input text cannot be empty.") | |
| result = detect_pii(request.text) | |
| text = result["text"] | |
| entities = sorted(result["entities"], key=lambda e: e["start"], reverse=True) | |
| redacted = text | |
| for ent in entities: | |
| redacted = redacted[: ent["start"]] + f"[{ent['entity']}]" + redacted[ent["end"]:] | |
| return { | |
| "text": result["text"], | |
| "entities": result["entities"], | |
| "redacted_text": redacted, | |
| } | |
| # ββ Keep process alive βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| demo.block_thread() | |