chore: bump version to 0.4.0, update changelog and all docs
Finalizes the 0.4.0 release: - Version bumped to 0.4.0 in pyproject.toml - CHANGELOG.md: add [0.4.0] section covering Frigate pre-upload scoring, quality replacement inversion, bootstrap fix, FRIGATE_SCORE_CEILING, ENABLE_FRIGATE_SCORES, removal of post-upload quality gate, and all doc/default corrections - README.md: step 8 updated for dual-mode replacement, FRIGATE_SCORE_CEILING and ENABLE_FRIGATE_SCORES added to env var table, MIN_FACE_WIDTH and BLUR_THRESHOLD defaults corrected (50→90, 100→120) - .env.example: FRIGATE_SCORE_THRESHOLD replaced with FRIGATE_SCORE_CEILING; QUALITY_REPLACEMENT line added; comments updated to match current semantics - winnow/executor.py: bootstrap fix — recognize now called for all below-cap uploads when ENABLE_FRIGATE_SCORES=true (was gated on CEILING > 0) - winnow/upload_tracker.py: frigate_scores schema comment corrected to pre-upload; get_most_redundant_mapped_file() added - winnow/frigate_api.py: recognize_face returns (face_name, score)|None tuple so wrong-person scores never drive replacement or ceiling decisions - winnow/config.py: FRIGATE_SCORE_THRESHOLD renamed to FRIGATE_SCORE_CEILING; ENABLE_FRIGATE_SCORES added - tests/test_upload_tracker.py: 4 new tests for get_most_redundant_mapped_file Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -218,3 +218,45 @@ def test_get_lowest_quality_exclude_all_returns_none():
|
||||
mark_uploaded("asset-a", person_name="Alice", score=0.50)
|
||||
record_frigate_file("Alice", "Alice-a.webp", "asset-a")
|
||||
assert get_lowest_quality_mapped_file("Alice", exclude={"Alice-a.webp"}) is None
|
||||
|
||||
|
||||
# ── get_most_redundant_mapped_file ────────────────────────────────────────────
|
||||
|
||||
def test_get_most_redundant_none_when_no_frigate_scores():
|
||||
from winnow.upload_tracker import get_most_redundant_mapped_file, mark_uploaded, record_frigate_file
|
||||
mark_uploaded("asset-a", person_name="Alice", score=0.80)
|
||||
record_frigate_file("Alice", "Alice-a.webp", "asset-a")
|
||||
# blur score only, no frigate_score → no candidates
|
||||
assert get_most_redundant_mapped_file("Alice") is None
|
||||
|
||||
|
||||
def test_get_most_redundant_returns_highest_frigate_score():
|
||||
from winnow.upload_tracker import get_most_redundant_mapped_file, mark_uploaded, record_frigate_file
|
||||
mark_uploaded("asset-novel", person_name="Alice", score=0.50, frigate_score=0.31)
|
||||
mark_uploaded("asset-redundant", person_name="Alice", score=0.90, frigate_score=0.88)
|
||||
record_frigate_file("Alice", "Alice-novel.webp", "asset-novel")
|
||||
record_frigate_file("Alice", "Alice-redundant.webp", "asset-redundant")
|
||||
result = get_most_redundant_mapped_file("Alice")
|
||||
assert result is not None
|
||||
frigate_filename, asset_id, score = result
|
||||
assert frigate_filename == "Alice-redundant.webp"
|
||||
assert asset_id == "asset-redundant"
|
||||
assert score == pytest.approx(0.88, abs=0.001)
|
||||
|
||||
|
||||
def test_get_most_redundant_exclude_skips_file():
|
||||
from winnow.upload_tracker import get_most_redundant_mapped_file, mark_uploaded, record_frigate_file
|
||||
mark_uploaded("asset-hi", person_name="Alice", score=0.9, frigate_score=0.85)
|
||||
mark_uploaded("asset-lo", person_name="Alice", score=0.5, frigate_score=0.40)
|
||||
record_frigate_file("Alice", "Alice-hi.webp", "asset-hi")
|
||||
record_frigate_file("Alice", "Alice-lo.webp", "asset-lo")
|
||||
result = get_most_redundant_mapped_file("Alice", exclude={"Alice-hi.webp"})
|
||||
assert result is not None
|
||||
assert result[1] == "asset-lo" # hi excluded; lo is next highest
|
||||
|
||||
|
||||
def test_get_most_redundant_exclude_all_returns_none():
|
||||
from winnow.upload_tracker import get_most_redundant_mapped_file, mark_uploaded, record_frigate_file
|
||||
mark_uploaded("asset-a", person_name="Alice", score=0.5, frigate_score=0.70)
|
||||
record_frigate_file("Alice", "Alice-a.webp", "asset-a")
|
||||
assert get_most_redundant_mapped_file("Alice", exclude={"Alice-a.webp"}) is None
|
||||
|
||||
Reference in New Issue
Block a user