diff --git a/scheduler.py b/scheduler.py index c770134..ae98438 100644 --- a/scheduler.py +++ b/scheduler.py @@ -17,13 +17,13 @@ from winnow.cli import main SCHEDULE = os.environ["CRON_SCHEDULE"] MODELS_DIR = os.environ.get("HF_HOME", "/models/huggingface") -INSIGHTFACE_BASE = os.environ.get("INSIGHTFACE_HOME", "/models") +INSIGHTFACE_HOME = os.environ.get("INSIGHTFACE_HOME", "/models/.insightface") logger = logging.getLogger(__name__) def check_models() -> None: - buffalo = Path(INSIGHTFACE_BASE) / ".insightface" / "models" / "buffalo_l" + 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) @@ -43,7 +43,9 @@ while True: try: main() print("winnow run complete", flush=True) - except Exception as e: + except KeyboardInterrupt: + raise + except BaseException 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) diff --git a/winnow/embeddings.py b/winnow/embeddings.py index e5845fd..16df985 100644 --- a/winnow/embeddings.py +++ b/winnow/embeddings.py @@ -287,30 +287,31 @@ def get_embedding( use_cache = Config.ENABLE_CACHE and asset_id is not None cache = get_cache(Config.CACHE_DIR) if use_cache else None - model_key = "immich" if entity_type == "face" else "siglip" + # Use a single consistent cache key per model so lookups and stores always match. + # "immich" was previously used as the face key on the lookup path but "insightface" + # on the store path — meaning the cache was never hit for locally-computed embeddings. + cache_key = "insightface" if entity_type == "face" else "siglip" # 1. Use Immich embedding if provided if immich_embedding is not None: if cache: - cache.put(asset_id, immich_embedding, model_key) + cache.put(asset_id, immich_embedding, cache_key) return immich_embedding # 2. Check disk cache if cache: - cached = cache.get(asset_id, model_key) + cached = cache.get(asset_id, cache_key) if cached is not None: return cached # 3. Compute locally if entity_type == "face": emb = get_face_embedding(img_pil) - model_key = "insightface" else: emb = get_object_embedding(img_pil) - # Cache the result if emb is not None and cache: - cache.put(asset_id, emb, model_key) + cache.put(asset_id, emb, cache_key) return emb diff --git a/winnow/log_config.py b/winnow/log_config.py index e8378bc..fa75a29 100644 --- a/winnow/log_config.py +++ b/winnow/log_config.py @@ -26,10 +26,12 @@ def setup_logging(verbose: bool = False) -> logging.Logger: """Configure logging with Rich console and file output.""" level = logging.DEBUG if verbose else logging.INFO - # Configure root logger + # Configure root logger; close existing handlers before replacing them root = logging.getLogger() root.setLevel(level) - root.handlers.clear() + for h in root.handlers[:]: + h.close() + root.removeHandler(h) # Rich console handler - uses shared console to avoid breaking progress bars root.addHandler(RichHandler(rich_tracebacks=True, markup=True, console=console))