--- title: GPU Detection Cluster emoji: ๐ŸŽฎ colorFrom: blue colorTo: purple sdk: docker app_port: 7860 pinned: false models: - onnx-community/rfdetr_medium-ONNX - HuggingFaceTB/SmolVLM-500M-Instruct --- # WebGPU Cluster A **distributed inference grid** that turns browsers with WebGPU into cluster nodes. Host **RF-DETR** object detection or **SmolVLM** image description in a Web Worker; a **Node broker** queues tasks and exposes them over HTTP so any client (`curl`, Python, Node, etc.) can call your GPU. **Repository:** [github.com/apssouza22/webgpu-video-cluster](https://github.com/apssouza22/webgpu-video-cluster) **Live demo (Hugging Face Space):** [apssouza22-webgpu-cluster.hf.space](https://apssouza22-webgpu-cluster.hf.space/) ยท [Space repo](https://huggingface.co/spaces/apssouza22/webgpu-cluster) ```text curl / Python / app โ†’ Node broker (task queue) โ†’ SSE โ†’ browser host (WebGPU) โ†“ RF-DETR ยท SmolVLM ``` Inference runs **in the hostโ€™s browser** on their hardware โ€” not on the broker machine. The broker only coordinates tasks and fetches remote images. ## Quick start ```bash npm install npm run dev ``` 1. Open **http://localhost:5180** (landing page) 2. Click **Join the grid** (or open **http://localhost:5180/host.html**), choose a **model to share**, pick a host id (e.g. `my-gpu-node`), and click **Start hosting** (loads the model on WebGPU; keep the tab open) 3. Open **http://localhost:5180/monitor.html** to see registered hosts and copy curl examples 4. From another terminal: ```bash curl -X POST 'http://localhost:5180/v1/detect' \ -H 'Content-Type: application/json' \ -d '{ "host": "my-gpu-node", "image_url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/coco_sample.png", "threshold": 0.5 }' ``` Response: ```json { "task_id": "...", "host": "my-gpu-node", "threshold": 0.5, "detections": [ { "label": "cat", "score": 0.92, "box": { "xmin": 10, "ymin": 20, "xmax": 200, "ymax": 180 } } ] } ``` `npm run dev` runs **Vite** (port 5180) and the **API broker** (port 8787). Vite proxies `/v1`, `/api`, and `/health` to the broker. ## Endpoints | Method | Path | Description | |--------|------|-------------| | `POST` | `/v1/detect` | Object detection with RF-DETR (waits for host) | | `POST` | `/v1/describe` | Image description with SmolVLM (waits for host) | | `GET` | `/v1/hosts` | List registered hosts and online status | | `GET` | `/v1/models` | Cluster models (id, label, implementation status) | | `GET` | `/v1/tasks/:id` | Task status / results | | `GET` | `/health` | Broker health check | | โ€” | `/` | Landing page โ€” join or view the grid | | โ€” | `/host.html` | Browser host โ€” register and share GPU | | โ€” | `/monitor.html` | Dashboard โ€” live host list and curl examples | | `POST` | `/api/hosts/register` | Called by the browser host | | `GET` | `/api/hosts/stream?host_id=` | SSE โ€” browser host receives tasks | **`POST /v1/detect` body:** - `host` (required) โ€” id from the browser host page - `image_url` or `image_base64` (required) โ€” broker fetches URLs server-side - `threshold` (optional, default `0.5`) **`POST /v1/describe` body:** - `host` (required) - `image_url` or `image_base64` (required) - `instruction` (optional, default `"What do you see?"`) - `max_new_tokens` (optional, default `100`) ## Scripts | Command | Description | |---------|-------------| | `npm run dev` | Vite (5180) + API broker (8787) | | `npm run dev:api` | API broker only | | `npm run dev:web` | Vite only (proxies API when broker is running) | | `npm run build` | Typecheck + production bundle to `docs/` (base `/webgpu-video-ai/` for GitHub Pages) | | `npm run build:space` | Same bundle with base `/` for Hugging Face Spaces | | `npm run preview` | Serve the production build locally | | `npm run start` | Broker + static UI (`SERVE_STATIC=1`, `PORT` default 8787) | | `npm run start:api` | Run broker without watch | ## Cluster models Models are defined in `shared/clusterModels.ts`. The host page dropdown and `GET /v1/models` both read from that list. To add a model: add an entry there, wire loading in `src/pages/addNode.ts` (`ensureModelLoaded`), add a task handler under `src/tasks/`, and register broker routes in `server/`. | Model id | Endpoint | Worker | |----------|----------|--------| | `rfdetr-medium` | `POST /v1/detect` | `src/detection/detection.worker.ts` | | `smolvlm-500m` | `POST /v1/describe` | `src/videodescription/videodescription.worker.ts` | - **RF-DETR:** `onnx-community/rfdetr_medium-ONNX` via `@huggingface/transformers` with `device: 'webgpu'` - **SmolVLM:** `HuggingFaceTB/SmolVLM-500M-Instruct` with quantized vision/decoder weights (same approach as the [SmolVLM realtime WebGPU demo](https://huggingface.co/spaces/webml-community/smolvlm-realtime-webgpu)) Models download from Hugging Face on first load. Inference runs in a **Web Worker**; the broker sends base64 images and the host converts them to `VideoFrame` for the worker. ## Requirements - Browser with **WebGPU** (Chrome or Edge desktop recommended) - Dev server COOP/COEP headers in `vite.config.ts` (required for Transformers.js / WASM) ## Project layout | Path | Role | |------|------| | `server/` | Express broker โ€” task queue, host registry, SSE | | `src/pages/addNode.ts` | Browser host โ€” register, pull tasks, run inference | | `src/pages/clusterMonitor.ts` | Monitor dashboard | | `src/detection/` | RF-DETR worker and main-thread API | | `src/videodescription/` | SmolVLM worker and main-thread API | | `shared/clusterModels.ts` | Model catalog for UI and API | ## Hugging Face Space Hosted at **[apssouza22/webgpu-cluster](https://huggingface.co/spaces/apssouza22/webgpu-cluster)** (Docker SDK, port 7860). | | URL | |--|-----| | Landing | [apssouza22-webgpu-cluster.hf.space](https://apssouza22-webgpu-cluster.hf.space/) | | Host UI | [apssouza22-webgpu-cluster.hf.space/host.html](https://apssouza22-webgpu-cluster.hf.space/host.html) | | Monitor | [apssouza22-webgpu-cluster.hf.space/monitor.html](https://apssouza22-webgpu-cluster.hf.space/monitor.html) | 1. Open the host UI in **Chrome or Edge** (WebGPU required). 2. Choose a host id and model, then click **Start hosting** โ€” keep the tab open. 3. Call the API on the same origin: ```bash curl -X POST 'https://apssouza22-webgpu-cluster.hf.space/v1/detect' \ -H 'Content-Type: application/json' \ -d '{ "host": "my-gpu-node", "image_url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/coco_sample.png", "threshold": 0.5 }' ``` The Space container serves the broker and static files only; **inference runs in the visitorโ€™s browser**. ### Deploy a new version ```bash npm run build:space hf upload apssouza22/webgpu-cluster . . \ --repo-type space \ --exclude ".git/*" \ --exclude "node_modules/*" \ --commit-message "Your change summary" ``` Wait until the Space shows **Running**, then check `curl https://apssouza22-webgpu-cluster.hf.space/health`. Full steps: [SPACES.md](./SPACES.md#deploy-a-new-version). ## License MIT