Know exactly what the algorithm sees before a recruiter does.
Live at : https://ai-resumeanalyzer-aperture.vercel.app/ Experience my AI Resume Analyzer(aperture)
Upload a resume, paste a job description, and get a full ATS-style report: match score, skill gaps, resume suggestions, and auto-generated interview questions — in seconds.
Demo · Features · Screenshots · Quick Start · Deploy · API · Architecture
Full end-to-end walkthrough — sign up → upload a resume + job description → live ATS scoring → skill-gap breakdown → interview questions → history → analytics.
- 📄 Upload a resume as PDF, DOCX, or TXT
- 🎯 Match it against any pasted job description
- 📊 ATS Score (0–100) — weighted composite of skill match, semantic relevance, and ATS-friendly formatting
- 🧠 AI skill extraction against a 400+ term skills taxonomy
- ❌ Missing skills detection — exactly what the JD wants that your resume doesn't mention
- 💡 Resume improvement suggestions — rule-based, specific, actionable
- 🤖 Interview question generation — tailored to your matched skills and your skill gaps
- 📈 Analytics dashboard — score trend over time, skill category coverage, most frequently missing skills
- 🔐 JWT authentication — sign up, sign in, guest mode supported
- 📜 Resume history — every analysis saved and browsable
- ✨ Distinctive "Ink & Gold" UI with a signature scanner-glint click effect — no template-generic dashboard look
| Component | Weight | How it's computed |
|---|---|---|
| Skill match | 45% | Overlap between skills detected in your resume and in the JD, against a curated taxonomy of 400+ programming languages, frameworks, cloud/DevOps tools, databases, AI/ML terms, and soft skills |
| Semantic relevance | 35% | Cosine similarity between resume and JD text. Uses TF-IDF by default (instant, zero setup); automatically upgrades to Sentence-Transformer (BERT-family) embeddings if that optional dependency is installed |
| ATS formatting | 20% | Contact info present, standard section headers, ideal word count, use of action verbs, quantified achievements |
This dual-engine design (lightweight-always-works + optional-AI-upgrade) is deliberate — the app never breaks because a model failed to download.
| Layer | Technology |
|---|---|
| Backend | Python · FastAPI · SQLAlchemy |
| Database | PostgreSQL (production) · SQLite (zero-config local dev) |
| AI / NLP | Custom skill-taxonomy engine · scikit-learn TF-IDF · optional spaCy NER + Sentence-Transformers |
| Auth | JWT (python-jose) · bcrypt password hashing |
| Frontend | Vanilla HTML/CSS/JS single-page app · Chart.js |
| Infra | Docker · Docker Compose · Redis (optional cache) · Vercel-ready |
You need Python 3.10+.
cd backend
pip install -r requirements.txt
uvicorn app.main:app --reloadOpen http://localhost:8000 — the frontend is served automatically at
the root URL. That's it. A local resume_analyzer.db SQLite file is
created for you on first run.
For real Named Entity Recognition and transformer-based semantic embeddings:
pip install spacy sentence-transformers
python -m spacy download en_core_web_smRestart the server — it detects and uses them automatically. No code
changes needed. Check GET /api/health to confirm which engine is active.
docker compose up --buildThis spins up PostgreSQL, Redis, and the backend together. Open http://localhost:8000.
To also bake in the enhanced AI engine at build time:
docker compose build --build-arg INSTALL_ENHANCED_AI=true
docker compose upThe repo ships ready for Vercel: api/index.py exposes the FastAPI app as
a serverless function, public/index.html is the static frontend, and
vercel.json rewrites /api/* to the function.
One thing to know: serverless functions have an ephemeral filesystem, so the local SQLite file won't persist there. You need a hosted Postgres database — Neon and Supabase both have generous free tiers and take under 2 minutes to set up.
-
Get a Postgres connection string from Neon/Supabase/Vercel Postgres.
-
Push this repo to GitHub (see next section).
-
Import the repo in Vercel:
- Go to vercel.com/new → Import Git Repository
- Select this repo — Vercel will detect the Python function automatically
-
Set environment variables in the Vercel project settings:
Key Value DATABASE_URLyour Postgres connection string JWT_SECRET_KEYany long random string -
Deploy. Vercel builds
api/index.pyusing the rootrequirements.txt(a lean, Vercel-sized dependency set — no spaCy/Sentence-Transformers, since those exceed sensible serverless bundle size) and servespublic/index.htmlas the frontend on the same domain.
npm install -g vercel
cd resume-analyzer
vercel login
vercel # first deploy — follow the prompts
vercel env add DATABASE_URL production
vercel env add JWT_SECRET_KEY production
vercel --prod # deploy to productionNote: the Hobby plan caps request bodies around 4.5MB — plenty for resumes, but keep files under that if you hit an upload limit.
cd resume-analyzer
git init
git add .
git commit -m "Initial commit — Aperture AI Resume Analyzer"
git branch -M main
git remote add origin https://github.com/<your-username>/<your-repo>.git
git push -u origin mainIf you don't have a repo yet: create one at
github.com/new (don't initialize it with a
README — this project already has one), then copy the remote URL it gives
you into the git remote add origin command above.
The included .gitignore already excludes __pycache__/, .env,
*.db, and .vercel/ so your database file and secrets never get
committed.
resume-analyzer/
├── api/
│ └── index.py # Vercel serverless entry point
├── public/
│ └── index.html # Static frontend copy (for Vercel)
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI app + local frontend serving
│ │ ├── database.py # SQLAlchemy setup (SQLite / Postgres)
│ │ ├── models.py # User, Analysis ORM models
│ │ ├── schemas.py # Pydantic request/response models
│ │ ├── auth.py # JWT auth + password hashing
│ │ ├── skills_data.py # 400+ term skills taxonomy
│ │ ├── routers/
│ │ │ ├── auth.py # /api/auth/*
│ │ │ ├── resume.py # /api/resume/* (the core feature)
│ │ │ └── analytics.py # /api/analytics/*
│ │ └── services/
│ │ ├── parser.py # PDF/DOCX/TXT text extraction
│ │ ├── nlp_engine.py # Skill/entity/keyword extraction
│ │ ├── embeddings.py # TF-IDF ⇄ Sentence-Transformer similarity
│ │ ├── scorer.py # ATS score computation
│ │ ├── suggestions.py # Resume improvement suggestions
│ │ └── interview.py # Interview question generation
│ ├── requirements.txt # Core deps — always works, local dev
│ ├── requirements-full.txt # + spaCy, Sentence-Transformers, psycopg2
│ └── Dockerfile
├── frontend/
│ └── index.html # Source of truth for the SPA
├── screenshots/ # README screenshots + demo GIF live here
├── requirements.txt # Lean deps for Vercel's Python runtime
├── vercel.json # Vercel routing config
├── docker-compose.yml
├── .env.example
└── README.md
Signing in unlocks saved history and the analytics dashboard; guests can still run one-off analyses.
Two inputs, nothing else in the way — drop a resume, paste a job description.
Resume uploaded, a real job description pasted in, job title tagged for history.
The button state while the backend parses the file and runs the scoring pipeline.
A 66/100 "Moderate Match" — the breakdown shows exactly why: 80% skill match and 98% formatting, dragged down by 28.5% semantic relevance because the resume's overall narrative didn't closely mirror this particular JD.
12 matched skills, 3 missing (Docker, Machine Learning, React) called out by name — with suggestions and interview questions generated directly from that gap.
Questions split by category — two probing the skill gap directly, three standard behavioral questions — generated fresh from this specific resume/JD pair, not a static bank.
Every analysis persisted per-account — here, two runs against two different job descriptions with their own scores and skill-match counts.
Aggregate stats across all analyses — average and best ATS score at a glance, feeding into the score-trend and skill-coverage charts below.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
| POST | /api/auth/signup |
– | Create an account, returns a JWT |
| POST | /api/auth/login |
– | Log in, returns a JWT |
| GET | /api/auth/me |
required | Current user |
| POST | /api/resume/analyze |
optional | Upload resume + JD, get full ATS report |
| GET | /api/resume/history |
required | List past analyses |
| DELETE | /api/resume/history/{id} |
required | Delete a saved analysis |
| GET | /api/analytics/summary |
required | Score trend + skill coverage stats |
| GET | /api/health |
– | Server + AI-engine status |
Interactive API docs (Swagger UI) are auto-generated at /docs.
A single dependency-free index.html — no build step, no npm install.
Uses Chart.js (via CDN) for the analytics charts. Click anywhere on the
page for the signature "scanner glint" sparkle effect.
- Every endpoint in this README was manually tested end-to-end against a live running server (not just unit tests) before delivery, including real PDF and DOCX file uploads.
- The skill/semantic/formatting scoring weights, the skills taxonomy, and the suggestion rules are all in plain, readable Python — nothing is a black box.
- Auth uses bcrypt password hashing and JWT bearer tokens; adjust
JWT_SECRET_KEYbefore any real deployment.
MIT — free to use, modify, and build on.
Built with FastAPI, scikit-learn, and a lot of attention to detail.
