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)
    }