"""GLiNER 2.5 demo server — identical for every demo. Serves the static page, answers /api/ready, and POSTs {text, ...} to /api/infer, which it delegates to model.infer(). All demo-specific logic lives in model.py. python app.py # local dev on :7860 """ import os import threading import time from flask import Flask, request, send_from_directory import model APP_DIR = os.path.dirname(os.path.abspath(__file__)) STATIC = os.path.join(APP_DIR, "static") # Shared kit-wide assets live in gliner2.5-demo-kit/assets/. Demo-local overrides # can be dropped in demos//static/assets/ and win over shared files of the # same name. URL space is the same: GET /assets/. KIT_ASSETS = os.path.abspath(os.path.join(APP_DIR, "..", "..", "assets")) _LOCK = threading.Lock() # one inference at a time: CPU threads beat concurrency print(f"[boot] {model.DEMO['title']} — mock={model.MOCK}", flush=True) model.warmup() # load model / validate fixtures before first request print("[boot] ready", flush=True) app = Flask(__name__) @app.route("/") def index(): return send_from_directory(STATIC, "index.html") @app.route("/") def static_file(name): # Shared chrome + demo assets. Anything in static/assets/ is served from the # demo-local dir first; falls back to kit-root assets/ for shared files. if name in ("brand.css", "strip.js", "favicon.svg", "og-card.png"): return send_from_directory(STATIC, name) if name.startswith("assets/"): rel = name[len("assets/"):] demo_local = os.path.join(STATIC, "assets", rel) if os.path.isfile(demo_local): return send_from_directory(os.path.join(STATIC, "assets"), rel) kit_shared = os.path.join(KIT_ASSETS, rel) if os.path.isfile(kit_shared): return send_from_directory(KIT_ASSETS, rel) return ("not found", 404) return ("not found", 404) @app.route("/api/config") def config(): """Demo content for the page: title, subtitle, example chips. No results. Demos whose examples carry derived fields (inlined texts, result previews) expose model.config(); others are served straight from model.DEMO.""" cfg = model.config() if hasattr(model, "config") else model.DEMO return {k: v for k, v in cfg.items() if k != "internal"} @app.route("/api/ready") def ready(): return {"ready": True} @app.route("/api/infer", methods=["POST"]) def infer(): data = request.get_json(silent=True) or {} t0 = time.perf_counter() with _LOCK: out = model.infer(data) out["ms"] = round((time.perf_counter() - t0) * 1000) return out if __name__ == "__main__": app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 7860)), threaded=True)