Files
winnow/scheduler.py
T
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

53 lines
1.6 KiB
Python

#!/usr/bin/env python3
import logging
import os
import sys
import time
from pathlib import Path
try:
from croniter import croniter
except ImportError:
print("croniter not installed. Run: uv add croniter")
sys.exit(1)
# Imported at module level so models loaded during the first run stay
# resident in memory across all subsequent scheduled runs.
from winnow.cli import main
SCHEDULE = os.environ["CRON_SCHEDULE"]
MODELS_DIR = os.environ.get("HF_HOME", "/models/huggingface")
INSIGHTFACE_HOME = os.environ.get("INSIGHTFACE_HOME", "/models/.insightface")
logger = logging.getLogger(__name__)
def check_models() -> None:
buffalo = Path(INSIGHTFACE_HOME) / "models" / "buffalo_l"
hf_hub = Path(MODELS_DIR) / "hub"
if not buffalo.exists():
print(" InsightFace Buffalo_L not found — will download on first run", flush=True)
if not (hf_hub.exists() and any(hf_hub.iterdir())):
print(" HuggingFace models not found — will download on first run", flush=True)
NOW = time.time()
cron = croniter(SCHEDULE, NOW)
next_run = cron.get_next(float)
while True:
now = time.time()
if now >= next_run:
print(f"\n[{time.strftime('%Y-%m-%d %H:%M:%S')}] Starting winnow run...", flush=True)
check_models()
try:
main()
print("winnow run complete", flush=True)
except KeyboardInterrupt:
raise
except Exception as e:
logger.error(f"winnow run failed: {e}", exc_info=True)
print(f"winnow run failed: {e}", flush=True)
next_run = cron.get_next(float)
time.sleep(60)