Spaces:
Sleeping
Sleeping
File size: 2,012 Bytes
6817686 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | import numpy as np
from config import match_config, TECH_SKILLS
from core.logger import get_logger
from src.embedder import embed_text
logger = get_logger(__name__)
def cosine_similarity(vec_a: np.ndarray, vec_b: np.ndarray) -> float:
norm_a = np.linalg.norm(vec_a)
norm_b = np.linalg.norm(vec_b)
if norm_a == 0 or norm_b == 0:
logger.warning(f"Zero vector detected - returning 0 similarity")
return 0.0
similarity = np.dot(vec_a, vec_b)/ (norm_a * norm_b)
return float(np.clip(similarity, -1.0, 1.0))
def extract_skills(text: str) -> set:
text_lower = text.lower()
return {
skill for skill in TECH_SKILLS if skill in text_lower
}
def get_verdict(score: float) -> str:
if score >= 0.85:
return "Strong Match"
elif score >= 0.70:
return "Good Match"
elif score >= 0.50:
return "Weak Match"
else:
return "Poor Match"
def compute_match(resume_text:str, jd_text:str) -> dict:
logger.info(
f"Computing match: "
f"resume={len(resume_text)} chars, "
f"jd={len(jd_text)} chars"
)
resume_embbed = embed_text(resume_text)
jd_embbed = embed_text(jd_text)
similarity_score = cosine_similarity(resume_embbed, jd_embbed)
verdict = get_verdict(similarity_score)
resume_skills = extract_skills(resume_text)
jd_skills = extract_skills(jd_text)
matched = resume_skills & jd_skills
missing_skills = jd_skills - resume_skills
logger.info(
f"Match complete: score={similarity_score:.3f} "
f"verdict={verdict} "
f"matched={len(matched)} "
f"missing={len(missing_skills)}"
)
return {
"match_score": similarity_score,
"match_percentage": round(similarity_score * 100, 1),
"match_skills": sorted(list(matched)),
"missing_skills": sorted(list(missing_skills)),
"verdict": verdict,
"resume_ength": len(resume_text),
"jd_length": len(jd_text)
}
|