feat: add candidate ranker with confidence gate
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
from dataclasses import replace
|
||||
|
||||
from lyra_worker.confidence import score_confidence
|
||||
from lyra_worker.quality import rank_key
|
||||
from lyra_worker.types import Candidate, MBTarget
|
||||
|
||||
|
||||
def rank_candidates(
|
||||
target: MBTarget, candidates: list[Candidate], min_confidence: float = 0.7
|
||||
) -> list[Candidate]:
|
||||
"""Score, gate by confidence, and sort best-first (quality, then confidence)."""
|
||||
scored = [replace(c, confidence=score_confidence(target, c)) for c in candidates]
|
||||
kept = [c for c in scored if c.confidence >= min_confidence]
|
||||
kept.sort(key=lambda c: (rank_key(c), c.confidence), reverse=True)
|
||||
return kept
|
||||
@@ -0,0 +1,42 @@
|
||||
from lyra_worker.ranker import rank_candidates
|
||||
from lyra_worker.types import Candidate, MBTarget, Quality
|
||||
|
||||
HIRES = Quality(fmt="FLAC", lossless=True, bit_depth=24, sample_rate=96000)
|
||||
CD = Quality(fmt="FLAC", lossless=True, bit_depth=16, sample_rate=44100)
|
||||
MP3 = Quality(fmt="MP3", lossless=False, bitrate_kbps=320)
|
||||
TARGET = MBTarget(artist="Radiohead", album="In Rainbows", track_count=10)
|
||||
|
||||
|
||||
def _cand(source, quality, artist="Radiohead", album="In Rainbows", tracks=10):
|
||||
return Candidate(source=source, source_ref=f"{source}:{quality.fmt}",
|
||||
matched_artist=artist, matched_album=album,
|
||||
quality=quality, track_count=tracks)
|
||||
|
||||
|
||||
def test_returns_empty_for_no_candidates():
|
||||
assert rank_candidates(TARGET, []) == []
|
||||
|
||||
|
||||
def test_best_quality_wins_among_correct_matches():
|
||||
ranked = rank_candidates(TARGET, [
|
||||
_cand("youtube", MP3),
|
||||
_cand("qobuz", HIRES),
|
||||
_cand("soulseek", CD),
|
||||
])
|
||||
assert [c.source for c in ranked] == ["qobuz", "soulseek", "youtube"]
|
||||
assert all(c.confidence > 0.9 for c in ranked)
|
||||
|
||||
|
||||
def test_confidence_gate_drops_wrong_album_even_if_higher_quality():
|
||||
ranked = rank_candidates(TARGET, [
|
||||
_cand("qobuz", HIRES, album="OK Computer", tracks=12), # wrong release, hi-res
|
||||
_cand("soulseek", CD), # correct, lossless
|
||||
])
|
||||
assert [c.source for c in ranked] == ["soulseek"]
|
||||
|
||||
|
||||
def test_all_below_threshold_returns_empty():
|
||||
ranked = rank_candidates(TARGET, [
|
||||
_cand("qobuz", HIRES, artist="Nirvana", album="Nevermind"),
|
||||
])
|
||||
assert ranked == []
|
||||
Reference in New Issue
Block a user