Screenshots and image credits
OpenProcessor is a backend and has no UI of its own. Two kinds of
screenshots appear in these docs: the tools the stack ships (Swagger UI,
Prometheus, Grafana, MLflow, OpenSearch Dashboards; see
Backend screenshots), and the curation screens,
which were captured from Cropwright, a frontend for this backend,
and are used here because they show backend-driven features directly:
cluster cards (GET /curation/projects/{project}/clusters), review queues
(GET /curation/projects/{project}/review/{tab}), region review, training
(the train routes) and model comparison (the bakeoff routes).
The files live under docs-site/static/img/screenshots/. The landing-page
showcase list is docs-site/src/data/screenshots.json. Pages embed a
capture with <Screenshot name="cropwright/<file>.png" />; a slot whose file
does not exist yet renders a "pending" placeholder. See
Cropwright screenshots for how they are made.
Cropwright screenshots
frontend/scripts/capture_docs_screenshots.py drives a real browser against
a running Cropwright instance and writes full-page PNGs into
docs-site/static/img/screenshots/cropwright/. Route captures come in two
widths (1600 and 800 px); only the 1600 px files are committed. States
(a dialog opened, a crop selected, a bulk run in progress) are captured at
1600 px only. The capture is read-only: every request except GET and HEAD
and a short allow-list of side-effect-free report calls is aborted (the
list is READ_ONLY_CALLS in frontend/scripts/docs_screenshots/guard.py).
Data rule
Public data only. Capture projects that hold COCO (coco-bench-2k,
make sample-coco) or Open Images plates (openimages-plates,
make sample-plates).
The script does not enforce this. A shared development stack can also hold non-public projects, and some pages list every project slug. On such a stack:
- pass
--project <public-slug>and capture project-scoped pages only; - never capture
projects,projects/combine, the project switcher,clone-from-project,models-sharing*, or the endpoint table on Settings, Models (its "Used by" column lists every project); - refresh global pages only from an isolated stack seeded with the sample tooling.
Open every PNG before you commit it and look for project slugs, host names, file paths and class names that are not sample data.
Capture
# Once: creates frontend/e2e/.venv with Playwright.
cd frontend && npm run test:e2e
# From the repository root. OP_CROPWRIGHT_URL has no default.
make docs-screenshots OP_CROPWRIGHT_URL=http://localhost:<cropwright-port>
make docs-screenshots runs the script with --project $(DOCS_PROJECT),
which defaults to coco-bench-2k. It captures every route in
frontend/scripts/screenshot_routes.json (including projects and
combine-wizard) and every state. On a shared stack that holds non-public
projects, do not use it: call the script directly with --only.
cd frontend
e2e/.venv/bin/python scripts/capture_docs_screenshots.py \
--base-url http://localhost:<cropwright-port> --project coco-bench-2k \
--only audit ingest-policy --out ../artifacts_local/screens_check
--out defaults to the committed directory. Capture into a scratch
directory first, look at the result, then copy the files you want to keep.
States that need data you write first
The browser never writes. A state that needs a run in progress or a failed
run reads throwaway projects named
cwlife-*, which frontend/scripts/docs_screenshot_fixtures.py creates
with plain API calls (every write asserts the cwlife- prefix).
cd frontend
# Two throwaway projects: a bulk run in progress and a finished run with two
# missing paths. <api-container> is the API container name; the folder is a
# container path with public images. The run takes about half a minute, so
# capture right after, with the two variables the command prints.
python3 scripts/docs_screenshot_fixtures.py bulk --base-url http://localhost:<api-port> \
--folder /data/source/valid/images --container <api-container>
BULK_RUN_PROJECT=<printed> BULK_FAIL_PROJECT=<printed> \
e2e/.venv/bin/python scripts/capture_docs_screenshots.py --base-url http://localhost:<cropwright-port> \
--project coco-bench-2k --only ingest-bulk-run ingest-bulk-failures
The bulk command starts the run with 8 images per batch and 2 batches in
flight, so it is slow enough to catch mid-run. The speed shown in that
screenshot is therefore not a throughput figure; quote only
docs/PERFORMANCE.md.
A deleted project slug is retired for good, so each bulk call uses fresh
slugs. teardown deletes every cwlife-* project.
Seeded capture on an isolated stack
Seventeen states need data that a shared stack does not reliably hold: the
prompt-pack and region-profile editors and tests, multi-box review and the box
editor, the import wizard, job and review, the Reprocess dialog's served
scopes, the lock badge, the VLM run picker, the Resources menu, a finished run's
confusion matrix, the bulk-ingest panel and the VLM-off card. The capture script
seeds all of it itself on a throw-away stack that holds nothing else, so no
screenshot depends on a host's projects, paths or banners (the list is
SEEDED_STATES in frontend/scripts/docs_screenshots/registry.py).
The stack is the live harness (docker/test/compose.yml) plus the
compose.docs-shots.yml overlay: OpenSearch, the API, Cropwright, and stand-ins
for the VLM, the segmenter and the trainer. It needs no GPU and no Triton. Use
your own compose project name and ports so it cannot touch another stack:
# Once: the public data, and the capture venv.
make sample-coco-import sample-coco-readme
(cd frontend && npm run test:e2e)
export VERIFY_COMPOSE_PROJECT=shots VERIFY_CONTAINER_PREFIX=shots \
VERIFY_API_PORT=14711 VERIFY_OPENSEARCH_PORT=14712 \
VERIFY_FAKE_VLM_PORT=14714 VERIFY_CROPWRIGHT_PORT=14715
COMPOSE="docker compose -p shots -f docker/test/compose.yml -f docker/test/compose.docs-shots.yml"
rm -rf docker/test/verify-data # an empty stack starts from empty directories too
$COMPOSE up -d --build --wait
cd frontend && e2e/.venv/bin/python scripts/capture_docs_screenshots.py \
--base-url http://localhost:14715 --seeded --container shots-api \
--out ../artifacts_local/screens_seeded # omit --out to write the committed directory
$COMPOSE down -v --remove-orphans
--seeded refuses a stack that holds any project beyond default (a stack it
already seeded is reused, so a re-run only captures again), seeds five public
projects (coco-sample, coco-vehicles, coco-import, coco-editors,
coco-vlm-off) through the curation API, and writes the same 17 files on every
run. It exits non-zero if any state fails. --only <state>... narrows a re-run.
What is real and what is a stand-in, so nobody reads a number off these images:
- Real: the public COCO images and their labels (a YOLO and a COCO dataset
import through
/datasets/imports), the region profile, the detection worker's region stage and the prompt-pack test run (both against the stand-ins below), classes, clusters, the export and the training-run bookkeeping. - Stand-ins: the VLM (
docker/test/fake_vlm.py) answerscarand a fixed accept, accept, reject verdict per box; the segmenter (docker/test/fake_segmenter.py) returns the same wheel-shaped boxes for every crop, so the wheel boxes are geometry, not detections; the trainer (docker/test/fake_trainer.sh) runs no model, and the per-class table and confusion matrix of the results screenshot are illustrative numbers written byscripts/curation/seed_docs_run_results.py; the cluster grid's embedding vectors are synthetic (scripts/curation/seed_docs_embeddings.py). Triton is absent, so the status chip and the Resources menu show monitoring services as not running.
Slots added for the ingest, pipeline and audit pages
File under cropwright/ | Page and state |
|---|---|
ingest-bulk-panel-1600.png | Ingest page, bulk panel with the source roots and no run |
ingest-bulk-run-1600.png | Bulk run in progress with the stage table open |
ingest-bulk-failures-1600.png | Finished run with two failed images |
ingest-policy-1600.png | Ingest policy page with the cost preview |
vlm-endpoint-off-1600.png | Models page, "VLM for this project: off" card only |
audit-1600.png | Audit page |
cluster-detail-1600.png | One cluster's grid and toolbar |
assist-dialog-1600.png | The Assist dialog on a cluster with the page selected and a representative sample chosen; the server's dry run only, nothing is started |
dataset-imports-1600.png | Dataset imports list (empty on the sample project) |
prompt-packs-list-1600.png, region-profiles-list-1600.png, open-vocab-list-1600.png | The three settings list pages |
The older state slots are listed in Cropwright screenshots, UI states.
Backend screenshots
The "See the backend in action" gallery on the landing page, and the
screenshots on Monitoring and
Training, bake-off and promote,
are the tools the stack ships, captured by
scripts/docs/capture_backend_screens.py from a stack holding public
sample data only:
# 1. A few minutes of read-only inference traffic (COCO val2017 images),
# so the dashboards have live data. Nothing is ingested or indexed.
.venv/bin/python scripts/docs/capture_backend_screens.py traffic \
--api http://localhost:<api-port> --seconds 300
# 2. 1600-px screenshots of every tool.
.venv/bin/python scripts/docs/capture_backend_screens.py capture \
--api http://localhost:<api-port> --prometheus http://localhost:<prometheus-port> \
--grafana http://localhost:<grafana-port> --mlflow http://localhost:<mlflow-port> \
--osd http://localhost:<dashboards-port> --out <dir>
It writes the model status (GET /models/, rendered as a terminal
frame), Swagger UI's endpoint groups, Prometheus target health, each
Grafana dashboard, MLflow's experiment, run, metric-chart and run
comparison pages, and OpenSearch Dashboards' index list. Grafana needs a
viewer login: the script reads DOCS_GRAFANA_TOKEN (a service-account
token) or DOCS_GRAFANA_USER and DOCS_GRAFANA_PASSWORD from the
environment, sends them only to Grafana, never prints them, and skips
Grafana when they are unset. The script refuses any URL on ports
4600-4799, which are reserved for non-public stacks. Copy the PNGs you
want into docs-site/static/img/screenshots/ as backend-<name>.png and
list them in docs-site/src/data/backend_screenshots.json.
The screenshots show the user interfaces of Swagger UI (Apache-2.0), Prometheus (Apache-2.0), Grafana (AGPL-3.0), MLflow (Apache-2.0) and OpenSearch Dashboards (Apache-2.0); product names belong to their respective owners. The data in them (model names, metrics, runs, index counts) comes from the public-sample-data stack.
The landing-page walkthrough GIF
docs-site/static/img/openprocessor-workflow.gif is built by
scripts/docs/create-workflow-gif.sh (ImageMagick) from frames captured
by scripts/docs/capture_hero_frames.py and
scripts/docs/capture_backend_screens.py against a running stack holding
public sample data:
OP_DOCS_API=http://localhost:<api-port> \
OP_DOCS_PROMETHEUS=http://localhost:<prometheus-port> \
OP_DOCS_GRAFANA=http://localhost:<grafana-port> \
OP_DOCS_MLFLOW=http://localhost:<mlflow-port> \
OP_DOCS_OSD=http://localhost:<dashboards-port> \
PYTHON=.venv/bin/python scripts/docs/create-workflow-gif.sh
The frames run in this order, each with a caption bar: a terminal session
(/detect on a public COCO image, /embed/text, the curation ingest
limits and status), Swagger UI, Triton model status, the Grafana
dashboards, Prometheus targets, MLflow runs and a run comparison,
OpenSearch Dashboards, and two closing frames from the Cropwright
screenshots above. Each tool's frames are skipped when its URL is unset
(Grafana's also without a login). Every request the capture makes is
read-only. Per-frame display times are the DELAY table at the top of
the script (dense UI frames 4-5 s, terminal frames under 2 s).
KEEP_FRAMES=<dir> keeps the captioned frames for review, and
GIF_COLORS (default 96) trades palette size against file size; keep the
GIF under about 1.5 MB. Set heroDemo to null in
docs-site/site.config.ts to hide it.
Image credits
The screenshots show photographs from the COCO
2017 set and the
Open Images V7
"Vehicle registration plate" subset, fetched by the sample tooling above.
COCO images are Flickr uploads under their owners' Creative Commons
licenses (filtered to redistributable ones); Open Images images are listed
by their authors as CC BY 2.0. Per-image author and license records are in
the ATTRIBUTION.csv each fetch writes. Boxes, labels and scores shown are
produced by OpenProcessor and drawn by Cropwright, not by either dataset.
Building these docs
cd docs-site
npm ci
npm run build # fails on any broken link or anchor
npx docusaurus serve # preview the production build
docs-site/Dockerfile builds the same site into an unprivileged nginx
image, and .github/workflows/docs.yml builds it on pull requests and
publishes it to GitHub Pages from the default branch.