A full-stack RAG application that helps job seekers understand how well they match a job description — with answers cited back to the exact part of their resume or the posting.
Most "AI resume" tools just dump your whole resume and a job description into a single prompt and hope the model figures it out. RoleFit instead uses Retrieval-Augmented Generation (RAG), which is a more honest and more accurate approach. Here's the idea in plain English:
-
Embeddings. Computers don't understand text directly, so we convert each chunk of a document into a list of numbers called an embedding (a "vector"). The neat property: chunks with similar meaning end up close together in this number-space, even if they use different words. "Built data pipelines in Python" and "experience with ETL using Pandas" land near each other.
-
Vector search. When you ask a question, we embed your question the same way, then find the document chunks whose vectors are closest to it. This is semantic search — it finds relevant passages by meaning, not by keyword matching. RoleFit retrieves the top 5 most relevant chunks for each question.
-
Retrieval → grounded answer. Those retrieved chunks (and only those) are handed to a local LLM, which writes the answer. Because the model is told to answer from the retrieved text, it can cite exactly which document and section each statement came from — and say "I don't have information on that" instead of hallucinating when nothing relevant is found.
The result: instead of a vague vibe-check, you get specific, source-backed answers about your fit for a role.
┌──────────────────────────────────────────────┐
│ FRONTEND (React) │
│ Upload (drag & drop) Chat Doc list │
└───────────────┬──────────────────────────────┘
│ HTTP (REST / JSON)
▼
┌──────────────────────────────────────────────────────────────────────────────────┐
│ BACKEND (FastAPI) │
│ │
│ INGESTION PIPELINE QUERY PIPELINE │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ PDF / text │ │ User question│ │
│ └──────┬───────┘ └──────┬───────┘ │
│ ▼ ▼ │
│ ┌──────────────┐ PyPDF2 ┌──────────────┐ │
│ │ Parse text │ │ Embed query │ MiniLM │
│ └──────┬───────┘ └──────┬───────┘ │
│ ▼ ▼ │
│ ┌──────────────┐ 512 tok / 50 overlap ┌──────────────┐ │
│ │ Chunk │ │ Vector search│ top-5 │
│ └──────┬───────┘ └──────┬───────┘ │
│ ▼ ▼ │
│ ┌──────────────┐ sentence-transformers ┌──────────────┐ │
│ │ Embed chunks │ (all-MiniLM-L6-v2, local) │ Build context│ + citations │
│ └──────┬───────┘ └──────┬───────┘ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Store + meta │ │ LLM answer │ Ollama (local) │
│ └──────┬───────┘ └──────┬───────┘ │
└──────────┼───────────────────────────────────────────────┼────────────────────────┘
▼ ▼
┌─────────────────────────────────────┐ ┌──────────────┐
│ ChromaDB (local vector store) │ ───────▶ │ Answer + │
│ vectors + {filename, type, │ │ citations │
│ upload_time, chunk text} │ └──────────────┘
└─────────────────────────────────────┘
| Choice | Why |
|---|---|
| FastAPI | Modern async Python web framework; automatic OpenAPI docs; great for a small REST API. |
| LlamaIndex | Purpose-built RAG framework — handles chunking, retrieval, and response synthesis so we don't reinvent the pipeline. |
| ChromaDB | Embedded vector database that runs locally with zero external services or setup. |
sentence-transformers (all-MiniLM-L6-v2) |
Fast, free, fully local embedding model. 384-dim vectors, good quality-to-speed ratio, no API keys. |
| Ollama | Runs an LLM locally for answer synthesis — keeps your resume private and avoids per-token cloud costs. |
| PyPDF2 | Lightweight pure-Python PDF text extraction. |
| uvicorn | Fast ASGI server to run FastAPI. |
| React + Vite + TypeScript | Fast dev experience, type safety, and a simple SPA for upload + chat. |
| Docker Compose | One command to run backend and frontend together. |
- Python 3.10+
- Node 18+
- Ollama installed and running
# Install (macOS)
brew install ollama
# or download from https://ollama.com/download
# Start the Ollama service
ollama serve
# In another terminal, pull a model (used for answer generation)
ollama pull llama3Ollama listens on
http://localhost:11434by default — the backend talks to it there.
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # adjust if needed
uvicorn app.main:app --reload --port 8000The API will be at http://localhost:8000 (interactive docs at /docs).
cd frontend
npm install
npm run devThe UI will be at http://localhost:5173.
docker compose up --buildNote: Ollama still runs on the host — make sure
ollama serveis up before querying.
- "How well do I match this role?"
- "What skills am I missing for this job?"
- "What should I emphasize for this position?"
- "What are the gaps in my experience?"
- "Which of my past roles is most relevant to this job?"
- "Do I meet the years-of-experience requirement?"
See SAMPLE_QUESTIONS.md for more, and tips on what kinds of questions work best.
Limitations
- Answer quality depends on the local Ollama model you choose — smaller models give weaker reasoning.
- PDF parsing is text-only; scanned/image resumes won't extract (no OCR yet).
- Retrieval is top-5 by semantic similarity — very long documents may push relevant context out.
- No authentication or multi-user separation; intended for local single-user use.
Future improvements
- OCR fallback for scanned PDFs.
- Re-ranking retrieved chunks for better precision.
- Per-session document collections / multi-user support.
- Side-by-side resume vs. job-description gap matrix.
- Streaming answers in the chat UI.
Placeholder — add screenshots once the UI is built.
| Upload | Chat with citations |
|---|---|
| (screenshot) | (screenshot) |
rolefit/
├── backend/ # FastAPI + LlamaIndex + ChromaDB RAG service
├── frontend/ # React + Vite + TypeScript UI
├── docker-compose.yml
├── SAMPLE_QUESTIONS.md
├── .gitignore
└── README.md
🚧 Early scaffolding — repository documentation and configuration only. Application code is not implemented yet.