Commit Graph
189 Commits
Author SHA1 Message Date
github-actions[bot] 40c2a850bc chore: update lockfiles 2026-06-13 06:53:22 +00:00
flanandClaude Sonnet 4.6 3e8dddb050 Bump version to 0.3.0 and update CHANGELOG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.3.0
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 12789e83f2 Fix four quality-replacement bugs found by code re-audit
C1/C4: Cap blur-score computation at 1440 px before calling assess_quality
so scores are always on the same Laplacian scale as the embedding path
(which operates on Immich preview thumbnails). Also converts the image to
RGB before scoring and stores 0.0 on assess_quality failure so files
uploaded without a score remain eligible for future quality replacement
instead of occupying a slot permanently.

C2: Fall back to the tracker's mapped-filename set as the pre-upload
baseline when the Frigate GET /api/faces endpoint is unreachable at upload
start. Previously, uploads that succeeded during a partial API outage were
never mapped in frigate_files, leaving get_tracked_frigate_file_count
permanently under-counting those files and allowing Frigate to exceed
MAX_AUTO_IMAGES over time.

C3: Track min_quality_score_for_slot when a quality-replacement delete
succeeds but the subsequent upload fails. This ensures the freed slot can
only be filled by a candidate that beats the deleted file's score, not just
the next file in iteration order (which could be lower quality than what
was deleted).

Add get_tracked_frigate_filenames() to upload_tracker and expand tracker
tests to cover the new function and exclude-parameter behaviour.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 8ee370406b Update README to reflect current pipeline and features
- Pipeline rewritten as 8 steps: separates thumbnail pass (quality filter +
  embeddings) from full-res download and crop; adds quality replacement
  logic at the upload step
- Persistence note updated to cover rejected IDs and RETRY_REJECTED
- Auto mode stopping threshold documented (20%/10% of median pairwise distance)
- Add OUTPUT_DIR env var (was undocumented)
- Local Install section notes interactive vs auto mode behaviour
- QUALITY_REPLACEMENT description tightened

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 5ab2cf2ac5 Polish build flow and README formatting
- update-lockfile.yml: rename workflow to "Update lockfiles"
- release.yml: add explicit uv python install 3.13 for consistency with other workflows
- docker-publish.yml: rename cpu cache scope from linux/amd64-cpu to cpu (now multi-arch)
- README: add GitHub release version badge and License badge
- README: shorten QUALITY_REPLACEMENT table cell

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:52 +00:00
flanandClaude Sonnet 4.6 608ade8499 Fix build flow: lockfile bot, CPU multi-arch, paths-ignore, release guard
- update-lockfile.yml: regenerate all four lockfiles (main + cpu/rocm/intel
  variants) on any pyproject change; add variant pyproject files to trigger
- docker-publish.yml: add lockfiles to paths-ignore so the bot commit does
  not trigger a second Docker build; remove redundant CONTRIBUTING/SECURITY
  entries already covered by **.md; add QEMU to build-cpu; set CPU image to
  linux/amd64,linux/arm64 to match release
- release.yml: inline lockfile generation now covers all variants; add
  workflow_dispatch guard that fails if not dispatched from main

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:52 +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 694e9af127 Add community scaffolding: CONTRIBUTING, SECURITY, issue templates, PR template
- CONTRIBUTING.md: dev-branch workflow, uv setup, test/lint commands
- SECURITY.md: private disclosure to holden@arch.fyi
- .github/ISSUE_TEMPLATE/bug_report.yml: structured form with image tag, versions, logs
- .github/ISSUE_TEMPLATE/feature_request.yml: problem/solution/alternatives form
- .github/PULL_REQUEST_TEMPLATE.md: checklist enforcing dev branch + passing CI
- pyproject.toml: add Changelog and Documentation URLs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 06:52:51 +00:00
github-actions[bot] 2055fe7aae chore: update uv.lock 2026-06-13 05:56:49 +00:00
flanandClaude Sonnet 4.6 d2bc7a94b1 Merge dev into main: NOTICES + 0.2.13
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:55:59 +00:00
flanandClaude Sonnet 4.6 0ce67a7570 Add NOTICES file for if_curator MIT attribution; bump to 0.2.13
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:55:51 +00:00
flanandClaude Sonnet 4.6 650dadd102 Cap quality replacement against tracked files only, not total Frigate count
Previously, effective_count and the jobs.py cap check used the total
Frigate file count (including manually-added files), so any file a user
curated by hand ate into winnow's managed quota. Now:

- get_tracked_frigate_file_count() returns len(frigate_files) from the
  tracker — only files winnow uploaded and reconciled
- effective_count in the upload loop uses this tracker count so
  manually-added files are invisible to the cap
- jobs.py capacity check uses len(frigate_files) instead of the live
  Frigate API count or cached frigate_count
- Frigate API call for known_frigate_files_at_start is now only used
  for the post-upload reconciliation diff, not for cap enforcement

Side-effect: fixes audit bug #1 — an unreachable Frigate GET no longer
zeroes effective_count and bypasses the cap, because the cap is now
read from the always-available local tracker.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:35:26 +00:00
flanandClaude Sonnet 4.6 1615e2e77e Merge feature/quality-replacement into dev
Adds quality replacement for Frigate face training images:
- When a person is at MAX_AUTO_IMAGES cap, replace the lowest-quality
  mapped Frigate file if a better candidate is available
- Quality score is laplacian blur variance from the quality filtering
  pipeline (stored on asset, propagated through tracker)
- Frigate filename mapping uses post-person batch reconciliation:
  poll after all uploads complete, map by filename timestamp order
  (documented race condition limitation in code)
- QUALITY_REPLACEMENT env var (default true) to disable the feature
- Bug fix: f-string TypeError when no mapped files exist (worst=None)
- CI: more aggressive runner disk cleanup to fix NVIDIA build OOM

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:18:26 +00:00
flanandClaude Sonnet 4.6 785ac3cbc6 Add QUALITY_REPLACEMENT to config tests; expand CI disk cleanup
Config tests now verify QUALITY_REPLACEMENT defaults to True and
respects the QUALITY_REPLACEMENT=false env override.

CI: replace minimal disk cleanup with more aggressive removal
(Android SDK ~14GB, Swift, CodeQL, docker system prune) so the
NVIDIA GPU image build no longer exhausts runner disk space.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:18:15 +00:00
flanandClaude Sonnet 4.6 12bccaa631 Fix TypeError when worst mapped file is None in quality replacement
When no mapped files exist for a person, worst is None and the old
f-string tried to subscript it before the conditional was evaluated.
Extracted worst_score_str as a local variable to avoid the crash.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 05:14:15 +00:00
flanandClaude Sonnet 4.6 11e7d4aad7 Implement quality score tracking and batch Frigate file mapping
- Track laplacian blur score through quality filtering pipeline
  (quality.py: blur_score on QualityResult; diversity.py: store on asset;
   executor.py: read via quality_score key)
- Replace per-file polling with post-person batch reconciliation:
  after all uploads for a person complete, poll Frigate (up to 15s)
  until the expected number of new files appear, then map by filename
  timestamp order (Frigate FIFO queue = upload order = timestamp order)
- Document race condition limitation: concurrent external uploads cause
  the batch to be skipped entirely (safe but files go unmapped); noted
  in code as requiring a Frigate API fix (return filename on upload)
- Add two assess_quality integration tests for blur_score

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 04:59:12 +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 9f92e1c919 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:08:22 +00:00
flanandClaude Sonnet 4.6 615c3c3cc6 Fix ruff import ordering in executor.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 03:53:28 +00:00
flanandClaude Sonnet 4.6 a0083cb9fe Fix three bugs found by code audit
- Delete failure retry loop: when delete_frigate_person_files() fails,
  remove the file from the tracker so the next candidate targets a
  different worst file rather than re-attempting the same failed delete.

- Interactive mode quality replacement: _configure_person() never set
  config["quality_replacement"], causing the executor to always default
  to False and silently skip all uploads for at-cap interactive jobs.
  Now mirrors auto_configure by reading Config.QUALITY_REPLACEMENT.

- Silent mapping loss on API flap: after a successful upload, if the
  post-upload GET /api/faces returns None (transient API failure),
  the file was silently left unmapped. Now logs a warning so users
  know quality replacement won't target that file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 03:52:04 +00:00
flanandClaude Sonnet 4.6 129c74720e Add quality replacement for Frigate face training images
When a person is at MAX_AUTO_IMAGES, winnow now replaces the
lowest-quality mapped training image in Frigate if a higher-confidence
candidate is available, keeping the training set always optimised.

Only files winnow uploaded (tracked via frigate_files mapping) are ever
replaced — manually added Frigate training images are never touched.
A concurrent-upload race condition is detected per-file: if N>1 new
files appear after one upload, the mapping is skipped rather than
guessed, logging at INFO level. The per-file snapshot approach is
retained over a batch approach because wrong mappings (which a batch
approach risks on race) are worse than no mapping.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 03:44:36 +00:00
flanandClaude Sonnet 4.6 3e68128ac5 Merge dev into main — release v0.2.12
ROCm (AMD GPU) and Intel GPU support. Full notes in CHANGELOG.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 02:34:16 +00:00
flanandClaude Sonnet 4.6 927ad3a68c Merge feature/rocm-intel-support into dev
Adds ROCm (AMD GPU) and Intel GPU support as new :rocm and :intel image
variants. Full changelog in CHANGELOG.md under [0.2.12].

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 02:32: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
flan 8103801ec8 chore: sync dev to main (0.2.11 release)
- fix: resolve onnxruntime/onnxruntime-gpu conflict clobbering GPU support
- perf: stream thumbnail download in bounded batches to cap peak RAM
- fix: log thumbnail fetch failures; restore get() for duplicate-ID safety
- ci: cancel in-progress Docker builds on superseding push
- ci: enforce GHCR package visibility public after each push
- docs: README and wiki updated with memory guidance and GPU troubleshooting
v0.2.11
2026-06-12 23:40:17 +00:00
flanandClaude Sonnet 4.6 a281b4b896 docs: add mem_limit guidance for CPU users in README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 23:40:07 +00:00
flanandClaude Sonnet 4.6 5345798dc1 ci: enforce GHCR package visibility public after each push
GHCR packages default private on first creation. Add a best-effort
gh api PATCH call at the end of both the multi-arch merge job and the
cpu build job so any new package version is immediately public without
requiring a manual UI step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 18:53:26 +00:00
flanandClaude Sonnet 4.6 046004a5d0 fix: log thumbnail fetch failures and restore get() for duplicate-ID safety
Two small correctness fixes from post-commit code review:

- except Exception: continue swallowed network/auth errors silently; add
  logger.debug so systematic failures are diagnosable in winnow.log
- batch_images.pop() regressed duplicate-asset-ID handling: if Immich
  returns the same asset ID twice within the same 32-item batch window
  (pagination edge case), the second occurrence got None and its embedding
  was silently dropped. Switching back to .get() matches the old
  thumbnail_map.get() behaviour. Peak memory is still bounded to _BATCH
  images because batch_images goes out of scope between batches.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 18:51:44 +00:00
flanandClaude Sonnet 4.6 86ee9a5ba2 ci: cancel in-progress Docker builds when a newer push supersedes them
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 18:09:03 +00:00
flanandClaude Sonnet 4.6 248b7a6270 docs: add batched thumbnail memory fix to 0.2.11 changelog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 18:08:02 +00:00
flanandClaude Sonnet 4.6 5b25b0df06 perf: stream thumbnail download in bounded batches to cap peak RAM
Previously all candidate thumbnails (up to 3000) were loaded into a
single dict before any processing started. At ~5 MB per decoded preview
image, 472 candidates = ~2.4 GB of thumbnail data alone, easily
exhausting a 4 GB container memory limit on CPU.

Now thumbnails are downloaded and processed in batches of 32. Each
image is pop()'d from the batch dict immediately after embedding so the
decoder memory is released before the next batch starts. Peak in-flight
thumbnail memory is now bounded to ~32 × 8 MB = ~256 MB regardless of
candidate pool size. GPU users benefit too — faster first results and
lower host RAM pressure during large runs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 18:07:40 +00:00
github-actions[bot] af9949c47f chore: update uv.lock 2026-06-12 17:45:50 +00:00
flanandClaude Sonnet 4.6 82d057b235 fix: resolve onnxruntime/onnxruntime-gpu conflict clobbering GPU support
insightface 1.0.1 added a hard dep on the CPU onnxruntime package.
Combined with an incorrect override-dependencies entry in 0.2.10 that
forced onnxruntime (no platform marker) unconditionally, both packages
were installed into the venv on x86_64 Linux — the CPU package landed
last and overwrote onnxruntime-gpu, removing CUDAExecutionProvider
from the provider list.

Fix: declare the two packages as conflicting in uv's resolver so only
the correct one is installed per environment.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 17:45:05 +00:00
flanandClaude Sonnet 4.6 fa6dc01366 chore: sync dev to main (0.2.10 release)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 17:01:01 +00:00
flanandClaude Sonnet 4.6 567e568c47 docs: correct CPU embedding speed estimate
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 17:00:37 +00:00
github-actions[bot] 1ed8d7e25e chore: update uv.lock 2026-06-12 16:56:13 +00:00
flanandClaude Sonnet 4.6 32e4235384 docs: add 0.2.10 changelog
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.2.10
2026-06-12 16:51:53 +00:00
github-actions[bot] f1df1c6bb3 chore: update uv.lock 2026-06-12 16:49:21 +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 ad4d212df0 chore: bump version to 0.2.10
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 16:38:40 +00:00
flanandClaude Sonnet 4.6 31e7ca5af0 fix: Frigate face count API structure and Immich 401 error message
Frigate /api/faces response has person names as top-level keys with
lists of filenames — {person: [file, ...], "train": [...]}. The old
code incorrectly looked inside data["train"] as if it were a dict of
persons, causing 'list object has no attribute items' on every run.

Immich get_people() now checks for 401 before raise_for_status() and
logs a clear "API key invalid or expired" message instead of the raw
requests exception string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:58:29 +00:00
flanandClaude Sonnet 4.6 4f6967258f docs: update .env.example and README to reflect VERBOSE and current defaults
- .env.example: add VERBOSE, remove active AUTO_MODE=true (now TTY-detected),
  comment out FORCE_CPU/ENABLE_CACHE default values, update CRON_SCHEDULE
  section to document all three modes
- README: clarify that log file is always DEBUG regardless of VERBOSE

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:50:51 +00:00
flanandClaude Sonnet 4.6 882af37d8e feat: VERBOSE=true enables DEBUG-level console output
The log file already captures DEBUG unconditionally. This env var wires
the same to the Rich console handler for troubleshooting without needing
to read the log file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:49:28 +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 3db52c2141 fix+logging: model load logging, CPU fallback, log level audit
Bugs fixed (from high-effort review):
- InsightFace CPU fallback now passes providers=['CPUExecutionProvider'] and
  wraps in _suppress_output() so broken GPU drivers don't cause fallback to
  try the same broken provider again, and C-extension noise stays suppressed
- scheduler.py: BaseException → Exception (KeyboardInterrupt already re-raised;
  winnow has no sys.exit() calls, so SystemExit would not occur, but Exception
  is the correct scope)
- compose.yml: fix inverted AUTO_MODE comment (docker run -it enables
  interactive mode via TTY, not non-interactive)

Model loading logging (embeddings.py):
- InsightFace: disk cache check, "not cached — downloading now (~300 MB)",
  "loading into memory on GPU/CPU...", "ready on GPU/CPU (Xs)"
- SigLIP: same treatment; cache path derived dynamically from model_name
  via HuggingFace slug convention (models--org--model) so it stays correct
  if the model variant ever changes

Logging level audit (INFO/DEBUG/WARNING/ERROR):
- diversity.py: internal algo steps (clustering, medoids, adaptive threshold,
  auto-stop decision) → DEBUG; final selection summaries stay INFO
- immich_api.py: "Fetching assets" and "Retained N assets" → DEBUG (callers
  already print this to the console via rprint)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:23:44 +00:00
flanandClaude Sonnet 4.6 af8bae1c45 fix: embedding cache key mismatch, scheduler path/exception, log handler leak
embeddings.py: face embedding cache used 'immich' for lookup but
'insightface' for storage, so the cache was never hit for locally-
computed embeddings. Unified to 'insightface'/'siglip' throughout.
This affects all users since ENABLE_CACHE now defaults to true.

scheduler.py: INSIGHTFACE_HOME=/models/.insightface was having
'.insightface' appended again, making buffalo_l check always report
'will download'. Also catch BaseException (not just Exception) so a
SystemExit from a library call can't silently kill all future runs.

log_config.py: handlers.clear() abandoned open FileHandler fds on
each scheduled main() call. Close each handler properly before removal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:10:44 +00:00
flanandClaude Sonnet 4.6 ac9e9530f3 fix: prompt for retry_rejected in interactive mode instead of silently applying env var
RETRY_REJECTED was silently read from the environment in _configure_person,
bypassing user control in interactive sessions. Now prompts the user with
the env var value as the default, so the setting is visible and overridable.

All other env vars in the interactive path are already correct:
YEARS_FILTER is a prompt default, ONLY_PEOPLE/SKIP_PEOPLE/MIN_FACE_COUNT
are auto_configure-only, and TRAINING_MODE/STRATEGY/OBJECT_CLASS are
always prompted.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:03:16 +00:00
flanandClaude Sonnet 4.6 015db63d19 feat: empty CRON_SCHEDULE keeps container alive for manual docker exec
Three container lifetime modes via CRON_SCHEDULE:
  unset          — run once on startup, exit
  empty string   — sleep infinity; use docker exec -it winnow winnow
  cron expression — run on startup, then on schedule

This replaces the need for a separate MANUAL_MODE env var. The empty
string is a natural "I want the container alive but unscheduled" signal.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 15:01:00 +00:00
flanandClaude Sonnet 4.6 2804b21f9e refactor: auto-detect headless mode via TTY; AUTO_MODE becomes an override
The primary use case is headless Docker, so auto mode is now the default
whenever stdin has no TTY. Interactive mode activates when a terminal is
present (docker run -it, local shell). AUTO_MODE=true remains as an
explicit override for scripting with a pseudo-TTY.

Removes AUTO_MODE=true, stdin_open, tty, and FORCE_CPU=false from
compose.yml — none are needed for headless operation. Updates README
and the interactive-mode hint in the CLI.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 14:59:09 +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