diff --git a/winnow/diversity.py b/winnow/diversity.py index 6961f56..7c308fb 100644 --- a/winnow/diversity.py +++ b/winnow/diversity.py @@ -195,9 +195,10 @@ def _scale_bbox_to_thumbnail( continue faces = person.get("faces", []) if faces: - meta_w = faces[0].get("imageWidth") or img_w - meta_h = faces[0].get("imageHeight") or img_h - scale_x, scale_y = img_w / meta_w, img_h / meta_h + meta_w = faces[0].get("imageWidth") or 0 + meta_h = faces[0].get("imageHeight") or 0 + scale_x = img_w / meta_w if meta_w else 1.0 + scale_y = img_h / meta_h if meta_h else 1.0 return (x1 * scale_x, y1 * scale_y, x2 * scale_x, y2 * scale_y) return bbox @@ -587,7 +588,8 @@ def _cluster_aware_selection( 1 for i in selected if confidence_scores and i < len(confidence_scores) - and (confidence_scores[i] is None or confidence_scores[i] < 0.85) + and confidence_scores[i] is not None + and confidence_scores[i] < 0.85 ) logger.info("Selection complete: %s images (%s hard examples with confidence < 0.85).", len(selected), hard_count) diff --git a/winnow/embeddings.py b/winnow/embeddings.py index 53f254e..1e84ed4 100644 --- a/winnow/embeddings.py +++ b/winnow/embeddings.py @@ -43,16 +43,25 @@ def _suppress_output(): except OSError: pass finally: - os.close(saved_out) + try: + os.close(saved_out) + except OSError: + pass if saved_err is not None: try: os.dup2(saved_err, 2) except OSError: pass finally: - os.close(saved_err) + try: + os.close(saved_err) + except OSError: + pass if devnull_fd is not None: - os.close(devnull_fd) + try: + os.close(devnull_fd) + except OSError: + pass # Lazy-loaded singleton diff --git a/winnow/executor.py b/winnow/executor.py index 52b7401..65114ad 100644 --- a/winnow/executor.py +++ b/winnow/executor.py @@ -534,9 +534,8 @@ def upload_to_frigate(jobs: list[dict]) -> None: " but asset may be re-selected next run: %s", fname, tracker_exc, ) - else: - if pre_fscore is not None: - person_has_fscores = True + if pre_fscore is not None: + person_has_fscores = True # Always record for reconcile so the Frigate filename→asset_id # mapping is created even when the tracker write fails. # Trade-off: if mark_uploaded failed, asset_id is absent from diff --git a/winnow/upload_tracker.py b/winnow/upload_tracker.py index 6997b6a..39e57a3 100644 --- a/winnow/upload_tracker.py +++ b/winnow/upload_tracker.py @@ -444,9 +444,10 @@ def reset_person(person_name: str) -> None: person_ids = set(_get_ids(tracker_entry)) if person_ids and flat_key in data and not isinstance(data[flat_key], list): logger.warning( - "reset_person: %s has unexpected type for %s (%s) — skipping flat-list cleanup", + "reset_person: %s has unexpected type for %s (%s) — clearing corrupt flat-list", filename, flat_key, type(data[flat_key]).__name__, ) + data[flat_key] = [] elif person_ids and flat_key in data: data[flat_key] = sorted(set(data[flat_key]) - person_ids) _save(filename, data)