redrob-ranker / src /matching /scorer.py
Venkat7123's picture
Deploy candidate ranker
37b0787
Raw
History Blame Contribute Delete
3.48 kB
from __future__ import annotations
from src.core.config import get_scoring_config
from src.core.models import MatchScores
from src.matching.confidence import compute_confidence
DIM_TO_ACTUAL: dict[str, str] = {
"skill_match": "skill_match",
"experience_match": "experience_match",
"education_match": "education_match",
"assessment_score": "cross_encoder_score",
"behavioral_signals": "behavioral_score",
"cultural_fit": "semantic_similarity",
}
DEFAULT_SLIDER_WEIGHTS: dict[str, float] = {
"skill_match": 0.25,
"experience_match": 0.20,
"education_match": 0.10,
"assessment_score": 0.15,
"behavioral_signals": 0.20,
"cultural_fit": 0.10,
}
# All known match-score dimension names that CandidateScorer can consume.
_ALL_DIMS = [
"semantic_similarity",
"keyword_match",
"skill_match",
"experience_match",
"location_match",
"education_match",
"cross_encoder_score",
"behavioral_score",
"career_trajectory_score",
"skill_proficiency_score",
"behavioral_signals",
"cultural_fit",
]
class CandidateScorer:
def __init__(self) -> None:
config = get_scoring_config()
self.weights = config["scoring_weights"]
self.slider_defaults = config.get("slider_weights", DEFAULT_SLIDER_WEIGHTS)
def compute_overall(
self,
scores: dict[str, float | None],
slider_weights: dict[str, float] | None = None,
) -> MatchScores:
total_weight = 0.0
weighted_sum = 0.0
components: dict[str, float | None] = {}
effective_weights: dict[str, float] = {}
if slider_weights:
for slider_dim, actual_dim in DIM_TO_ACTUAL.items():
if slider_dim in slider_weights and slider_weights[slider_dim] > 0:
effective_weights[actual_dim] = slider_weights[slider_dim] / 100.0
for dim, w in self.slider_defaults.items():
actual = DIM_TO_ACTUAL.get(dim, dim)
if actual not in effective_weights:
effective_weights[actual] = w
else:
effective_weights = dict(self.weights)
for dim in _ALL_DIMS:
score = scores.get(dim)
if score is not None:
weight = effective_weights.get(dim, 0.0)
total_weight += weight
weighted_sum += weight * score
components[dim] = score
overall = weighted_sum / total_weight if total_weight > 0 else 0.0
overall = max(0.0, min(1.0, overall))
confidence = compute_confidence({k: v for k, v in components.items() if v is not None})
return MatchScores(
overall=overall,
semantic_similarity=components.get("semantic_similarity", 0.0) or 0.0,
keyword_match=components.get("keyword_match", 0.0) or 0.0,
skill_match=components.get("skill_match", 0.0) or 0.0,
experience_match=components.get("experience_match", 0.0) or 0.0,
location_match=components.get("location_match"),
education_match=components.get("education_match"),
cross_encoder_score=components.get("cross_encoder_score"),
behavioral_score=components.get("behavioral_score"),
career_trajectory_score=components.get("career_trajectory_score"),
skill_proficiency_score=components.get("skill_proficiency_score"),
confidence=confidence,
)