Skip to content

About

Argus Studio — the Argus suite's web UI and compose orchestration: curate, caption, and export LoRA training datasets

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Argus Studio

The Argus suite's web UI and compose orchestration. The main page demonstrates argus-lens structured image captioning — paste a URL, drag in images, pick a server-side folder, or caption straight from an Immich album — and inspects training-optimised caption variants, raw model outputs, and auto-removed tag analysis. A curator view at /curate talks to argus-curator for dataset ingestion, folder scans, and exports. Upstream acquisition (argus-quarry) runs as a compose profile.

Formerly argus-vision-demo — the old GitHub URL redirects here.

Designed as a living onboarding document -- every parameter includes an inline explanation of what it does and why.

Input form with pipeline parameters

Caption variants output

Raw model outputs and auto-removed tags

Quick Start

Whole suite in one stack (recommended)

The suite repos are designed to run together but stay loosely coupled — bring up only what you need with compose profiles. By default the backends run from their published GHCR images, so no sibling checkouts are needed:

git clone https://github.com/smk762/argus-studio   # this repo
cd argus-studio
cp .env.example .env      # set DATASET_DIR / OUTPUT_DIR, choose UI mode, etc.

Then, from this repo root (frontend builds locally; the backends pull GHCR images):

docker compose up                    # frontend only (demo mode, no backend)
docker compose --profile curator up  # frontend + argus-curator
docker compose --profile lens    up  # frontend + argus-lens
docker compose --profile gallery up  # argus-quarry: acquire PD/CC0 images -> DATASET_DIR
ARGUS_CURATOR_UI_MODE=live \
docker compose --profile forge   up  # frontend + curator + argus-forge (training configs)
docker compose --profile proof   up  # frontend + argus-proof (post-training LoRA evaluation)
docker compose --profile atlas   up  # frontend + argus-atlas (fantasy-map bakes from real terrain)
docker compose --profile full    up  # whole suite (pull + run GHCR images)
docker compose --profile full    pull  # refresh the images to the current *_TAG

Pin a specific released version with the *_TAG vars in .env (CURATOR_TAG / LENS_TAG / QUARRY_TAG / FORGE_TAG / PROOF_TAG / ATLAS_TAG, default latest).

Build from local source instead — clone the sibling repos and layer the build override, which re-adds each backend's build: context:

git clone https://github.com/smk762/argus-lens    ../argus-lens
git clone https://github.com/smk762/argus-curator ../argus-curator
git clone https://github.com/smk762/argus-quarry  ../argus-quarry   # gallery profile
git clone https://github.com/smk762/argus-forge   ../argus-forge    # forge profile
git clone https://github.com/smk762/argus-proof   ../argus-proof    # proof profile
git clone https://github.com/smk762/argus-atlas   ../argus-atlas    # atlas profile

docker compose -f compose.yaml -f compose.build.yaml --profile full up --build
Profile Services started Use it for
(none) frontend Public captioning + read-only /curate demo
curator frontend + argus-curator Scanning / exporting datasets
lens frontend + argus-lens Captioning against a running engine
gallery argus-quarry (acquisition job) + argus-quarry-server Acquiring PD/CC0 images with provenance into DATASET_DIR, browsable at /gallery
forge frontend + argus-curator + argus-forge Turning /curate exports into ready-to-run LoRA training configs (kohya / OneTrainer / diffusers) at /forge. Set ARGUS_CURATOR_UI_MODE=live for the export flow that hands off to it; /forge also takes an export dir typed by hand
proof frontend + argus-proof Post-training LoRA evaluation (epic): review scored eval runs at /proof — pass/fail verdict, per-metric scores, and a keyboard-first HITL review (5-star + structured reject reasons, blind mode) against argus-proof on :8104
atlas frontend + argus-atlas Baking a georeferenced fantasy-map overlay from a DEM at /atlas: GDAL controls, a ComfyUI restyle (off unless ATLAS_ALLOW_BAKE=1), the alignment gate, and a PMTiles archive, against argus-atlas on :8105
full frontend + curator + lens + quarry server + forge + proof + atlas End-to-end acquire → curate → caption → forge → evaluate → bake (set ARGUS_CURATOR_UI_MODE=live)

argus-quarry (the gallery profile) is the upstream producer: it fetches public-domain / CC0 images from open archives with full provenance and licence records, grouped into LoRA-training categories (identity / wardrobe / setting / concept), and publishes a curator-ready <category>/<subject>/ tree into DATASET_DIR. Run it first, then curate the published images:

docker compose --profile gallery up   # fetch -> pool -> publish DATASET_DIR
docker compose --profile curator up   # then scan/curate on /curate

NVIDIA GPUs (optional, needs the NVIDIA Container Toolkit): layer the override so the base stack still runs on CPU-only machines.

docker compose -f compose.yaml -f compose.gpu.yaml --profile full up

The only cross-service coupling is the curate → caption handoff: curator and lens share the dataset at /data/images (DATASET_DIR) so lens can read the manifest's abs_path entries and write .txt sidecars. The curator calls lens server-to-server at the compose service DNS name (http://argus-lens:8100), not localhost. Each service still runs perfectly on its own.

Run services individually

You can also run any piece outside Docker. Start the argus-lens server (in a separate terminal):

# In the argus-lens repo (PyPI install)
pip install argus-lens[server,local]
argus-lens serve --cors --port 8100

If you are developing argus-lens locally, rebuild the wheel and reinstall into the same environment you use for serve (the demo always talks to whatever is running on ARGUS_LENS_URL). Targets use uv so installs work on PEP 668 (externally managed) system Pythons:

cd ../argus-lens
uv venv                 # once: create .venv in the repo
source .venv/bin/activate
uv build
uv pip install --force-reinstall "$(ls -t dist/*.whl | head -1)[server,local,cli]"
argus-lens serve --cors --port 8100

Or use an editable install while hacking Python: uv pip install -e ".[server,local]" from the argus-lens repo (no wheel step).

Caption page (/)

The caption page has five input modes (drag-and-drop works anywhere on the page — images land in Upload, a .jsonl lands in Curate manifest):

  • Single URL — paste an image URL for one structured caption (POST /caption/url).

  • Upload — drag-and-drop (or browse) images from your machine; they stream through POST /caption/stream with per-image progress. A single image gets the full variant breakdown; multiple images run as a batch.

  • Local folder — batch-caption every image in a server-side folder (POST /caption/folder), writing a .txt sidecar next to each image. The folder picker browses GET /folders, which requires a source root:

    argus-lens serve --cors --port 8100 --source-root /path/to/images
    # or: LENS_SOURCE_PATH=/path/to/images argus-lens serve --cors

    In the suite compose this is preset to /data/images (DATASET_DIR). You can also type a path manually if browsing is disabled.

  • Immich — batch-caption an album on your Immich photo server (POST /immich/caption/stream), optionally writing each caption back to the asset's description in Immich. Requires IMMICH_URL / IMMICH_API_KEY on the argus-lens server.

  • Curate manifest — upload a manifest.jsonl produced by /curate (POST /caption/manifest); each row's target_profile is applied per image. Images must be reachable at their abs_path (the shared /data/images mount).

What a result contains (argus-lens ≥ 0.6): one caption per category (identity, wardrobe, pose_composition, setting, lighting, action), each leading with its own category, plus training (tag-style, for SDXL/CLIP), training_prose (sentence-style, for Flux/SD3/T5) and zeroshot. Every variant passes a coherence post-check, so dangling fragments, "The image shows…" openers and hedging are repaired before display. metadata.subjects carries a headcount (count, multiple, agree), so multi-person images can go to face identification in argus-curator. metadata.buckets carries the per-category tags behind each caption. When lens runs with ARGUS_REFINE_MODEL, metadata.refine records which variants an LLM rewrote and why any rewrite was rejected.

The caption page shows training_prose directly under training, and the headcount above the variants: a multi-person image, or one where the tags and prose disagree on the count, is flagged for face ID in /curate. Against an older lens server neither appears.

WD14 tags + an Ollama VLM for prose. In the suite compose, set ARGUS_BACKEND=hybrid:wd14+openai-compat with ARGUS_OPENAI_COMPAT_BASE_URL / ARGUS_OPENAI_COMPAT_MODEL (e.g. http://<ollama-host>:11434/v1, qwen3-vl:8b). The URL is reached from inside the lens container, so use the LAN host's IP, or host.docker.internal for an Ollama on the compose host. The other lens settings are in Configuration.

Curator SPA (/curate)

The curator UI calls ARGUS_CURATOR_URL (default http://localhost:8101). Run the FastAPI app from argus-curator in another terminal.

In live mode the page also offers:

  • Add images to dataset — drag-and-drop images into a folder under the shared dataset (POST /upload on the curator), or pull an Immich album into it via argus-lens (POST /immich/pull); the target folder is pre-filled for scanning.
  • Recent scans — reopen a persisted scan (GET /scan/{scan_id}) without rescanning; history is kept in the browser.
  • Detector badges — what the curator backend can actually do (GET /detectors: torch / cuda / clip / faces / onnx), so greyed-out options explain themselves.
  • Forge training config — after export (and captioning), argus-forge turns the export into a ready-to-run LoRA config for kohya sd-scripts, OneTrainer, or diffusers (POST /config on ARGUS_FORGE_URL, default http://localhost:8103), seeded from the same selection-insight heuristics the panel displays. Demo mode offers a client-side kohya TOML download instead. Two caveats when forge runs in Docker: the generated configs reference container paths (/data/out/…), so substitute your OUTPUT_DIR (and prefer copy-mode exports over symlink) when running train.sh on the host; and if you run forge outside compose, start it with argus-forge serve --cors so the browser can reach it.

Gallery (/gallery)

A view over argus-quarry's provenance database (ARGUS_QUARRY_URL, default http://localhost:8102): pool stats, licence/source/category/subject filters, thumbnails, and a per-image provenance card (source page, photographer, attribution, SHA256). Every photo links straight into /curate with its published subject folder preselected. Run the server with the gallery profile, or standalone:

pip install "argus-quarry[server]"
argus-quarry serve --cors --port 8102

Sources (the second tab on /gallery, or /gallery?view=sources) browses two large public-domain datasets without downloading them. PD12M has 12.4M CC0 / Public Domain Mark images from 640 institutions. Megalith-10m has 9.58M Flickr photos marked public domain, CC0, Flickr Commons or US Gov. Quarry searches a local index of each dataset's metadata (links, captions, sizes), and thumbnails come straight from where each archive hosts its images. Narrow the matches by caption words, institution or Flickr account, licence, minimum size and orientation, and optionally tick individual images. Then name a category and subject folder and land that slice in the pool through quarry's normal ingest (licence gate, SHA256 dedup, provenance).

  • With QUARRY_ALLOW_FETCH=1 on the quarry server, Fetch into the pool does it in place and streams progress. It is a cross-origin POST, so also set QUARRY_CORS_ORIGINS to the studio origin(s) (argus-quarry ≥ 0.3.1).
  • Otherwise (the default), Download slice.json saves the slice. Land it on the quarry host with argus-quarry archives fetch slice.json.

Setup, once (this needs argus-quarry with the archives extra, which the image includes):

# in the argus-quarry repo: archive the metadata (~45 GB incl. PD12M's CLIP embeddings; no photos)
HF_TOKEN=hf_... uv run scripts/fetch_public_domain_metadata.py --root /media/photos/public_domain
# in .env here: PUBLIC_DOMAIN_DIR=/media/photos/public_domain (optionally QUARRY_ALLOW_FETCH=1), then
docker compose run --rm argus-quarry-server archives index    # builds the search index under QUARRY_HOME

PyPI install:

pip install "argus-curator[server,gpu]"
argus-curator serve --cors --port 8101

Local wheel (after uv build or hatch build in the argus-curator repo — you should see something like dist/argus_curator-0.1.1.dev2+g…-py3-none-any.whl):

cd ../argus-curator
source .venv/bin/activate    # or: uv venv && source .venv/bin/activate
uv build
WHEEL="$(ls -t dist/*.whl | head -1)"
uv pip install --force-reinstall "${WHEEL}[server,gpu]"
argus-curator serve --cors --port 8101

Use "${WHEEL}[server]" instead of [server,gpu] if you only need the HTTP API without optional GPU detectors and embeddings. Editable alternative: uv pip install -e ".[server,gpu]" from the argus-curator repo.

From this repo root (activate the same Python venv you use for argus-curator serve), reinstall the newest wheel without cd by pointing at the sibling dist/ (build in argus-curator first so dist/*.whl exists):

WHEEL="$(ls -t ../argus-curator/dist/*.whl | head -1)"
uv pip install --force-reinstall "${WHEEL}[server,gpu]"

Then launch the demo frontend:

# Docker (recommended)
cp .env.example .env
docker compose up          # add --build to rebuild the frontend after source changes
# Or local dev
cd frontend
npm install
npm run dev

Open http://localhost:3000 (captioning) or http://localhost:3000/curate (curation).

Proof (/proof)

Review post-training LoRA evaluation runs from argus-proof (ARGUS_PROOF_URL, default http://localhost:8104). A run browser lists scored runs; the selected run shows its pass/fail verdict, group-collapsed pass-rate, per-metric means (identity / adherence / quality / preference / safety), diversity, and scorer provenance. Below it is the human-in-the-loop review: a keyboard-first grid (1–5 rate, 0 clear, arrows move) with a 5-star rating and a structured, multi-label reject taxonomy (deformation / decoherence / ID-not-applied / …) captured as structured codes, not free text. Blind mode hides each sample's checkpoint/weight/epoch/seed and randomises order to remove expectation bias, revealing provenance after you rate; the borderline (needs-review) band is surfaced first via the automated pre-pass. Saving folds the ratings + reasons + rater id back into the report and recomputes the verdict (POST /report/{id}/hitl). Demo mode reviews a bundled sample report with no backend; run the server with the proof profile, or standalone:

pip install "argus-proof[server]"
argus-proof serve --cors --port 8104

Atlas (/atlas)

Bake one georeferenced fantasy-map overlay from real terrain with argus-atlas (PyPI; ARGUS_ATLAS_URL, default http://localhost:8105). It is the stage after proof: a cartography LoRA that passed evaluation goes in as a file, and atlas does the geodata work with GDAL.

  • New canvas picks a DEM and an optional OSM extract from what the server lists under ATLAS_DEM_DIR (GET /inputs), takes an AOI in degrees, and builds the hillshade, slope, layer masks and composite (POST /controls). No GPU, so this works on a read-only host too.
  • The job view shows each control on the canvas grid with the painted map over it and an opacity slider. The coastline should not move as you fade: the model only painted pixels inside a frame GDAL had already georeferenced.
  • Bake streams POST /bake/stream with a style preset (GET /presets), a checkpoint and an optional LoRA. It is off unless the server sets ATLAS_ALLOW_BAKE=1; the form then stays visible with the reason. A bake that fails the alignment gate keeps its PNG and writes no GeoTIFF.
  • Cut PMTiles (POST /tiles) packs the aligned GeoTIFF up to its native zoom; the archive downloads from the page. Drape it on a basemap with atlas's examples/viewer.html.
  • Provenance lists the DEM hash and every GDAL command, so a bake can be replayed.

In compose, put DEMs (GeoTIFF or .vrt) in DEM_DIR and point MODELS_DIR / COMFYUI_BASE_URL at the ComfyUI the bake uses. Standalone (GDAL must be installed):

pip install "argus-atlas[server,cli,tiles]"
argus-atlas serve --cors          # :8105; add ATLAS_ALLOW_BAKE=1 to bake

Architecture

argus-quarry (gallery profile, run-to-completion)
   └─ acquire PD/CC0 + provenance ──▶ /data/images (DATASET_DIR)

browser (:3000)  →  Next.js frontend
                         ├─ /caption/*, /immich/*  →  argus-lens (:8100)          →  captioning
                         ├─ /scan, /upload, …      →  argus-curator (:8101)       →  curation API
                         ├─ /photos, /stats, …     →  argus-quarry-server (:8102) →  provenance (read-only)
                         ├─ /config                →  argus-forge (:8103)         →  training configs
                         ├─ /reports, /report/*    →  argus-proof (:8104)         →  LoRA evaluation + HITL review
                         └─ /controls, /bake/*, …  →  argus-atlas (:8105)         →  DEM → fantasy-map PMTiles

curate → caption → forge handoff ("full" profile):
   /curate export ── manifest ──▶  argus-lens /caption/manifest/stream
        └───────────── shared /data/images ─────────────┘
   then argus-forge /config reads the export (+ collects .txt sidecars)
        and writes kohya / OneTrainer / diffusers configs under <export>/forge/

Immich (optional):  argus-lens ⇄ IMMICH_URL  (album captioning, write-back, pull-to-dataset)

Argus Studio is a thin frontend-only wrapper. It sends JSON requests to the argus-lens and argus-curator HTTP servers and renders results. No backend code lives in this repo — the suite compose.yaml runs the backends from published GHCR images by default (or builds them from their sibling repositories when you layer compose.build.yaml).

  • Frontend — Next.js 15 (App Router) + Tailwind CSS v4, dark theme
  • Captioning server — argus-lens[server] (see argus-lens)
  • Curation server — argus-curator[server] (optional gpu extra; see argus-curator)

Configuration

Variable Default Description
ARGUS_LENS_URL http://localhost:8100 URL the browser uses to reach the argus-lens API
ARGUS_CURATOR_URL http://localhost:8101 URL the browser uses to reach the argus-curator API (/curate)
ARGUS_QUARRY_URL http://localhost:8102 URL the browser uses to reach the argus-quarry provenance API (/gallery)
PUBLIC_DOMAIN_DIR ./public_domain Host dir holding the archived pd12m/ and megalith/ metadata, mounted read-only into the quarry server for /gallery → Sources
QUARRY_ALLOW_FETCH (unset) Let the quarry server land a Sources slice in the pool itself; unset, the page hands back slice.json + the CLI command
QUARRY_CORS_ORIGINS (unset = read-only *) Comma-separated studio origins the quarry server allows; required for Fetch into the pool (argus-quarry ≥ 0.3.1)
ARGUS_FORGE_URL http://localhost:8103 URL the browser uses to reach the argus-forge training bridge (/forge)
ARGUS_PROOF_URL http://localhost:8104 URL the browser uses to reach argus-proof (the /proof eval-review view)
ARGUS_ATLAS_URL http://localhost:8105 URL the browser uses to reach argus-atlas (the /atlas map-bake view)
ARGUS_CURATOR_UI_MODE demo demo (bundled sample, no backend) or live (real scans/exports)
ARGUS_CURATOR_SOURCE_PATH (empty) Default source path shown in the folder picker (path inside the curator container). compose.yaml sets /data/images
ARGUS_CURATOR_OUTPUT_PATH (empty) Default export destination (path inside the curator container). compose.yaml sets /data/out
DATASET_DIR ./data Host dir mounted at /data/images on both curator and lens
OUTPUT_DIR ./out Host dir mounted at /data/out on curator (exports)
HF_CACHE_DIR ~/.cache/huggingface Host Hugging Face cache shared with the backends
ARGUS_BACKEND hybrid argus-lens captioning backend. hybrid:wd14+openai-compat = WD14 tags locally + prose from an Ollama/vLLM vision model
WD14_MODEL_REPO (unset = SmilingWolf/wd-vit-tagger-v3) WD14 v3 tagger for lens; SmilingWolf/wd-eva02-large-tagger-v3 is the most accurate
WD14_CACHE_DIR ~/.cache/wd14_tagger Host WD14 model cache mounted into lens (RW, so a new WD14_MODEL_REPO can download)
ARGUS_OPENAI_COMPAT_BASE_URL / ARGUS_OPENAI_COMPAT_MODEL / ARGUS_OPENAI_COMPAT_API_KEY (unset) Vision-model endpoint, model and optional key for lens's openai-compat prose stage, e.g. http://<ollama-host>:11434/v1 + qwen3-vl:8b
ARGUS_OPENAI_COMPAT_PROMPT detailed Prompt preset (detailed, straightforward, descriptive, booru, count) or literal text
ARGUS_REFINE_MODEL / ARGUS_REFINE_BASE_URL / ARGUS_REFINE_API_KEY (unset = off) Chat model that rewrites lens's training captions; every rewrite is validated and falls back to the deterministic caption
ARGUS_REFINE_VARIANTS training,training_prose Variants lens refines; add identity,wardrobe,setting,action for cleaner category captions
ARGUS_IDLE_UNLOAD_S / ARGUS_GPU_COORDINATOR (unset) / none Lens frees its VRAM after this many idle seconds when it shares a GPU with ComfyUI; lease serialises argus jobs only
IMMICH_URL / IMMICH_API_KEY (unset) Enable the Immich integration on argus-lens (album captioning + pull-to-dataset)
DEM_DIR ./dem Host dir of DEMs and vector layers, mounted at /data/dem on argus-atlas
ATLAS_ALLOW_BAKE / ATLAS_ALLOW_OSM (unset) Let argus-atlas bake on the GPU / fetch OSM from Overpass; both off by default
LENS_SOURCE_PATH /data/images Root the caption page's folder picker browses on lens (GET /folders)
CURATOR_TAG / LENS_TAG / QUARRY_TAG / FORGE_TAG / PROOF_TAG / ATLAS_TAG latest GHCR image tag per backend on the default pull path; pin an exact release for reproducible deploys
LENS_EXTRAS server,local pip extras for a source build only (-f compose.build.yaml); ignored on the default pull path (server,openai,replicate for a cloud-only image)
PROOF_EXTRAS server,cli pip extras for a source build only (-f compose.build.yaml); server,cli,score adds the identity/quality/safety scorer stack
FRONTEND_PORT / LENS_PORT / CURATOR_PORT 3000 / 8100 / 8101 Host ports
QUARRY_SERVER_PORT / FORGE_PORT / PROOF_PORT / ATLAS_PORT 8102 / 8103 / 8104 / 8105 Host ports

The ARGUS_* frontend variables are resolved per request from the container's environment, not baked into the client bundle, so docker compose up -d frontend applies a change without a rebuild — one published image deploys to any origin.

Behind a reverse proxy, give each service a path prefix on the proxy's origin:

ARGUS_CURATOR_URL=/api/curator   # browser calls /api/curator/scan/folder
ARGUS_LENS_URL=/api/lens

An empty string means the origin root (/scan/folder instead of http://host:8101/scan/folder). That works for at most one backend: all six services expose /health, curator and lens both expose /folders, and curator and quarry both expose /thumb, so a shared root is ambiguous. Use prefixes when more than one service sits behind the proxy.

The pre-existing NEXT_PUBLIC_* names are still honoured as a fallback for older .env files. The one rename that is not a straight prefix swap: NEXT_PUBLIC_API_URL is now ARGUS_LENS_URL.

The repo-root .env is read by docker compose. A host npm run dev does not see it — put local overrides in frontend/.env.local.

Parameters

All captioning parameters are exposed in the UI with inline documentation:

Parameter Default Description
target_style photo photo for realism models, anime for booru-tagged models
target_backend sdxl Diffusion backend — determines CLIP/T5 token budget (60–200 tokens)
target_category identity Which category variant becomes final_caption
prose_enrichment true Append novel prose-derived tokens to training variant at lowest priority

Related

  • argus-lens — captioning engine, CLI, and server for the main page. For a whole library at scale (caption once, group by identity/wardrobe/setting/action, flag multi-person images, export SDXL and Flux datasets), see its curate-index workflow
  • argus-curator — dataset curation CLI and HTTP server for /curate
  • argus-quarry — provenance-first PD/CC0 image acquisition (the gallery compose profile)
  • argus-forge — training bridge: curated exports → ready-to-run LoRA training configs (the forge profile)
  • argus-proof — post-training LoRA evaluation and optimisation (the proof profile; epic)
  • argus-atlas — georeferenced fantasy-map overlays from real terrain: DEM in, PMTiles out (the atlas profile)

License

MIT

About

Argus Studio — the Argus suite's web UI and compose orchestration: curate, caption, and export LoRA training datasets

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages