22.04 non-GPU amd64 bases were never updated when arm64 moved to 24.04.
Python 3.13 is still pulled from deadsnakes PPA (26.04 ships 3.14 natively).
intel stays on 22.04: the Intel GPU repo URL is pinned to the "jammy"
codename and cannot be bumped until Intel publishes 26.04 packages.
After removing the object pipeline, several dead 'mode' artifacts remained:
- executor.py: unpack `config` from job even though it was no longer read
- jobs.py: set `"mode": "face"` in both configure paths (key never consumed)
- compose.yml: TRAINING_MODE=face env, OBJECT_CLASS comment, HF_HOME, stale MAX_AUTO_IMAGES default note
- Dockerfile: "and object classification" label, /models/huggingface mkdir, HF_HOME ENV
CUDA 13.3 requires driver >= 575 but the host only has 570 (error 804).
CUDA 12.8.1 is the highest version supported by driver 570 and works
correctly with the NVIDIA Container Toolkit.
Add scripts/benchmark.py to measure InsightFace + SigLIP latency and
throughput across GPU and CPU modes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: ARG VERSION + OCI labels (title, description, source, licenses, version)
- release.yml: pass VERSION build-arg to all four image builds
- docker-publish.yml: extend paths-ignore to cover community files
- .github/ISSUE_TEMPLATE/config.yml: disable blank issues, link to Discussions and wiki
- README.md: add Getting Help section
- pyproject.toml: expand description; add System Administrators audience classifier
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Intel renamed libze-intel-gpu1 to level-zero in their graphics repository,
breaking the amd64 Intel GPU image build.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New image variants:
- :rocm — InsightFace via ROCmExecutionProvider, SigLIP via PyTorch ROCm 6.3
- :intel — InsightFace via OpenVINOExecutionProvider (onnxruntime-openvino);
Intel GPU compute runtime auto-installed from Intel graphics repo;
OPENVINO_DEVICE=GPU opts into Arc/iGPU inference (default: CPU)
Also adds:
- pyproject-rocm.toml + uv-rocm.lock, pyproject-intel.toml + uv-intel.lock
- compose.yml device passthrough snippets for AMD and Intel
- CI: build-rocm and build-intel jobs in docker-publish.yml; all four
variants built and tagged in release.yml
- README reworked: cleaner structure, GPU variant quick-start examples,
OPENVINO_DEVICE env var documented
- CHANGELOG entry and version bump to 0.2.12
Fix: IntPrompt in dict literal was eagerly evaluated in the no-embedding
fallback path of _get_strategy_choice, prompting users for a custom count
regardless of which strategy they picked.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- immich_api: `score or confidence` treated 0.0 score as falsy; use explicit None check
- diversity: same falsy-zero fix in _get_face_confidence
- diversity: _crop_face_from_thumbnail scale loop now filters by person_id (was
using first person's imageWidth/imageHeight regardless of target in group photos)
- jobs: partially-trained auto mode kept limit="auto" for adaptive stopping, then
caps result to remaining capacity (was converting to int, silently disabling FPS
adaptive threshold and early-stop)
- embeddings: _suppress_output finally block wraps first dup2 in try/finally so
stderr is always restored even if stdout restore raises OSError
- Dockerfile: ldconfig find uses python3.* glob instead of hardcoded python3.13
- scheduler: sleep until next_run instead of fixed 60s; eliminates late-fire jitter
and unnecessary wakeups on long schedules
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
uv sync runs before winnow/ is COPY'd into the build stage, so the wheel
uv builds contains only dist-info (no Python files). The console_scripts
entry point sets sys.path[0] to its own directory (/app/.venv/bin), not
/app, so 'from winnow.cli import main' fails at container startup.
PYTHONPATH=/app makes the package importable regardless of how Python
is invoked (script, -m, entry point, docker exec). This is preferable
to re-ordering the COPY layers, which would bust the heavy uv sync cache
on every winnow/ source change.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The static LD_LIBRARY_PATH only covered cudnn and cuda_runtime — missing
cublas, cufft, curand, cusolver, cusparse, nvjitlink, etc. onnxruntime-gpu
needs libcublasLt.so at minimum, so GPU mode silently fell back to CPU.
Replace with a one-shot ldconfig call over every nvidia site-packages lib/
dir, which covers all packages regardless of what gets installed.
Also: remove the ambiguous directory="" from preload_dlls (use auto-search
default) and add a clear warning when CUDAExecutionProvider is absent so
the user sees actionable guidance instead of silent CPU fallback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces a VARIANT=gpu|cpu build arg to the Dockerfile. The cpu
variant uses ubuntu:22.04 (no CUDA base), installs torch+cpu and
onnxruntime (no GPU deps) via a separate pyproject-cpu.toml / uv-cpu.lock,
and is published as :cpu (dev-cpu on the dev branch) via a new
build-cpu CI job. Saves ~2 GB over the default GPU image.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: ENV INSIGHTFACE_HOME=/models → /models/.insightface to
match compose.yml and .env.example; the old value caused InsightFace
to store models at /models/models/buffalo_l (double-appended subdir)
- entrypoint.sh: use /app/.venv/bin/winnow (installed entry point)
instead of python -m winnow.cli
- config.py: ENABLE_CACHE default false → true; embedding cache is
always beneficial in practice; users can opt out with ENABLE_CACHE=false
- compose.yml: comment out CRON_SCHEDULE so scheduling is opt-in;
flip ENABLE_CACHE to commented opt-out to reflect new default
- README.md: update ENABLE_CACHE default documentation to true
- tests/test_config.py: update default assertion to match
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
curl|gpg --dearmor was silently dropping the deadsnakes key (gpg exits 0
on bad input), leaving apt unable to find python3.13. Reverted to
add-apt-repository with GNUPGHOME=$(mktemp -d) to isolate gpg from any
pre-existing agent socket. Removed --platform=\$BUILDPLATFORM from the
arm64 base so the image contains real arm64 binaries. License updated
from MIT to AGPL-3.0-or-later.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ubuntu 26.04 ships Python 3.14, not 3.13. Reverted arm64 to ubuntu:24.04.
Both architectures now add the deadsnakes PPA by fetching the GPG key via
curl and piping through gpg --dearmor — no gpg-agent, safe under QEMU.
Removes the per-arch conditional and ARG TARGETARCH dependency in RUN commands.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Docker automatic platform ARGs are only in scope for FROM instructions.
$TARGETARCH in RUN commands was always empty, so the deadsnakes PPA
conditional never ran and python3.13 could not be found on the Ubuntu
22.04 CUDA base.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All platforms now use Python 3.13. amd64 installs via deadsnakes PPA on
the Ubuntu 22.04 CUDA base; arm64 gets Python 3.13 natively from Ubuntu
26.04. Verified cp313 wheels exist for onnxruntime-gpu 1.26.0 and
torch 2.12.0+cu126. uv.lock regenerated under CPython 3.13.5.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
add-apt-repository ppa:deadsnakes/ppa fails on arm64 in GitHub Actions
because QEMU emulation doesn't support the GPG agent. Ubuntu 24.04 ships
Python 3.12 natively so the PPA is not needed. amd64 (CUDA/Ubuntu 22.04
base) still uses the PPA. PPA install is now gated on TARGETARCH=amd64.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runtime stage was missing WORKDIR, so uv run started from / and
couldn't find the .venv or pyproject.toml, causing "No module named
'winnow'" on container startup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Dockerfile: separate runtime stage from build stage so g++,
python3.12-dev, curl, gnupg are excluded from the final image
- uv sync --no-dev: drop ruff/pytest from production image
- Remove build.sh (replaced by CI) and root-level upload_tracker.py (stale duplicate)
- .gitignore: add *.log
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
uv sync was after COPY if_curator/, so any source change invalidated
the 800MB dependency cache and re-downloaded everything. Now deps are
installed first and stay cached across code-only changes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>