Commit Graph
52 Commits
Author SHA1 Message Date
dependabot[bot] 18305b5b06 chore(deps): bump nvidia/cuda
Bumps nvidia/cuda from 12.8.1-cudnn-runtime-ubuntu24.04 to 12.9.2-cudnn-runtime-ubuntu24.04.

---
updated-dependencies:
- dependency-name: nvidia/cuda
  dependency-version: 12.9.2-cudnn-runtime-ubuntu24.04
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-25 18:53:34 +00:00
flan 001dd2c575 fix: reinstall onnxruntime-gpu after uv sync to guarantee GPU binary wins
insightface depends on onnxruntime (CPU) as a direct dependency. During
uv sync --extra gpu, both onnxruntime (CPU, 24.6 MB binary) and
onnxruntime-gpu (GPU, 24.7 MB binary) are installed in parallel — both
claim onnxruntime/capi/onnxruntime_pybind11_state.so. The last writer wins,
which is non-deterministic in uv's parallel installer.

On GitHub Actions (no GPU, different scheduler ordering), the CPU binary
consistently wins, leaving onnxruntime-gpu's pybind11_state.so as the CPU
version. CUDAExecutionProvider then silently disappears because the CPU
binary's provider registration code has no CUDA EP.

Fix: after uv sync, reinstall onnxruntime-gpu explicitly using the already-
cached wheel. Since uv pip install is synchronous and runs after the parallel
sync completes, the GPU binary is guaranteed to be on disk when the build
layer commits.
2026-06-17 03:05:33 +00:00
flanandgithub-actions[bot] 8acf8b52b8 fix: Immich v2.7.5 compat, supply-chain hardening, and quality fixes (0.5.2) (#23)
* fix: Immich v2.7.5 compat, supply-chain hardening, and quality fixes (0.5.2)

- Remove assetCount pre-filter broken by Immich v2.7.5 API change; check
  MIN_FACE_COUNT after fetch_all_assets instead
- Replace curl|sh uv installer with COPY --from Docker stage (supply chain)
- Fix HEALTHCHECK to use kill -0 on PID file instead of static file test
- Fix CONFIG_FILE path to resolve inside DATA_DIR for volume persistence
- Fix EmbeddingCache singleton to re-init when cache_dir changes
- Fix fd leak in _suppress_output() with nested finally closes
- Fix silent exception on SQLite connection close in upload_tracker
- Log unexpected Frigate API keys at DEBUG in get_all_frigate_person_files
- Add reconcile FIFO-mapping debug log
- Pin all CI action SHAs; update setup-uv v8.2.0, upload/download-artifact,
  ruff-action v4.0.0

* chore: update lockfile

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2026-06-14 19:15:20 -04:00
flan 2a2c6b0c47 Merge remote-tracking branch 'origin/dev' into refactor/code-quality 2026-06-14 20:57:31 +00:00
flan cabdb9c0eb fix: address 9 code review findings
- upload_tracker: partial migration now rolls back atomically on failure;
  JSON renamed only after successful commit so failed runs retry cleanly
- upload_tracker: allowlist score_col in _pick_mapped_file to close
  latent SQL injection surface
- config: move load_dotenv() from module import into _load() so no I/O
  at import time and reset() fully resets env loading
- config: use is None checks for IMMICH_URL/OUTPUT_DIR config-file
  fallback so explicitly empty env vars are not overridden by the file
- executor: skip reconcile when Frigate API is unreachable at upload
  start — tracker baseline is incomplete and would mis-trigger the
  external-upload guard, permanently losing file mappings
- reconcile: change polling break condition from >= to == target so
  transient overshoots don't prematurely exit the loop and trigger
  the external-upload guard
- jobs: apply capacity cap as the selection limit rather than truncating
  post-selection by position, so the diversity algorithm works within
  the right budget from the start
- Dockerfile: explicit gpu branch + exit 1 on unknown VARIANT instead
  of silent fallback
2026-06-14 20:37:51 +00:00
flan e2a1924fb0 refactor: collapse Config proxy, migrate tracker to SQLite, split reconcile module
- Config: remove _ConfigAccessor and ConfigManager; use __getattr__ for lazy
  loading on single _Config class; re-register self as _instance in __getattr__
  so reset() always clears the correct object (item 1)
- upload_tracker: replace hand-rolled JSON store with sqlite3; auto-migrates
  existing JSON on first run; remove dead record_frigate_file function;
  connection re-opens when CACHE_DIR changes for test isolation (items 2, 8)
- diversity: move ThreadPoolExecutor import to module level; inject optional
  fetch_fn parameter for testability (items 3, 6)
- pyproject: consolidate 4 variant files into extras (gpu/rocm/intel/cpu);
  update Dockerfile to use --extra flag; delete variant pyproject/lock files;
  uv.lock needs regen with `uv lock` after this change (item 4)
- jobs: extract _build_job helper to separate business logic from terminal I/O;
  auto_configure delegates dedup/selection to _build_job (item 5)
- logging: convert f-string log calls to % interpolation throughout all winnow/
  modules (item 7)
- reconcile: new module with reconcile_frigate_mappings and
  enrich_asset_with_face_data extracted from executor.py (item 9)
- scheduler: print next scheduled run time after startup and after each run;
  fix f-string logger.error call (item 10)
2026-06-14 19:59:17 +00:00
flan 237dd2091b build: bump amd64 gpu base to NVIDIA CUDA ubuntu24.04
Highest Ubuntu version NVIDIA currently publishes for CUDA 12.8.1.
26.04 not yet available from NVIDIA's image registry.
2026-06-14 19:17:13 +00:00
flan e7bfe00d5d build: bump amd64 rocm and cpu bases to Ubuntu 26.04
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.
2026-06-14 18:55:50 +00:00
flan 274d50ee99 chore: remove remaining dead-mode references from executor, jobs, compose, Dockerfile
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
2026-06-14 17:42:27 +00:00
flanandClaude Sonnet 4.6 9f0a78522f Downgrade GPU base image to CUDA 12.8.1; add benchmark script
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>
2026-06-13 22:19:16 +00:00
flanandClaude Sonnet 4.6 7e90b8e669 Add OCI image labels, issue template config, paths-ignore, and metadata fixes
- 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>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 4c8c219598 Fix Intel GPU Docker build: libze-intel-gpu1 renamed to level-zero
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>
2026-06-13 04:09:18 +00:00
flanandClaude Sonnet 4.6 b2be19e259 feat: add ROCm (AMD GPU) and Intel GPU support (v0.2.12)
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>
2026-06-13 02:31:09 +00:00
flanandClaude Sonnet 4.6 85e499a677 fix: audit — score falsy-zero, crop person mismatch, adaptive cap, suppress_output, ldconfig glob, scheduler sleep
- 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>
2026-06-12 16:48:24 +00:00
flanandClaude Sonnet 4.6 cad053e88f fix: add PYTHONPATH=/app so winnow entry point finds its package
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>
2026-06-12 15:44:56 +00:00
flanandClaude Sonnet 4.6 981a86f28a fix: register all nvidia pip lib dirs with ldconfig; improve GPU warnings
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>
2026-06-12 14:54:31 +00:00
flanandClaude Sonnet 4.6 ee585d4bae feat: add :cpu tag for amd64 CPU-only image
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>
2026-06-12 14:50:12 +00:00
flanandClaude Sonnet 4.6 196b0a5147 fix: INSIGHTFACE_HOME path, entrypoint, caching default, CRON_SCHEDULE opt-in
- 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>
2026-06-12 05:36:47 +00:00
flanandClaude Sonnet 4.6 209e077055 fix: add-apt-repository with GNUPGHOME, true arm64 base; license to AGPLv3
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>
2026-06-12 04:48:28 +00:00
flanandClaude Sonnet 4.6 7bd66c4218 fix: use curl+gpg for deadsnakes PPA, arm64 base back to ubuntu:24.04
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>
2026-06-12 04:36:12 +00:00
flanandClaude Sonnet 4.6 619a96b8c3 fix: re-declare ARG TARGETARCH in each Dockerfile stage
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>
2026-06-12 04:30:00 +00:00
dependabot[bot] d563aa9e74 build(deps): bump nvidia/cuda
Bumps nvidia/cuda from 12.9.2-cudnn-runtime-ubuntu22.04 to 13.3.0-cudnn-runtime-ubuntu22.04.

---
updated-dependencies:
- dependency-name: nvidia/cuda
  dependency-version: 13.3.0-cudnn-runtime-ubuntu22.04
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-12 04:20:26 +00:00
flanandClaude Sonnet 4.6 34d4780554 feat: upgrade to Python 3.13, arm64 base to Ubuntu 26.04
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>
2026-06-12 04:18:50 +00:00
flanandClaude Sonnet 4.6 3087d59558 fix: bump arm64 base to Ubuntu 26.04
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 04:04:20 +00:00
flanandClaude Sonnet 4.6 c59acb5e31 fix: use Ubuntu 24.04 for arm64 base to avoid deadsnakes PPA under QEMU
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>
2026-06-12 04:02:49 +00:00
flanandClaude Sonnet 4.6 4529a63082 fix: add WORKDIR /app to runtime stage in Dockerfile
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>
2026-06-12 02:01:32 +00:00
flanandClaude Sonnet 4.6 eea7baa19f refactor: rename project to winnow
- Rename Python package directory if_curator/ → winnow/
- Update all imports, entry points, and CLI references
- Update pyproject.toml: name, scripts, package list, repository URL
- Update Dockerfile, compose.yml, entrypoint.sh, scheduler.py
- Update GitHub Actions workflow image names
- Update README

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 01:07:46 +00:00
flanandClaude Sonnet 4.6 eedbd3180a fix: resolve all linting errors, add tests, bump base image
Linting (ruff):
- cli.py: sort relative imports (I001)
- jobs.py: remove unused get_people import (F401), wrap long line (E501)
- executor.py: remove unused success variable (F841), wrap 4 long lines (E501)

Tests (24 passing):
- tests/test_config.py: config singleton defaults + env var overrides
- tests/test_upload_tracker.py: mark/filter/reset/summary logic
- tests/test_immich_api.py: filter_recent_assets date boundary cases
- tests/test_jobs.py: _resolve_strategy with LIMIT env var and fallbacks
- pyproject.toml: add [tool.pytest.ini_options] testpaths=["tests"] so
  pytest doesn't scan .venv in CI

Security:
- Dockerfile: bump CUDA base from 12.6.3 to 12.9.2 to pick up patched
  Ubuntu packages (fixes Dependabot low-severity alert)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 00:42:38 +00:00
flanandClaude Sonnet 4.6 2c77532d35 refactor: slim image with proper multi-stage build and --no-dev deps
- 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>
2026-06-12 00:21:01 +00:00
flanandClaude Sonnet 4.6 63cfe62340 fix: move uv sync before source COPY for faster incremental builds
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>
2026-06-12 00:04:28 +00:00
flan a04d1a5d9b fix: force onnxruntime-gpu over CPU + preload CUDA DLLs 2026-06-11 10:34:31 -04:00
flan b0ee06ee51 fix: revert to CUDA 12.6 base for onnxruntime-gpu compatibility 2026-06-11 09:59:53 -04:00
root 30d7d79873 automated update: 2026-06-11 08:22:00 2026-06-11 08:24:45 -04:00
root 54960a0229 automated update: 2026-06-11 00:34:20 2026-06-11 00:34:20 -04:00
root 7210df27c8 automated update: 2026-06-10 23:50:06 2026-06-10 23:50:06 -04:00
root 4670ad2646 automated update: 2026-06-10 23:27:48 2026-06-10 23:27:48 -04:00
root 4909ca3c2e automated update: 2026-06-10 23:19:46 2026-06-10 23:19:46 -04:00
Holden 8e253dc991 fix: add README.md to COPY, move croniter to deps, remove readme field 2026-06-10 22:50:25 -04:00
root fb78f955b8 automated update: 2026-06-10 22:45:29 2026-06-10 22:45:29 -04:00
Holden b16488b771 fix: switch to cu126 index, move torch to [object] extra, update CUDA 12.6 base 2026-06-10 22:41:48 -04:00
root cdf10452fb automated update: 2026-06-10 22:31:20 2026-06-10 22:31:20 -04:00
root b9b734507b automated update: 2026-06-10 22:25:47 2026-06-10 22:25:47 -04:00
root 31b0885e00 automated update: 2026-06-10 21:15:42 2026-06-10 21:15:42 -04:00
root 6b35dec201 automated update: 2026-06-10 21:13:39 2026-06-10 21:13:39 -04:00
root da2c58ae8d automated update: 2026-06-10 20:51:44 2026-06-10 20:51:44 -04:00
root bd9e8d0970 automated update: 2026-06-10 20:13:26 2026-06-10 20:13:26 -04:00
root 76fe87ac06 automated update: 2026-06-10 19:51:09 2026-06-10 19:51:09 -04:00
root ea176c0083 automated update: 2026-06-10 19:47:45 2026-06-10 19:47:45 -04:00
Holden a2f18484a6 better logging 2026-06-10 18:31:43 -04:00
Holden 9aded6e181 fix cron 2026-06-10 16:44:41 -04:00