diff --git a/agent/README.md b/agent/README.md index da72f44..ac2d7b2 100644 --- a/agent/README.md +++ b/agent/README.md @@ -7,6 +7,17 @@ Redis stay private; the agent never touches them. You run it when you want a burst and stop it to reclaim the card. +## 0. Host prerequisite — NVIDIA Container Toolkit +Docker needs the toolkit to hand the GPU to a container (else: *"could not select +device driver nvidia with capabilities [[gpu]]"*). On Arch/CachyOS: +```sh +sudo pacman -S nvidia-container-toolkit +sudo nvidia-ctk runtime configure --runtime=docker +sudo systemctl restart docker +# verify: +docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi +``` + ## 1. Get a token In FC: **Settings → Tagging → GPU agent → Generate token** (or Rotate). Copy it. diff --git a/agent/fc_agent/app.py b/agent/fc_agent/app.py index 8329297..f93b9fe 100644 --- a/agent/fc_agent/app.py +++ b/agent/fc_agent/app.py @@ -1,13 +1,14 @@ """FastAPI control surface for the agent (served on localhost). -Start / pause / resume / stop the worker, set nothing else here (config is env), -and watch progress + the server-side queue. The container exposes this on a -localhost port; stopping the worker frees the GPU. +Start / stop the worker pool, tune the worker count live (trades desktop +responsiveness for throughput), and watch GPU load + progress + the server-side +queue. Config is env-seeded; the worker count is adjustable here on the fly. """ -from fastapi import FastAPI +from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse, JSONResponse from .config import Config +from .gpu import read_gpu from .worker import Worker cfg = Config.from_env() @@ -26,29 +27,25 @@ def start(): return JSONResponse(worker.status()) -@app.post("/pause") -def pause(): - worker.pause() - return JSONResponse(worker.status()) - - -@app.post("/resume") -def resume(): - worker.resume() - return JSONResponse(worker.status()) - - @app.post("/stop") def stop(): worker.stop() return JSONResponse(worker.status()) +@app.post("/concurrency") +async def concurrency(request: Request): + body = await request.json() + worker.set_concurrency(int(body.get("value", 1))) + return JSONResponse(worker.status()) + + @app.get("/status") def status(): s = worker.status() s["fc_url"] = cfg.fc_url s["configured"] = bool(cfg.token) + s["gpu"] = read_gpu() try: s["queue"] = worker.client.queue_status() except Exception: @@ -59,35 +56,54 @@ def status(): _PAGE = """ FabledCurator GPU agent

FabledCurator GPU agent

FC: · token

-

+

- - -

-

- idle
state
+

+
+ workers + + 1 + + (more = faster + more GPU) +
+
+ stopped
state
+ 0
active now
0
processed
0
errors
-
current image
-

+
+
GPU — …
+