Files
FabledCurator/agent/README.md
T
bvandeusenandClaude Opus 5.5 7a09dc3cda
CI and images / lint (push) Successful in 3s
CI and images / extension-version (push) Successful in 3s
extension / lint (push) Successful in 16s
CI and images / frontend-build (push) Successful in 19s
CI and images / backend-lint-and-test (push) Successful in 31s
CI and images / integration (push) Successful in 2m22s
CI and images / sign-extension (push) Successful in 3s
CI and images / build-web (push) Successful in 3m7s
CI and images / smoke-web (push) Successful in 59s
CI and images / build-agent (push) Successful in 6m41s
CI and images / promote (push) Successful in 2s
build: the agent installs one CUDA-13 stack instead of two, the web image drops ML packages it never imported, and Redis moves to 8 (1451, 1452)
Agent:
- The image ran PyPI's CUDA-13 torch 2.14 and onnxruntime-gpu 1.30 on a
  CUDA 12.9 cudnn-runtime base. requirements.txt had silently replaced the
  Dockerfile's torch 2.6+cu124, because ultralytics pulls torchvision, which
  pulls its own torch. That left ~3 GB of base libraries and a ~3 GB torch
  nothing loaded: 10 GB compressed.
- Now: an nvidia/cuda 13.0.3 `base` image, with torch and torchvision
  installed together from cu130. CUDA and cuDNN come from the nvidia-* pip
  packages; onnxruntime-gpu declares its [cuda,cudnn] extras.
- fc_agent/accel.py preloads those libraries for onnxruntime. It then logs,
  and reports in /status, whether torch and the ONNX CUDA provider actually
  got the GPU, since both fall back to the CPU silently.

Web image:
- Drop opencv-python-headless and onnxruntime, plus the opencv-only apt libs.
  Both have been listed since the scaffold and nothing in backend/ imports
  them.
- torch/torchvision move to 2.14/0.29, and the unexplained caps are lifted
  (rule 154).

Redis: 8-alpine in both compose files and both CI service containers. That
gives an AGPLv3 licence option, where 7.4 was RSAL/SSPL only. The client
moves to >=8.1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVjrnpQjRgHdvq95rASoiR
2026-09-24 17:45:39 -04:00

73 lines
3.1 KiB
Markdown

# FabledCurator GPU agent
A desktop-GPU worker that embeds characters (CCIP) + figure crops for
FabledCurator. It talks to FC **only over HTTP** — it leases jobs, fetches image
pixels, runs the models on your GPU, and posts results back. Your FC database and
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:13.0.3-base-ubuntu24.04 nvidia-smi
# the header's CUDA version must be 13.0 or later (driver 580+)
```
## 1. Get a token
In FC: **Settings → Tagging → GPU agent → Generate token** (or Rotate). Copy it.
## 2. Pull (CI publishes it alongside the web image)
```sh
docker pull git.fabledsword.com/bvandeusen/fabledcurator-agent:latest
```
> Local build for development instead: `docker build -t fc-gpu-agent agent/`
## 3. Run (on the machine with the GPU)
```sh
docker run --rm --gpus all -p 8770:8770 \
-e FC_URL=http://curator.traefik.internal \
-e FC_TOKEN=<paste-the-token> \
-v fc-agent-models:/models \
git.fabledsword.com/bvandeusen/fabledcurator-agent:latest
```
Then open <http://localhost:8770> — the control page. Click **Start** to begin
draining the queue; **Pause**/**Stop** to yield the GPU. The `-v fc-agent-models`
volume caches the downloaded ONNX models so restarts are fast.
Kick off a backfill from FC (**GPU agent card → Queue character embedding**), then
watch the queue counts on the control page (or FC's card) drain.
## Config (env)
| var | default | meaning |
|---|---|---|
| `FC_URL` | `http://localhost:8000` | FC base URL |
| `FC_TOKEN` | — | the bearer token (required) |
| `AGENT_ID` | `desktop-agent` | identifies this agent's leases |
| `BATCH_SIZE` | `4` | jobs leased per round (still processed one at a time) |
| `CCIP_MODEL` | imgutils default | CCIP model name |
| `DETECTOR_LEVEL` | `m` | person-detector size: `n` < `s` < `m` < `x` |
| `POLL_IDLE_SECONDS` | `10` | wait between empty leases |
## ⚠️ Verify on first run
This part can't be CI-tested (no GPU/models in CI), so confirm against your
installed `dghs-imgutils` (`pip show dghs-imgutils`) — see `fc_agent/models.py`:
- `imgutils.detect.detect_person(image, level=...)` returns
`[((x0,y0,x1,y1), label, score), ...]`.
- `imgutils.metrics.ccip_extract_feature(image, model=...)` returns a vector
(768-d for caformer). If you want the F1-0.94 variant, set
`CCIP_MODEL=ccip-caformer_b36-24` (verify the exact string in imgutils).
If FC's matcher under/over-fires, tune the cosine threshold in
`backend/app/services/ml/ccip.py` (`DEFAULT_SIM_THRESHOLD`) and use
`GET /api/ccip/overview` + `/api/ccip/images/<id>` to spot-check.
## CPU fallback
Swap `onnxruntime-gpu` → `onnxruntime` in `requirements.txt` and drop `--gpus all`
to grind it slowly on the server instead. Same agent, no card.