Source code for lalandre_rag.scoring
"""Shared score helpers and source score contract."""
import math
from typing import Any, Dict
SCORE_SCALE_NORMALIZED_0_1 = "normalized_0_1"
SCORE_SCALE_BINARY_EVIDENCE = "binary_evidence"
SCORE_KIND_RELEVANCE = "relevance"
SCORE_KIND_EVIDENCE = "evidence"
[docs]
def coerce_finite_float(value: Any) -> float | None:
"""Return a finite float when possible, otherwise ``None``."""
try:
result = float(value)
except (TypeError, ValueError):
return None
if not math.isfinite(result):
return None
return result
[docs]
def clamp_unit_interval(value: Any, *, default: float = 0.0) -> float:
"""Clamp a value to the normalized 0..1 range."""
result = coerce_finite_float(value)
if result is None:
return default
return max(0.0, min(1.0, result))
[docs]
def non_negative(value: Any, *, default: float = 0.0) -> float:
"""Clamp a value to the non-negative range."""
result = coerce_finite_float(value)
if result is None:
return default
return max(0.0, result)
[docs]
def normalize_by_max(value: Any, max_value: Any, *, default: float = 0.0) -> float:
"""Normalize a non-negative value by a positive maximum."""
denominator = non_negative(max_value, default=1.0)
if denominator <= 0.0:
return default
return clamp_unit_interval(non_negative(value) / denominator, default=default)
[docs]
def round_score(value: Any, digits: int = 4) -> float:
"""Round a finite score after clamping it to a numeric value."""
result = coerce_finite_float(value)
if result is None:
return 0.0
return round(result, digits)
[docs]
def build_relevance_score_payload(
score: Any,
*,
rank_score: Any | None = None,
) -> Dict[str, Any]:
"""Build a normalized relevance score payload for user-facing sources."""
normalized_score = clamp_unit_interval(score)
normalized_rank = normalized_score if rank_score is None else clamp_unit_interval(rank_score)
return {
"score": normalized_score,
"rank_score": normalized_rank,
"score_kind": SCORE_KIND_RELEVANCE,
"score_scale": SCORE_SCALE_NORMALIZED_0_1,
}
[docs]
def build_evidence_score_payload() -> Dict[str, str]:
"""Build a payload for tangible but non-scored evidence."""
return {
"score_kind": SCORE_KIND_EVIDENCE,
"score_scale": SCORE_SCALE_BINARY_EVIDENCE,
}