Skip to content

About

Fork of a shared academic CV-screening project: document parsing, ML Invite/Reject prediction, PostgreSQL and React.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

104 Commits

Folders and files

Repository files navigation

Filtrant

Filtrant — Automated CV Pre-Screening 🤖

AI-Powered · Fairness-First · Production-Ready

Python FastAPI React Claude Docker License: MIT

#cv-screening #hr-tech #ai-recruitment #fastapi #react #docker #anthropic #claude #machine-learning #fairness #automation


Upload a CV (PDF, DOCX, or image) → Claude Haiku 4.5 parses it into structured JSON → ML model predicts Invite or Reject → stored in PostgreSQL → visible in a React dashboard.

Built for LuxTalent Advisory Group S.A. — production-grade, fairness-audited, Docker-ready.


Architecture

┌──────────────────────────────────────────────────────────────────┐
│                    React Dashboard (:3000)                        │
│    Upload CV · Browse Candidates · Stats & Filters               │
└──────────────────────────┬───────────────────────────────────────┘
                           │ REST API (/api/v1/)
                           ▼
┌──────────────────────────────────────────────────────────────────┐
│                     FastAPI Backend (:8000)                       │
│                                                                   │
│  1. Text extraction (pdfplumber / python-docx)                    │
│  2. Anthropic Claude Haiku 4.5 → Universal JSON schema            │
│  3. ML model → Invite / Reject + confidence score                 │
│  4. Store in PostgreSQL                                           │
└──────────────────────────┬───────────────────────────────────────┘
                           │
                    ┌──────┴──────┐
                    │ PostgreSQL  │
                    │   (:5432)   │
                    └─────────────┘

Stack : FastAPI · Anthropic Claude (claude-haiku-4-5) · scikit-learn · PostgreSQL · React + Vite + TypeScript + Tailwind · Framer Motion · Docker Compose


Quick Start (Docker Compose)

1 — Clone & configure

git clone https://github.com/ForgedEmir/Filtrant-CV-Pre-Screening.git
cd Filtrant-CV-Pre-Screening
cp .env.example .env

Open .env and set your Anthropic API key:

ANTHROPIC_API_KEY=sk-ant-...

2 — Start the stack

docker compose up --build

This starts two containers:

Container Port Description
backend 8000 FastAPI + auto-creates DB tables on first boot
postgres 5432 PostgreSQL 16, data persisted in a named volume

Wait for: backend | INFO: Application startup complete.

3 — Start the frontend

cd frontend
npm install
npm run dev

Open http://localhost:3000.

4 — Test it

  1. Go to the Upload tab → drag & drop any PDF/DOCX CV
  2. System returns Invite or Reject with confidence within seconds
  3. Switch to Candidates to browse all processed CVs with filters

Or via curl:

curl -X POST http://localhost:8000/api/v1/upload \
  -F "file=@path/to/cv.pdf"

curl http://localhost:8000/api/v1/health

ML Model

backend/ml/model.joblib is gitignored and must be generated. Without it, every candidate returns pending.

Training

# 1 — Export labelled candidates
curl http://localhost:8000/api/v1/candidates/export.csv -o backend/ml/candidates_export.csv

# 2 — Train (compares 6 classifiers, saves best)
docker compose exec backend python /app/ml/train.py

train.py compares 6 classifiers (LogisticRegression, RandomForest, GradientBoosting, SVM, HistGradientBoosting, XGBoost), selects the best by cross-validated F1 score, optimises hyperparameters with RandomizedSearchCV, and saves the pipeline.

Fairness audit

The system includes a dedicated fairness module (backend/src/services/fair_wrapper.py) that:

  • Tracks prediction distributions across demographic groups
  • Audits for disparate impact
  • Generates fairness reports

See docs/SPECS_WP2.md for the full fairness methodology.

LLM Parsing Reliability

Claude is called with temperature=0 and a hardened system prompt for fully deterministic output. Tested across 3 runs per CV — all fields identical across every run.

details in the original analysis


API Reference

All endpoints prefixed /api/v1/.

Method Path Description
POST /upload Upload CV (multipart) → parse → predict → store
GET /candidates Paginated list with filters (recommendation, date_from, date_to)
GET /candidates/{id} Full candidate record including raw CV JSON
GET /candidates/export.csv ML-ready CSV export (features + recommendation)
GET /health DB status + model file presence

Project Structure

├── docker-compose.yml          # backend + postgres
├── .env.example                # Copy to .env
│
├── backend/
│   ├── Dockerfile
│   ├── requirements.txt
│   ├── ml/
│   │   ├── train.py                # 6 classifiers → save best
│   │   ├── setup_data.py           # Raw data import helper
│   │   ├── train_fair.py           # Fairness-augmented training
│   │   └── model.joblib            # Trained model (gitignored)
│   └── src/
│       ├── main.py                 # FastAPI entry point
│       ├── config.py               # Pydantic settings
│       ├── db.py                   # psycopg2 pool
│       ├── models/cv_schema.py     # Universal JSON schema
│       └── services/
│           ├── extractor.py        # PDF/DOCX/TXT → text + SHA-256
│           ├── llm_parser.py       # Claude Haiku → structured JSON
│           ├── features.py         # JSON → ML feature vector
│           ├── predictor.py        # Load model, predict
│           ├── fair_wrapper.py     # Fairness auditing
│           └── watcher.py          # Auto-process incoming CVs
│
├── frontend/
│   ├── Dockerfile
│   ├── src/
│   │   ├── App.tsx
│   │   ├── api/client.ts           # Typed API client
│   │   ├── types/cv.ts             # TypeScript ↔ Pydantic
│   │   └── pages/
│   │       ├── DashboardPage.tsx    # Stats + activity chart
│   │       ├── UploadPage.tsx       # Drag-and-drop upload
│   │       └── CandidatesPage.tsx   # Paginated list + detail modal
│   └── ... config files
│
├── data/
│   ├── incoming_cvs/          # Drop CVs → watcher auto-processes
│   ├── processed_cvs/         # Moved here on success
│   └── failed_cvs/            # Moved here on failure
│
└── docs/
    ├── SPECS_WP1.md           # Client requirements (Work Package 1)
    ├── SPECS_WP2.md           # Fairness audit & model redesign
    ├── ML_REPORT.md           # Metrics, feature importance, v1 vs v2
    └── ML_COMPLETE_GUIDE.md   # Deep-dive on every ML algorithm

File Watcher

The backend polls data/incoming_cvs/ every 10 seconds. Drop any CV in → auto-processed → moved to processed_cvs/ on success or failed_cvs/ on failure. Configurable via WATCHER_INTERVAL env variable.


Environment Variables

Variable Required Description
ANTHROPIC_API_KEY Yes sk-ant-... from console.anthropic.com
DATABASE_URL Yes PostgreSQL connection string (Railway auto-sets this)
ENV No development (default) or production
LOG_LEVEL No INFO (default)
WATCHER_INTERVAL No File watcher poll interval in seconds (default: 10)
VITE_API_BASE_URL Frontend API base URL (defaults to http://localhost:8000)

Deployment

Railway (backend + PostgreSQL)

  1. New Railway project → add PostgreSQL plugin
  2. Add service from repo, root backend/, Docker auto-detected
  3. Set ANTHROPIC_API_KEY in Railway env vars

Vercel (frontend)

  1. Import repo, root frontend/ (Vite auto-detected)
  2. Set VITE_API_BASE_URL=https://<your-railway-backend-url>

IDE Setup (VS Code)

The app runs inside Docker, but your IDE needs local packages for IntelliSense.

cd backend
python -m venv .venv
# Windows
.venv\Scripts\pip install --only-binary=:all: fastapi uvicorn[standard] python-multipart httpx python-docx pdfplumber scikit-learn pandas numpy joblib pydantic pydantic-settings python-dotenv psycopg2-binary

Use Python 3.11.x — the Docker image is pinned to python:3.11.12-slim.

The repo includes .vscode/settings.json — VS Code picks up the venv automatically.


Stopping / Cleaning Up

# Stop containers (preserves data)
docker compose down

# Stop + wipe database
docker compose down -v

Contributing

Resource Description
LICENSE MIT — free to use, modify, distribute

Filtrant — Forked from Oliphantaupe/Filtrant-CV-Pre-Screening.

About

Fork of a shared academic CV-screening project: document parsing, ML Invite/Reject prediction, PostgreSQL and React.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages