refactor: confidence should always have a value
This commit is contained in:
+19
-16
@@ -127,15 +127,13 @@ class CacheEngine:
|
|||||||
f"[{status_str}, ttl={remaining}s]"
|
f"[{status_str}, ttl={remaining}s]"
|
||||||
)
|
)
|
||||||
status = CacheStatus(status_str)
|
status = CacheStatus(status_str)
|
||||||
if confidence is None and status in (
|
if confidence is None:
|
||||||
CacheStatus.SUCCESS_SYNCED,
|
if status == CacheStatus.SUCCESS_SYNCED:
|
||||||
CacheStatus.SUCCESS_UNSYNCED,
|
confidence = LEGACY_CONFIDENCE_SYNCED
|
||||||
):
|
elif status == CacheStatus.SUCCESS_UNSYNCED:
|
||||||
confidence = (
|
confidence = LEGACY_CONFIDENCE_UNSYNCED
|
||||||
LEGACY_CONFIDENCE_SYNCED
|
else:
|
||||||
if status == CacheStatus.SUCCESS_SYNCED
|
confidence = 100.0 # negative statuses: value irrelevant
|
||||||
else LEGACY_CONFIDENCE_UNSYNCED
|
|
||||||
)
|
|
||||||
|
|
||||||
return LyricResult(
|
return LyricResult(
|
||||||
status=status,
|
status=status,
|
||||||
@@ -163,12 +161,13 @@ class CacheEngine:
|
|||||||
continue
|
continue
|
||||||
if best is None:
|
if best is None:
|
||||||
best = cached
|
best = cached
|
||||||
else:
|
elif cached.confidence > best.confidence:
|
||||||
cached_conf = (
|
best = cached
|
||||||
cached.confidence if cached.confidence is not None else 100.0
|
elif (
|
||||||
)
|
cached.confidence == best.confidence
|
||||||
best_conf = best.confidence if best.confidence is not None else 100.0
|
and cached.status == CacheStatus.SUCCESS_SYNCED
|
||||||
if cached_conf > best_conf:
|
and best.status != CacheStatus.SUCCESS_SYNCED
|
||||||
|
):
|
||||||
best = cached
|
best = cached
|
||||||
return best
|
return best
|
||||||
|
|
||||||
@@ -298,12 +297,15 @@ class CacheEngine:
|
|||||||
f"SELECT status, lyrics, source, confidence FROM cache WHERE {where} "
|
f"SELECT status, lyrics, source, confidence FROM cache WHERE {where} "
|
||||||
"ORDER BY COALESCE(confidence, "
|
"ORDER BY COALESCE(confidence, "
|
||||||
" CASE status WHEN ? THEN ? ELSE ? END"
|
" CASE status WHEN ? THEN ? ELSE ? END"
|
||||||
") DESC, created_at DESC LIMIT 1",
|
") DESC, "
|
||||||
|
"CASE status WHEN ? THEN 0 ELSE 1 END, "
|
||||||
|
"created_at DESC LIMIT 1",
|
||||||
params
|
params
|
||||||
+ [
|
+ [
|
||||||
CacheStatus.SUCCESS_SYNCED.value,
|
CacheStatus.SUCCESS_SYNCED.value,
|
||||||
LEGACY_CONFIDENCE_SYNCED,
|
LEGACY_CONFIDENCE_SYNCED,
|
||||||
LEGACY_CONFIDENCE_UNSYNCED,
|
LEGACY_CONFIDENCE_UNSYNCED,
|
||||||
|
CacheStatus.SUCCESS_SYNCED.value,
|
||||||
],
|
],
|
||||||
).fetchall()
|
).fetchall()
|
||||||
|
|
||||||
@@ -389,6 +391,7 @@ class CacheEngine:
|
|||||||
key=lambda x: (
|
key=lambda x: (
|
||||||
x[0],
|
x[0],
|
||||||
-(x[1].get("confidence") or 0),
|
-(x[1].get("confidence") or 0),
|
||||||
|
x[1].get("status") != CacheStatus.SUCCESS_SYNCED.value,
|
||||||
-(x[1].get("created_at") or 0),
|
-(x[1].get("created_at") or 0),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -453,6 +453,8 @@ def _print_cache_row(row: dict, indent: str = "") -> None:
|
|||||||
print(f"{indent} Lyrics : {line_count} lines")
|
print(f"{indent} Lyrics : {line_count} lines")
|
||||||
if confidence is not None:
|
if confidence is not None:
|
||||||
print(f"{indent} Confidence: {confidence:.0f}")
|
print(f"{indent} Confidence: {confidence:.0f}")
|
||||||
|
else:
|
||||||
|
print(f"{indent} Confidence: (legacy)")
|
||||||
|
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
|
|||||||
+12
-18
@@ -40,15 +40,14 @@ _STATUS_TTL: dict[CacheStatus, Optional[int]] = {
|
|||||||
|
|
||||||
|
|
||||||
def _is_better(new: LyricResult, old: LyricResult) -> bool:
|
def _is_better(new: LyricResult, old: LyricResult) -> bool:
|
||||||
"""Compare two results by confidence only.
|
"""Compare two results: higher confidence wins; synced breaks ties."""
|
||||||
|
if new.confidence != old.confidence:
|
||||||
Synced/unsynced preference is already baked into the confidence score
|
return new.confidence > old.confidence
|
||||||
(synced bonus in scoring weights), so we don't need a separate tier.
|
# Equal confidence — prefer synced as tiebreaker
|
||||||
None confidence = trusted = 100.
|
return (
|
||||||
"""
|
new.status == CacheStatus.SUCCESS_SYNCED
|
||||||
new_conf = new.confidence if new.confidence is not None else 100.0
|
and old.status != CacheStatus.SUCCESS_SYNCED
|
||||||
old_conf = old.confidence if old.confidence is not None else 100.0
|
)
|
||||||
return new_conf > old_conf
|
|
||||||
|
|
||||||
|
|
||||||
class LrcManager:
|
class LrcManager:
|
||||||
@@ -121,13 +120,10 @@ class LrcManager:
|
|||||||
# Positive cache hit — apply the same confidence evaluation
|
# Positive cache hit — apply the same confidence evaluation
|
||||||
# as fresh fetches so that low-confidence cached results
|
# as fresh fetches so that low-confidence cached results
|
||||||
# don't block better results from later fetchers.
|
# don't block better results from later fetchers.
|
||||||
is_trusted = (
|
is_trusted = cached.confidence >= HIGH_CONFIDENCE
|
||||||
cached.confidence is None
|
|
||||||
or cached.confidence >= HIGH_CONFIDENCE
|
|
||||||
)
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[{source}] cache hit: {cached.status.value}"
|
f"[{source}] cache hit: {cached.status.value}"
|
||||||
f" (confidence={'trusted' if cached.confidence is None else f'{cached.confidence:.0f}'})"
|
f" (confidence={cached.confidence:.0f})"
|
||||||
)
|
)
|
||||||
if cached.status == CacheStatus.SUCCESS_SYNCED and is_trusted:
|
if cached.status == CacheStatus.SUCCESS_SYNCED and is_trusted:
|
||||||
return cached
|
return cached
|
||||||
@@ -155,12 +151,10 @@ class LrcManager:
|
|||||||
CacheStatus.SUCCESS_SYNCED,
|
CacheStatus.SUCCESS_SYNCED,
|
||||||
CacheStatus.SUCCESS_UNSYNCED,
|
CacheStatus.SUCCESS_UNSYNCED,
|
||||||
):
|
):
|
||||||
is_trusted = (
|
is_trusted = result.confidence >= HIGH_CONFIDENCE
|
||||||
result.confidence is None or result.confidence >= HIGH_CONFIDENCE
|
|
||||||
)
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"[{source}] got {result.status.value} lyrics"
|
f"[{source}] got {result.status.value} lyrics"
|
||||||
f" (confidence={'trusted' if result.confidence is None else f'{result.confidence:.0f}'})"
|
f" (confidence={result.confidence:.0f})"
|
||||||
)
|
)
|
||||||
# Trusted synced → return immediately
|
# Trusted synced → return immediately
|
||||||
if result.status == CacheStatus.SUCCESS_SYNCED and is_trusted:
|
if result.status == CacheStatus.SUCCESS_SYNCED and is_trusted:
|
||||||
|
|||||||
+1
-3
@@ -62,6 +62,4 @@ class LyricResult:
|
|||||||
lyrics: Optional[LRCData] = None
|
lyrics: Optional[LRCData] = None
|
||||||
source: Optional[str] = None # Which fetcher produced this result
|
source: Optional[str] = None # Which fetcher produced this result
|
||||||
ttl: Optional[int] = None # Hint for cache TTL (seconds)
|
ttl: Optional[int] = None # Hint for cache TTL (seconds)
|
||||||
confidence: Optional[float] = (
|
confidence: float = 100.0 # 0-100 selection confidence (100 = trusted/exact)
|
||||||
None # 0-100 selection confidence (None = exact/trusted)
|
|
||||||
)
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "lrx-cli"
|
name = "lrx-cli"
|
||||||
version = "0.2.1"
|
version = "0.3.0"
|
||||||
description = "Fetch line-synced lyrics for your music player."
|
description = "Fetch line-synced lyrics for your music player."
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.13"
|
requires-python = ">=3.13"
|
||||||
|
|||||||
Reference in New Issue
Block a user