ResuMatch explores how AI can help rank resumes without skipping anyone.
Instead of auto-rejects, every applicant is parsed, scored, ranked — and explained.
Not an ATS: No silent filters. Everyone gets a score with visible rationale.
- What it is: A lightweight Flask app that parses resumes + a JD, then ranks candidates.
- How it scores: A multi-factor model combining:
- Semantic similarity (Sentence Transformers embeddings)
- TF-IDF coverage (skills/keywords present)
- Optional heuristics (e.g., experience indicators)
- Why it’s different: Transparency. Each ranking includes why it ranked that way.
Most ATS (Applicant Tracking Systems):
- Auto-reject candidates if certain keywords are missing.
- Hide applicants from recruiters if they don’t match a predefined filter.
- Often act like a black box — candidates never know why they were skipped.
ResuMatch, by contrast:
- Never auto-rejects anyone — every resume is parsed and scored.
- Every candidate is ranked, not hidden.
- Transparency first: each score comes with an explanation breakdown (semantic similarity, TF-IDF coverage, heuristic signals).
- Built for fairness and insight, not filtering.
The goal is to augment recruiters, not replace human judgment.
- Parse PDF/DOCX resumes and a job description.
- Build vector embeddings for semantic comparison.
- Compute TF-IDF coverage over required terms/skills.
- Combine into a multi-factor score (tunable weights).
- Rank candidates and output explanation notes.
- Python · Flask
- Sentence Transformers (embeddings)
- scikit-learn (TF-IDF, metrics)
- PyPDF2 / python-docx (parsing)
ResuMatch/ ├─ main.py # Flask entry + endpoints ├─ requirements.txt # Dependencies (CPU-friendly, numpy<2) ├─ utils/ # (If present) parsing + scoring helpers ├─ templates/, static/ # (If present) minimal UI └─ README.md
# Pseudocode for the core scoring
sem = cosine_sim(emb(job_desc), emb(resume_text))
tfidf_score = tfidf_coverage(resume_text, required_terms)
heur = simple_heuristics(resume_text) # e.g., mentions of tools/years
score = 0.6 * sem + 0.35 * tfidf_score + 0.05 * heur
explanation = {
"semantic_similarity": round(sem, 3),
"tfidf_coverage": round(tfidf_score, 3),
"signals": heur.details
}