Download server.py from ORCMS/vlps-demo: direct link, hf CLI and curl.
- Browser
- Download file 4.3 kB
-
https://huggingface.co/spaces/ORCMS/vlps-demo/resolve/main/server.py
- Command line
-
hf download hf://spaces/ORCMS/vlps-demo/server.py
-
curl -L -o server.py https://huggingface.co/spaces/ORCMS/vlps-demo/resolve/main/server.py
4.3 kB
| """ | |
| FastAPI backend for the VLPS custom website. | |
| Serves the static frontend (web/) and a JSON API over the core logic. | |
| Run locally: uvicorn server:app --reload --port 7860 | |
| On HF Spaces: CMD in Dockerfile runs uvicorn on 0.0.0.0:7860 | |
| """ | |
| import base64 | |
| import io | |
| import os | |
| import secrets | |
| from fastapi import FastAPI, UploadFile, File, Form, Request | |
| from fastapi.responses import JSONResponse, StreamingResponse, Response | |
| from fastapi.staticfiles import StaticFiles | |
| from PIL import Image | |
| import core | |
| app = FastAPI(title="VLPS Demo") | |
| # Optional password gate. Set APP_PASSWORD (and optionally APP_USER) as a Space | |
| # secret to require a login on a public Space. Left unset -> open (local dev). | |
| APP_USER = os.getenv("APP_USER", "grader") | |
| APP_PASSWORD = os.getenv("APP_PASSWORD", "") | |
| async def password_gate(request: Request, call_next): | |
| if APP_PASSWORD: | |
| header = request.headers.get("authorization", "") | |
| ok = False | |
| if header.startswith("Basic "): | |
| try: | |
| user, _, pwd = base64.b64decode(header[6:]).decode().partition(":") | |
| ok = (secrets.compare_digest(user, APP_USER) | |
| and secrets.compare_digest(pwd, APP_PASSWORD)) | |
| except Exception: # noqa: BLE001 | |
| ok = False | |
| if not ok: | |
| return Response(status_code=401, headers={"WWW-Authenticate": 'Basic realm="VLPS"'}) | |
| response = await call_next(request) | |
| # Always revalidate static assets so UI updates show without a hard refresh. | |
| response.headers["Cache-Control"] = "no-cache" | |
| return response | |
| def _pil(upload: UploadFile) -> Image.Image: | |
| return Image.open(io.BytesIO(upload.file.read())).convert("RGB") | |
| def _ok(data): | |
| return JSONResponse(data) | |
| def _err(e): | |
| return JSONResponse({"error": str(e)}, status_code=200) | |
| def config(): | |
| return {"model": core.MODEL, "user": core.USER} | |
| async def api_search(payload: dict): | |
| try: | |
| return _ok({"results": core.search_images( | |
| payload.get("query", ""), | |
| payload.get("mode", "knn"), | |
| int(payload.get("top_k", 6)), | |
| )}) | |
| except Exception as e: # noqa: BLE001 | |
| return _err(e) | |
| async def api_vqa(image: UploadFile = File(...), question: str = Form(...), | |
| system_prompt: str = Form("")): | |
| try: | |
| return _ok({"answer": core.visual_qa(_pil(image), question, system_prompt)}) | |
| except Exception as e: # noqa: BLE001 | |
| return _err(e) | |
| async def api_ocr_qa(image: UploadFile = File(...), question: str = Form(...), | |
| lang: str = Form("en")): | |
| try: | |
| return _ok(core.ocr_qa(_pil(image), question, lang)) | |
| except Exception as e: # noqa: BLE001 | |
| return _err(e) | |
| async def api_dataset(dataset: str = "textvqa", limit: int = 12): | |
| try: | |
| return _ok({"items": core.dataset_browse(dataset, limit)}) | |
| except Exception as e: # noqa: BLE001 | |
| return _err(e) | |
| async def api_dataset_search(payload: dict): | |
| try: | |
| return _ok({"items": core.dataset_search( | |
| payload.get("dataset", "textvqa"), | |
| payload.get("query", ""), | |
| int(payload.get("k", 6)), | |
| )}) | |
| except Exception as e: # noqa: BLE001 | |
| return _err(e) | |
| async def api_agent(payload: dict): | |
| try: | |
| return _ok(core.agent_answer(payload.get("message", ""), payload.get("session", ""))) | |
| except Exception as e: # noqa: BLE001 | |
| return _err(e) | |
| async def api_agent_reset(payload: dict): | |
| core.reset_agent(payload.get("session", "")) | |
| return _ok({"ok": True}) | |
| def pt_image(image_id: str): | |
| _, lookup = core.pt_data() | |
| img = lookup.get(image_id) | |
| if img is None: | |
| return JSONResponse({"error": "not found"}, status_code=404) | |
| buf = io.BytesIO() | |
| img.save(buf, format="JPEG") | |
| buf.seek(0) | |
| return StreamingResponse(buf, media_type="image/jpeg") | |
| # Static frontend (mounted last so /api/* take precedence). | |
| app.mount("/", StaticFiles(directory="web", html=True), name="web") | |