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:
+6
-4
@@ -195,9 +195,10 @@ def _scale_bbox_to_thumbnail(
|
|||||||
continue
|
continue
|
||||||
faces = person.get("faces", [])
|
faces = person.get("faces", [])
|
||||||
if faces:
|
if faces:
|
||||||
meta_w = faces[0].get("imageWidth") or img_w
|
meta_w = faces[0].get("imageWidth") or 0
|
||||||
meta_h = faces[0].get("imageHeight") or img_h
|
meta_h = faces[0].get("imageHeight") or 0
|
||||||
scale_x, scale_y = img_w / meta_w, img_h / meta_h
|
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 (x1 * scale_x, y1 * scale_y, x2 * scale_x, y2 * scale_y)
|
||||||
return bbox
|
return bbox
|
||||||
|
|
||||||
@@ -587,7 +588,8 @@ def _cluster_aware_selection(
|
|||||||
1 for i in selected
|
1 for i in selected
|
||||||
if confidence_scores
|
if confidence_scores
|
||||||
and i < len(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)
|
logger.info("Selection complete: %s images (%s hard examples with confidence < 0.85).", len(selected), hard_count)
|
||||||
|
|
||||||
|
|||||||
+12
-3
@@ -43,16 +43,25 @@ def _suppress_output():
|
|||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
os.close(saved_out)
|
try:
|
||||||
|
os.close(saved_out)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
if saved_err is not None:
|
if saved_err is not None:
|
||||||
try:
|
try:
|
||||||
os.dup2(saved_err, 2)
|
os.dup2(saved_err, 2)
|
||||||
except OSError:
|
except OSError:
|
||||||
pass
|
pass
|
||||||
finally:
|
finally:
|
||||||
os.close(saved_err)
|
try:
|
||||||
|
os.close(saved_err)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
if devnull_fd is not None:
|
if devnull_fd is not None:
|
||||||
os.close(devnull_fd)
|
try:
|
||||||
|
os.close(devnull_fd)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
# Lazy-loaded singleton
|
# Lazy-loaded singleton
|
||||||
|
|||||||
+2
-3
@@ -534,9 +534,8 @@ def upload_to_frigate(jobs: list[dict]) -> None:
|
|||||||
" but asset may be re-selected next run: %s",
|
" but asset may be re-selected next run: %s",
|
||||||
fname, tracker_exc,
|
fname, tracker_exc,
|
||||||
)
|
)
|
||||||
else:
|
if pre_fscore is not None:
|
||||||
if pre_fscore is not None:
|
person_has_fscores = True
|
||||||
person_has_fscores = True
|
|
||||||
# Always record for reconcile so the Frigate filename→asset_id
|
# Always record for reconcile so the Frigate filename→asset_id
|
||||||
# mapping is created even when the tracker write fails.
|
# mapping is created even when the tracker write fails.
|
||||||
# Trade-off: if mark_uploaded failed, asset_id is absent from
|
# Trade-off: if mark_uploaded failed, asset_id is absent from
|
||||||
|
|||||||
@@ -444,9 +444,10 @@ def reset_person(person_name: str) -> None:
|
|||||||
person_ids = set(_get_ids(tracker_entry))
|
person_ids = set(_get_ids(tracker_entry))
|
||||||
if person_ids and flat_key in data and not isinstance(data[flat_key], list):
|
if person_ids and flat_key in data and not isinstance(data[flat_key], list):
|
||||||
logger.warning(
|
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__,
|
filename, flat_key, type(data[flat_key]).__name__,
|
||||||
)
|
)
|
||||||
|
data[flat_key] = []
|
||||||
elif person_ids and flat_key in data:
|
elif person_ids and flat_key in data:
|
||||||
data[flat_key] = sorted(set(data[flat_key]) - person_ids)
|
data[flat_key] = sorted(set(data[flat_key]) - person_ids)
|
||||||
_save(filename, data)
|
_save(filename, data)
|
||||||
|
|||||||
Reference in New Issue
Block a user