Skip to main content

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) answers car and 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 by scripts/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.pngIngest page, bulk panel with the source roots and no run
ingest-bulk-run-1600.pngBulk run in progress with the stage table open
ingest-bulk-failures-1600.pngFinished run with two failed images
ingest-policy-1600.pngIngest policy page with the cost preview
vlm-endpoint-off-1600.pngModels page, "VLM for this project: off" card only
audit-1600.pngAudit page
cluster-detail-1600.pngOne cluster's grid and toolbar
assist-dialog-1600.pngThe 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.pngDataset imports list (empty on the sample project)
prompt-packs-list-1600.png, region-profiles-list-1600.png, open-vocab-list-1600.pngThe 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.