redrob-ranker / src /features.py
Dhruv Goyal
Redrob ranker demo - full hybrid bge-small (Docker/Streamlit)
e0a3391
Raw
History Blame Contribute Delete
5.12 kB
"""
Shared feature extraction - term matching used by the trap gate, the scorer and
the reasoning generator so all three read the profile the same way.
"""
from __future__ import annotations
import re
from typing import Dict, List, Set
from . import config
def _term_pattern(term: str) -> str:
"""Word-boundary regex for one term. Short/ambiguous tokens (<=3 chars, e.g.
'rag', 'ner', 'nlp', 'llm', 'e5') require both-side boundaries so they match
real tokens, not substrings inside words like 'average' or 'owner'. Longer
terms use a left boundary + prefix so morphological variants match
(rank/ranking/ranked, embedding/embeddings, retrieval)."""
esc = re.escape(term.strip())
if len(term.strip()) <= 3:
return r"\b" + esc + r"\b"
left = r"\b" if term[0].isalnum() else ""
return left + esc
def _compile_group(terms: List[str]) -> "re.Pattern":
return re.compile("|".join(_term_pattern(t) for t in terms), re.IGNORECASE)
# Precompile once at import.
_EVIDENCE_PATTERNS = {g: _compile_group(t) for g, t in config.EVIDENCE_TERMS.items()}
_NICE_PATTERN = _compile_group(config.NICE_TO_HAVE_TERMS)
def _any_term(text: str, terms: List[str]) -> bool:
return any(t in text for t in terms)
def title_class(rec: dict) -> str:
"""Classify the current title: 'relevant' | 'adjacent' | 'nontech' |
'offdomain' | 'other'. Order matters: relevant wins over adjacent."""
t = rec["title_lower"]
if _any_term(t, config.RELEVANT_TITLE_TERMS):
return "relevant"
if _any_term(t, config.OFFDOMAIN_TITLE_TERMS):
return "offdomain"
if _any_term(t, config.NONTECH_TITLE_TERMS):
return "nontech"
if _any_term(t, config.ADJACENT_TITLE_TERMS):
return "adjacent"
return "other"
def evidence_groups(rec: dict) -> Dict[str, int]:
"""Count evidence hits per group across career descriptions + headline +
summary (the *work narrative*), NOT the bare skills list. This is the
'outcome evidence, not vocabulary' read that catches plain-language Tier-5s
and ignores keyword stuffing in the skills array."""
# Narrative text = headline + summary + every role description.
work_text = " ".join(
[rec["headline"].lower(), rec["summary"].lower()]
+ [c["description_lower"] for c in rec["career"]]
+ [c["title_lower"] for c in rec["career"]]
)
out: Dict[str, int] = {}
for group, pat in _EVIDENCE_PATTERNS.items():
out[group] = len(pat.findall(work_text))
return out
def skill_evidence_groups(rec: dict) -> Set[str]:
"""Evidence groups that appear as *genuinely assessed* skills - an AI/IR skill
with a real Redrob assessment score >= 60. Self-reported duration alone does
NOT count as backing (stuffers fake duration); the platform assessment is the
trustworthy signal per redrob_signals_doc."""
backed: Set[str] = set()
for s in rec["skills"]:
if s["assessment"] is None or s["assessment"] < 60:
continue
nm = s["name_lower"]
for group, pat in _EVIDENCE_PATTERNS.items():
if pat.search(nm):
backed.add(group)
return backed
def _any_skill_is_ai(skill: dict) -> bool:
"""True if a single skill entry names an AI/ML/IR skill."""
return any(pat.search(skill["name_lower"]) for pat in _EVIDENCE_PATTERNS.values())
def ai_skill_count(rec: dict) -> int:
"""Number of distinct AI/ML/IR-flavoured skills listed (any group)."""
n = 0
for s in rec["skills"]:
nm = s["name_lower"]
if any(pat.search(nm) for pat in _EVIDENCE_PATTERNS.values()):
n += 1
return n
def consulting_only(rec: dict) -> bool:
"""True if every company in the career history is an IT-services/consulting
firm (JD explicit disqualifier) - and there is at least one job."""
if not rec["companies"]:
return False
def is_consult(c):
return any(f in c for f in config.CONSULTING_FIRMS)
return all(is_consult(c) for c in rec["companies"])
def location_class(rec: dict) -> str:
loc = rec["location_lower"]
if _any_term(loc, config.PREFERRED_LOCATIONS):
return "preferred"
if _any_term(loc, config.WELCOME_LOCATIONS):
return "welcome"
return "far"
def has_relevant_or_adjacent_role(rec: dict) -> bool:
"""True if any role in the career history (or the current title) is a
relevant or adjacent technical title - i.e. the person has actually held an
ML/SWE-type role at some point, not just listed skills."""
titles = [rec["title_lower"]] + [c["title_lower"] for c in rec["career"]]
for t in titles:
if _any_term(t, config.RELEVANT_TITLE_TERMS) or _any_term(t, config.ADJACENT_TITLE_TERMS):
return True
return False
def is_title_hopper(rec: dict) -> bool:
"""JD: switching companies every ~1.5y chasing titles. Flag short average
tenure across several completed jobs."""
completed = [c for c in rec["career"] if not c["is_current"] and c["months"] > 0]
return len(completed) >= 3 and rec["avg_tenure_months"] < 18