An NLP-based tool that compares a resume against a job description and reports a match score, a resume/JD skill breakdown, and basic text stats — built as a college NLP project.
- Upload a resume as PDF or DOCX
- Paste any job description
- Get a TF-IDF + cosine similarity match score (0–100%)
- Skill extraction using a curated skill list matched with spaCy's
PhraseMatcher(handles multi-word terms likescikit-learn,machine learning) - Breakdown of matched, missing, and extra skills between resume and JD
- Simple web UI built with Streamlit
Resume file (PDF/DOCX)
│
▼
Text extraction (pdfplumber / python-docx)
│
▼
Preprocessing (spaCy: lowercase, tokenize, remove stopwords, lemmatize)
│
▼
TF-IDF vectorization + cosine similarity ──▶ Match score
│
▼
Skill matching (spaCy PhraseMatcher on raw text) ──▶ Matched / Missing / Extra skills
Text extraction and skill matching happen on the raw text (so multi-word skill names aren't broken apart), while the match score is computed on the cleaned, lemmatized tokens (so different word forms of the same term count as equivalent).
resume_analyzer/
├── app.py # Streamlit web app
├── requirements.txt
├── data/ # sample test resumes
├── src/
│ ├── extractor.py # PDF/DOCX text extraction
│ ├── preprocessor.py # spaCy-based text cleaning
│ ├── scorer.py # TF-IDF + cosine similarity scoring
│ ├── skill_extractor.py # skill matching via PhraseMatcher
│ └── skills_data.py # curated skill list
git clone https://github.com/<your-username>/resume-analyzer.git
cd resume-analyzer
python3 -m pip install -r requirements.txt
python3 -m spacy download en_core_web_smpython3 -m streamlit run app.pyThen open the local URL Streamlit prints (usually http://localhost:8501).
| Purpose | Library |
|---|---|
| PDF text extraction | pdfplumber |
| DOCX text extraction | python-docx |
| Text preprocessing (tokenize, lemmatize, stopwords) | spaCy |
| Skill phrase matching | spaCy PhraseMatcher |
| Similarity scoring | scikit-learn (TfidfVectorizer, cosine_similarity) |
| Web UI | Streamlit |
| Score gauge chart | Plotly |
- TF-IDF is a bag-of-words method — it doesn't understand synonyms or paraphrasing (e.g., "built REST APIs" vs. "developed backend services" won't match well). A dense embedding model (e.g.,
sentence-transformers) would catch this but trades off interpretability. - Raw TF-IDF cosine similarity gets diluted on long, multi-topic resumes. A resume covering many unrelated projects/certifications can score a low overall text-similarity percentage against a short, focused JD, even when every required skill is genuinely present — because unrelated content dominates the resume's overall vector direction. This is why Skill Match % (not the TF-IDF score) is the primary metric shown in the UI — it directly measures "how many required skills does the resume have," which the TF-IDF score cannot reliably answer once documents differ a lot in length and topic breadth.
- General-purpose lemmatization mishandles tech vocabulary — e.g., "Pandas" (the library) can lemmatize to "panda" (the animal), and "data" to "datum". Skill matching avoids this entirely by matching on raw, unlemmatized text against a curated skill list.
- Skill detection is limited to a predefined list (
src/skills_data.py) — any skill not in that list won't be detected. ASKILL_ALIASESmap normalizes common variant forms (e.g.css3→css,oop→object oriented programming) so differently-worded resumes and JDs still match on the same underlying skill — but any skill/alias not yet added will still be missed. Expanding the list and alias map improves coverage. - PDF extraction quality depends on layout — complex multi-column resumes or scanned/image-only PDFs may extract text out of order or not at all.
- Swap/augment TF-IDF with sentence embeddings for semantic similarity
- Section detection (Education, Experience, Skills) for more structured feedback
- Resume "quality" checks (quantified achievements, action verbs)
- Expand the skill list or move it to an external JSON/CSV for easier maintenance