Spaces:
Running
Running
| from fastapi import FastAPI | |
| from fastapi.responses import HTMLResponse | |
| from pydantic import BaseModel, Field | |
| from test_model import mark_pii_context | |
| class MarkRequest(BaseModel): | |
| text: str = Field(..., min_length=1, description="Input text to tag PII") | |
| class MarkResponse(BaseModel): | |
| sentence: str | |
| original_text: str | |
| entities: list[dict] | |
| context: str | |
| app = FastAPI(title="PII Marking API", version="1.0.0") | |
| def test_page() -> str: | |
| return """ | |
| <!doctype html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <title>PII Marking Test</title> | |
| <style> | |
| :root { | |
| --bg: #f7f9fc; | |
| --card: #ffffff; | |
| --text: #1f2a37; | |
| --accent: #0f766e; | |
| --border: #d7dee8; | |
| } | |
| * { box-sizing: border-box; } | |
| body { | |
| margin: 0; | |
| font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; | |
| background: radial-gradient(circle at top left, #e7f4ff, var(--bg) 45%); | |
| color: var(--text); | |
| min-height: 100vh; | |
| display: grid; | |
| place-items: center; | |
| padding: 20px; | |
| } | |
| .card { | |
| width: min(900px, 100%); | |
| background: var(--card); | |
| border: 1px solid var(--border); | |
| border-radius: 12px; | |
| box-shadow: 0 10px 30px rgba(12, 24, 44, 0.08); | |
| padding: 20px; | |
| } | |
| h1 { | |
| margin: 0 0 14px; | |
| font-size: 1.5rem; | |
| } | |
| textarea { | |
| width: 100%; | |
| min-height: 150px; | |
| resize: vertical; | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| padding: 12px; | |
| font-size: 1rem; | |
| line-height: 1.5; | |
| outline: none; | |
| } | |
| textarea:focus { | |
| border-color: var(--accent); | |
| box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.15); | |
| } | |
| button { | |
| margin-top: 12px; | |
| border: 0; | |
| border-radius: 8px; | |
| background: var(--accent); | |
| color: #fff; | |
| padding: 10px 16px; | |
| font-size: 1rem; | |
| cursor: pointer; | |
| } | |
| button:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| } | |
| .result { | |
| margin-top: 18px; | |
| border-top: 1px solid var(--border); | |
| padding-top: 14px; | |
| } | |
| .label { | |
| font-weight: 600; | |
| margin: 10px 0 4px; | |
| } | |
| .value { | |
| background: #f8fafc; | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| padding: 10px; | |
| min-height: 44px; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| } | |
| .error { | |
| margin-top: 12px; | |
| color: #b91c1c; | |
| font-weight: 600; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <main class="card"> | |
| <h1>PII Marking Quick Test</h1> | |
| <textarea id="input" placeholder="Type text to test"></textarea> | |
| <button id="submit" type="button">Run Marking</button> | |
| <section class="result"> | |
| <div class="label">sentence</div> | |
| <div id="sentence" class="value">-</div> | |
| <div class="label">original_text</div> | |
| <div id="original" class="value">-</div> | |
| <div id="error" class="error"></div> | |
| </section> | |
| </main> | |
| <script> | |
| const input = document.getElementById("input"); | |
| const submitBtn = document.getElementById("submit"); | |
| const sentence = document.getElementById("sentence"); | |
| const original = document.getElementById("original"); | |
| const error = document.getElementById("error"); | |
| async function runMarking() { | |
| const text = input.value.trim(); | |
| error.textContent = ""; | |
| if (!text) { | |
| error.textContent = "Please enter some text."; | |
| return; | |
| } | |
| submitBtn.disabled = true; | |
| submitBtn.textContent = "Processing..."; | |
| try { | |
| const response = await fetch("/mark", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ text }) | |
| }); | |
| if (!response.ok) { | |
| throw new Error("Request failed with status " + response.status); | |
| } | |
| const data = await response.json(); | |
| sentence.textContent = data.sentence ?? ""; | |
| original.textContent = data.original_text ?? ""; | |
| } catch (err) { | |
| error.textContent = String(err); | |
| } finally { | |
| submitBtn.disabled = false; | |
| submitBtn.textContent = "Run Marking"; | |
| } | |
| } | |
| submitBtn.addEventListener("click", runMarking); | |
| </script> | |
| </body> | |
| </html> | |
| """ | |
| def health() -> dict: | |
| return {"status": "ok"} | |
| def mark_text(payload: MarkRequest) -> MarkResponse: | |
| try: | |
| result = mark_pii_context(payload.text) | |
| return MarkResponse( | |
| sentence=result["sentence"], | |
| original_text=result["original_text"], | |
| entities=result["entities"], | |
| context=result["context"], | |
| ) | |
| except Exception as e: | |
| from fastapi import HTTPException | |
| raise HTTPException(status_code=500, detail=str(e)) | |