Production-ready AI-powered ATS Resume Optimizer: upload resume and job description, get an optimized resume, ATS score, keyword analysis, and downloadable DOCX.
- Resume & JD upload: PDF, DOCX; optional paste for job description
- Job description analyzer: Google Gemini 1.5 Flash extracts required/preferred skills, keywords, tools, experience level (strict JSON)
- ATS optimizer: Rewrites resume with better action verbs and keyword alignment without fabricating experience
- ATS scoring: Keyword overlap %, TF-IDF cosine similarity, weighted final score (0β100%), missing/recommended keywords
- Skill Gap Analysis: Identifies matched vs missing required and preferred skills
- Resume Quality Score: Evaluates readability, formatting, content quality, and keyword density
- Keyword Heatmap: Visual analysis of top keywords and their importance
- Visual dashboard: Professional Matplotlib charts (keyword coverage, match vs missing, skill gap, quality breakdown)
- Download: DOCX export via python-docx
- Writing Feedback: Weak verb detection, metric detection, passive voice, readability score, section detection
- Professional UI: Modern SaaS-style interface with Tailwind CSS
- Backend: FastAPI (Python), Pydantic for data validation
- Frontend: React, TypeScript, Vite, Tailwind CSS
- LLM Integration: Google Gemini 1.5 Flash via
google-generativeai - Text Processing: pdfplumber (PDF), python-docx (DOCX)
- Analysis: scikit-learn (TF-IDF, cosine similarity)
- Visualization: Matplotlib (charts), NumPy
- Deployment-ready: Docker-compatible, serverless-compatible
This project was originally built with OpenAI's GPT-4 but was refactored to use Google Gemini 1.5 Flash for improved cost-efficiency and broader API availability.
- Abstracted LLM Interface - Services (
jd_analyzer,ats_optimizer,gemini_service) use consistent async patterns independent of provider - Drop-in Replacement - Minimal changes to response handling; Gemini returns same JSON structures
- Configuration-driven - Single
.envchange switches LLM provider (GOOGLE_API_KEY) - Provider-agnostic Models - Pydantic models work with any LLM returning JSON
- Error Handling - Graceful fallbacks prevent charts/visualizations from breaking on API errors
OpenAI Integration: Gemini Integration:
βββ openai import βββ google.generativeai import
βββ AsyncOpenAI client βββ genai.GenerativeModel()
βββ chat.completions.create() βββ model.generate_content()
βββ OPENAI_API_KEY env var βββ GOOGLE_API_KEY env var
- β Cost: Gemini 1.5 Flash significantly cheaper than GPT-4o
- β Performance: Fast inference times for resume processing
- β Reliability: Google's infrastructure + API consistency
- β Flexibility: Easy to swap providers with same codebase
ATS Scanner/
βββ backend/ # FastAPI Python backend
β βββ main.py # FastAPI app & routes
β βββ models.py # Pydantic models (request/response)
β βββ services/
β β βββ resume_parser.py # PDF/DOCX text extraction
β β βββ jd_analyzer.py # Gemini JD β structured JSON
β β βββ ats_optimizer.py # Gemini resume rewrite
β β βββ scorer.py # Keyword + TF-IDF scoring
β β βββ skill_analyzer.py # Skill gap analysis
β β βββ quality_scorer.py # Resume quality evaluation
β β βββ keyword_heatmap.py # Keyword frequency analysis
β β βββ doc_generator.py # DOCX generation
β β βββ visualizer.py # Matplotlib charts
β β βββ writing_feedback.py # Writing analysis
β β βββ gemini_service.py # Google Gemini API integration
β βββ utils/
β β βββ resume_parser.py # Shared parser utilities
β β βββ text_cleaner.py # Text normalization
β βββ requirements.txt
β
βββ frontend/ # React + Vite + TypeScript
β βββ src/
β β βββ App.tsx # Main app component (enhanced UI)
β β βββ main.tsx # Entry point
β β βββ types.ts # TypeScript interfaces
β β βββ index.css # Tailwind styles
β βββ package.json
β βββ tailwind.config.js
β βββ vite.config.ts
β
βββ .env.example # Environment template
βββ .env # Your configuration (create from template)
βββ README.md # This file
- Python 3.10+
- Node.js 16+ & npm
- Google Gemini API key (get one)
Clone/extract and enter the project directory:
cd "ATS Scanner"Copy the environment template:
cp .env.example .envEdit .env and add your Google Gemini API key:
GOOGLE_API_KEY=your-gemini-api-key-here
CHARTS_DIR=backend/chartsCreate and activate a virtual environment:
Windows (PowerShell):
python -m venv .venv
.\.venv\Scripts\Activate.ps1macOS/Linux:
python3 -m venv .venv
source .venv/bin/activateInstall dependencies:
pip install -r requirements.txtRun the backend:
uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000β Backend is running at http://localhost:8000
β API docs: http://localhost:8000/docs
In a new terminal, navigate to frontend:
cd frontend
npm install
npm run devβ Frontend is running at http://localhost:5173
- Open
http://localhost:5173in your browser - Upload a resume (PDF or DOCX)
- Provide a job description (paste or upload)
- Click "π Analyze Now"
- View results in the comprehensive dashboard:
- π Dashboard: Visual charts and metrics
- β¨ Optimized Resume: AI-enhanced resume text
- π― Skill Gap: Matched vs missing skills
- β Quality Score: Detailed quality breakdown
- π₯ Keywords: Keyword analysis and recommendations
- Download optimized resume as DOCX
POST /api/analyze/comprehensive
Request:
resume(File): PDF or DOCX resumejob_description(File, optional): PDF/DOCX JDjd_text(string, optional): Paste JD text
Response:
{
"optimized_resume": "...",
"ats_score": {
"final_ats_score": 78.5,
"keyword_match_percent": 82,
"semantic_similarity_score": 0.65,
"missing_keywords": [...],
"recommended_keywords_to_add": [...]
},
"jd_analysis": {
"required_skills": [...],
"preferred_skills": [...],
"keywords": [...],
"tools": [...],
"experience_level": "Senior"
},
"skill_gap": {
"matched_skills": [...],
"missing_skills": [...],
"gap_score": 75.0,
"match_count": 12,
"total_required": 18
},
"resume_quality": {
"overall_score": 82,
"readability_score": 85,
"formatting_score": 80,
"content_score": 85,
"keyword_density_score": 75,
"feedback": ["β Good readability...", ...]
},
"keyword_heatmap": {
"keywords": ["Python", "AWS", ...],
"frequencies": [5, 3, ...],
"importance_scores": [0.95, 0.72, ...]
},
"writing_feedback": {
"weak_verbs_detected": [...],
"bullets_without_metrics": [...],
"passive_voice_phrases": [...],
"readability_score": 0.82,
"sections_detected": ["SUMMARY", "EXPERIENCE", ...]
},
"chart_paths": {
"keyword_coverage": "/api/charts/session-id/...",
"match_pie": "/api/charts/...",
"skill_gap": "/api/charts/...",
"quality_breakdown": "/api/charts/...",
"keyword_heatmap": "/api/charts/..."
}
}POST /api/download-docx
Request:
optimized_resume(string): Resume text to convert to DOCX
Response: DOCX file binary
GET / # Health check
GET /health # Service health
GET /api/charts/{session_id}/{filename} # Serve chart images
Edit .env to customize:
# Google Gemini API
GOOGLE_API_KEY=your-api-key-here # Your Gemini API key
# Paths
CHARTS_DIR=backend/charts # Where to save chart images- Extracts text from PDF/DOCX files
- Cleans and normalizes formatting
- Preserves original content
- Extracts structured data:
- Required skills
- Preferred skills
- Responsibilities
- Keywords & tools
- Experience level
- Returns strict JSON format
- Rewrites resume using JD keywords
- Improves action verbs and phrasing
- Does NOT fabricate experience
- Maintains factual accuracy
- Improves ATS friendliness
- Keyword Match %: How many JD keywords appear in resume
- Semantic Similarity: TF-IDF cosine similarity (0-1 scale)
- Final Score: Weighted blend (55% keyword, 45% semantic)
- Compares required skills vs resume
- Identifies matched and missing skills
- Calculates gap percentage (weighted by skill importance)
- Readability: Word length, sentence complexity
- Formatting: Section headers, bullet points, structure
- Content: Action verbs, metrics, technology references
- Keyword Density: JD keyword percentage
- Keyword Coverage: Bar chart of matched vs missing
- Match Pie: Percentage breakdown
- Skill Gap: Donut chart of skill matching
- Quality Breakdown: Component score visualization
- Keyword Heatmap: Top keywords and importance
To showcase this as a portfolio project:
-
Deploy Backend: Use platforms like:
- Heroku (with procfile)
- AWS (EC2 + RDS)
- Railway
- DigitalOcean
-
Deploy Frontend: Use:
- Vercel (easiest for React)
- Netlify
- GitHub Pages
- AWS S3 + CloudFront
-
Example .github/workflows/deploy.yml:
name: Deploy on: [push] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Deploy to Vercel run: npm run build && vercel deploy
-
README highlights:
- Tech stack: FastAPI, React, Tailwind, Google Gemini 1.5 Flash
- 50+ lines of code per service
- Database-free but production-ready
- API-first architecture
- Comprehensive error handling
# Manual test with curl
curl -X POST http://localhost:8000/api/analyze/comprehensive \
-F "resume=@resume.pdf" \
-F "jd_text=Senior Python Developer required..."Manual testing:
- Try uploading invalid files β should show errors
- Missing JD β error message
- Large resumes β should handle gracefully
- Check all tabs render correctly
-
Resume Format:
- Clean, standard format
- Use clear section headers
- Quantify achievements (e.g., "Increased revenue by 25%")
- Action verbs per bullet point
-
Job Description:
- Full JD text works better
- Include "Required", "Preferred", tools, responsibilities
- Longer = more detailed analysis
-
Optimization:
- Tool detects ~80-90% of important keywords
- Review suggestions before accepting
- Don't over-optimize: maintain authenticity
- Add real skills you possess
Solution: Create .env file with your key (copy from .env.example)
Solution: Run backend from project root: uvicorn backend.main:app --reload
Solution: Kill process or use different port: uvicorn backend.main:app --reload --port 8001
Solution: Check browser console for errors, ensure backend is running
Solution: Check backend logs, ensure CHARTS_DIR exists and is writable
For detailed info on individual services, see:
Improvements welcome! Areas for enhancement:
- Database support (PostgreSQL)
- Job queue for async processing
- WebSocket updates for real-time analysis
- Resume templates library
- Multi-language support
- User accounts & saved analyses
- Batch resume processing
- Advanced formatting preservation
Open source. Use freely for portfolio/production projects.
- β Run locally following Quick Start
- Deploy backend to cloud (Railway/Render)
- Deploy frontend to Vercel
- Add to GitHub portfolio
- Write blog post about the project
- Showcase in interviews
Built with Python, FastAPI, React, OpenAI API, and Tailwind CSS
-
Create a virtual environment and install dependencies:
cd "c:\Users\amrit\OneDrive\Documents\ATS Scanner" python -m venv .venv .venv\Scripts\activate # Windows # source .venv/bin/activate # macOS/Linux pip install -r requirements.txt
-
Copy
.env.exampleto.envand set your OpenAI API key:OPENAI_API_KEY=sk-... OPENAI_MODEL=gpt-4o-mini CHARTS_DIR=backend/charts -
Run the API (from project root so
backendpackage is importable):set PYTHONPATH=%CD% # Windows # export PYTHONPATH=. # macOS/Linux uvicorn backend.main:app --reload --host 0.0.0.0 --port 8000
API: http://localhost:8000
Docs: http://localhost:8000/docs
-
Install and run:
cd frontend npm install npm run dev -
The Vite dev server proxies
/apitohttp://localhost:8000, so use the frontend URL for full flow.
- Upload your resume (PDF or DOCX).
- Provide job description: either upload a PDF/DOCX/TXT or paste text.
- Click Optimize.
- View ATS score, Optimized resume, Score breakdown, Missing keywords, and Visual dashboard.
- Click Download DOCX to save the optimized resume.
| Variable | Description | Default |
|---|---|---|
OPENAI_API_KEY |
OpenAI API key | (required) |
OPENAI_MODEL |
Model for JD/optimize | gpt-4o-mini |
CHARTS_DIR |
Dir for chart images | backend/charts |
- No fabrication: The optimizer does not invent experience, skills, or employment history. It only improves wording and keyword alignment.
- All OpenAI prompts instruct the model to return strict JSON and not fabricate.
MIT.