fix: address 5 code review findings (round 8)

- diversity: fix hard_count regression from round 7 — revert to
  'is not None and < 0.85' so only images that actually receive a
  FPS boost (confirmed low confidence) are counted as hard examples;
  None-confidence images use conf_array=1.0 (no boost) and should
  not appear in the hard-example log count
- diversity: fix _scale_bbox_to_thumbnail to use explicit zero-guard
  for imageWidth/imageHeight (meta_w or 0; scale = img_w/meta_w if
  meta_w else 1.0) — mirrors image_processing.py pattern; prevents
  `or img_w` from silently treating imageWidth=0 as missing and
  returning scale=1.0 without surfacing the zero-metadata case
- embeddings: wrap all three os.close calls in _suppress_output
  finally block with try/except OSError: pass so a failed close
  in one branch cannot abort the outer finally and leak devnull_fd
  or the saved_err/saved_out fds
- upload_tracker: clear corrupt flat-list key (data[flat_key] = [])
  after the isinstance warning instead of leaving the corrupt value
  in place — prevents stale IDs persisting across reset_person calls
  and future load_uploaded_ids() from seeing a non-list value
- executor: move 'if pre_fscore is not None: person_has_fscores = True'
  out of the try/except else branch so it fires even when mark_uploaded
  raises; Frigate scores exist once measured regardless of tracker
  write success, and replacement strategy should reflect that
This commit is contained in:
2026-06-16 23:24:11 +00:00
parent 7282c76b68
commit 461ceb7af4
4 changed files with 22 additions and 11 deletions
+6 -4
View File
@@ -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)
+12 -3
View File
@@ -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
+2 -3
View File
@@ -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
+2 -1
View File
@@ -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)