Supercharge your job applications with AI. Upload your CV once, provide any job description, and receive a tailored ATS-optimised CV and a bespoke cover letter as download-ready PDFs — in under a minute.
CV & Cover Letter AI Optimizer is an open-source, AI-powered web application designed to eliminate the tedious manual work of tailoring job applications. Most candidates send the same CV to every role — and most automated screening tools (ATS) reject these generic applications before a human ever reads them.
This tool solves that problem in three steps:
pdfplumber and OpenAI GPT-4o.| Feature | Detail |
|---|---|
| AI engine | OpenAI GPT-4o — state-of-the-art reasoning for nuanced rewrites |
| ATS-friendly output | Single-column layout, plain language, no graphics — passes automated screening |
| JD input flexibility | Paste a job-board URL or paste raw JD text |
| Zero data persistence | CV bytes never hit disk; generated PDFs are ephemeral |
| Single-page UI | Clean, drag-and-drop interface — no account required |
| Fully tested | Unit & integration test suite with mocked LLM calls |
.docx) or plain-text output formats.Upload CV (PDF) + Paste JD (URL or text)
│
▼
Extract CV text ──► Fetch / clean JD text
(pdfplumber) (requests + BS4)
│
▼
GPT-4o analyses CV → structured JSON
(name, email, phone, skills, experience …)
│
▼
GPT-4o optimises CV against JD
(rewritten summary, ATS keywords, stronger bullets)
│
▼
GPT-4o generates Cover Letter
(personalised, max 400 words, professional tone)
│
▼
ReportLab renders PDF (CV) + PDF (Cover Letter)
│
▼
Download individually ──or── Download as ZIP bundle
| Layer | Technology | Version |
|---|---|---|
| Web framework | Flask | 3.1 |
| AI / LLM | OpenAI GPT-4o | via openai 1.68 |
| PDF parsing | pdfplumber | 0.11 |
| PDF generation | ReportLab | 4.3 |
| Web scraping | requests + BeautifulSoup4 | 2.32 / 4.13 |
| Configuration | python-dotenv | 1.1 |
| WSGI utilities | Werkzeug | 3.1 |
| Testing | pytest + pytest-mock | 8.3 / 3.14 |
improved-JD-application/
│
├── app.py # Flask entry point — all HTTP routes
│ # GET / → serve UI
│ # POST /generate → run AI pipeline
│ # GET /download/<id>/<type> → serve PDF
│ # GET /download/<id>/bundle → serve ZIP
│
├── requirements.txt # Pinned Python dependencies
├── .env.example # Template for required environment variables
├── .gitignore # Excludes .env, uploads/, outputs/, __pycache__
│
├── src/ # Core business logic
│ ├── __init__.py
│ ├── cv_processor.py # PDF text extraction (pdfplumber) and
│ │ # regex-based contact detail parsing
│ │ # (email, phone, LinkedIn URL)
│ │
│ ├── jd_processor.py # Fetch JD from URL (requests + BeautifulSoup)
│ │ # or sanitise plain-text JD input
│ │
│ ├── llm_service.py # OpenAI GPT-4o client (thread-safe singleton)
│ │ # — analyse_cv() → structured JSON
│ │ # — optimise_cv() → ATS-tuned JSON
│ │ # — generate_cover_letter() → plain text
│ │
│ └── pdf_generator.py # ReportLab PDF renderer
│ # — generate_cv_pdf() → CV PDF
│ # — generate_cover_letter_pdf() → CL PDF
│
├── templates/
│ └── index.html # Jinja2 single-page web UI
│
├── static/
│ ├── css/style.css # UI styles (responsive, clean)
│ └── js/main.js # Form handling, progress indicator,
│ # download button activation
│
├── tests/
│ ├── __init__.py
│ └── test_app.py # pytest unit & integration tests
│ # (all LLM calls mocked via pytest-mock)
│
├── uploads/ # Reserved for future disk-based upload handling
│ # (currently CV bytes are processed in memory)
└── outputs/ # Ephemeral generated PDF / ZIP output files
git for cloninggit clone https://github.com/shamir456/improved-JD-application.git
cd improved-JD-application
# macOS / Linux
python -m venv .venv
source .venv/bin/activate
# Windows (PowerShell)
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install -r requirements.txt
cp .env.example .env
Open .env in your editor and fill in the required values:
OPENAI_API_KEY=sk-... # Required — your OpenAI key
FLASK_SECRET_KEY=change-me # Required — any long random string
FLASK_DEBUG=False # Optional — set True for hot-reload in dev
MAX_UPLOAD_SIZE_MB=10 # Optional — max CV file size (default 10 MB)
UPLOAD_FOLDER=uploads # Optional — directory for uploads
OUTPUT_FOLDER=outputs # Optional — directory for generated PDFs
Tip: Generate a strong secret key with:
python -c "import secrets; print(secrets.token_hex(32))"
python app.py
The app starts on http://localhost:5000.
Set FLASK_DEBUG=True in .env to enable auto-reload on code changes.
pip install gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 app:app
Note: Always set a stable
FLASK_SECRET_KEYin production; the auto-generated key is invalidated on every restart.
Once the server is running, open http://localhost:5000 in your browser.
| Step | Action | Detail |
|---|---|---|
| 1 | Upload your CV | Drag & drop a PDF onto the upload area, or click Browse to select a file. The file must be a text-based PDF (not a scanned image) and must not exceed the configured size limit (default: 10 MB). |
| 2 | Provide the Job Description | Choose one of two methods: |
| → Paste a URL | Select the URL tab and paste the full link to the job posting (e.g. a LinkedIn or Indeed listing). The app will fetch and extract the JD text automatically. | |
| → Paste raw text | Select the Text tab and paste the full job description text directly into the text area. | |
| 3 | Generate | Click the Generate Optimized CV & Cover Letter button. A progress indicator will appear. |
| 4 | Wait ~30–60 seconds | The AI pipeline runs three sequential GPT-4o calls: CV analysis → CV optimisation → cover letter generation. |
| 5 | Download your documents | Once complete, three download buttons appear: |
| → Optimized CV | Downloads Optimized_CV.pdf — ATS-tuned, keywords aligned to the JD. |
|
| → Cover Letter | Downloads Cover_Letter.pdf — personalised, professional, max 400 words. |
|
| → Download Bundle (ZIP) | Downloads Application_Bundle.zip containing both PDFs in one file. |
pytest tests/ -v
The test suite uses pytest-mock to patch all OpenAI API calls so no real key is needed.
Tests cover:
| Area | What is tested |
|---|---|
cv_processor |
PDF text extraction from file path and bytes; email, phone, LinkedIn regex extraction |
jd_processor |
URL validation and HTTP error handling; plain-text cleaning and blank-line collapsing |
pdf_generator |
CV PDF generation with full and minimal data; cover letter PDF generation |
app routes |
Missing CV / JD validation; JD URL and text modes with mocked LLM; all download endpoints; ZIP bundle; 404 / 413 error handlers |
To run a specific test file or test:
# Run only a specific test
pytest tests/test_app.py::test_generate_success -v
# Run with coverage (requires pytest-cov)
pip install pytest-cov
pytest tests/ --cov=src --cov-report=term-missing
| Variable | Required | Default | Description |
|---|---|---|---|
OPENAI_API_KEY |
✅ | — | Your OpenAI API key (GPT-4o access required) |
FLASK_SECRET_KEY |
✅ | (random) | Secret key for Flask session signing — set a stable value in production |
FLASK_DEBUG |
❌ | False |
Enable Flask debug/hot-reload mode |
MAX_UPLOAD_SIZE_MB |
❌ | 10 |
Maximum CV PDF upload size in megabytes |
UPLOAD_FOLDER |
❌ | uploads |
Directory reserved for upload handling |
OUTPUT_FOLDER |
❌ | outputs |
Directory where generated PDFs and ZIPs are written |
uploads/ folder is reserved for future use.outputs/ and served on demand. No automatic cleanup is performed; remove old files manually or via a cron job.OPENAI_API_KEY and FLASK_SECRET_KEY must never be committed to source control — use .env (already in .gitignore).FLASK_SECRET_KEY is not set, a random key is generated at startup and a warning is logged; all sessions are invalidated on restart. Always set this in production.download_id is a 32-character alphanumeric UUID hex before serving any file.MAX_CONTENT_LENGTH to enforce the upload size limit; requests exceeding it receive a 413 response.The following features are planned for future releases, roughly ordered by priority:
| # | Feature | Description |
|---|---|---|
| 1 | ATS Score & Keyword Report | Display a match-score dashboard showing which JD keywords are present/missing in the optimised CV, giving users actionable insight before downloading. |
| 2 | Multiple CV Template Styles | Offer a choice of professionally designed PDF layouts (e.g. modern, classic, minimal) so users can match the aesthetic expected in their industry. |
| 3 | DOCX Export | Generate Microsoft Word (.docx) output in addition to PDF, allowing users to make further manual edits using standard word processors. |
| 4 | LinkedIn Profile Import | Allow users to paste their LinkedIn profile URL as an alternative to uploading a PDF, automatically scraping public profile data as the CV source. |
| 5 | Direct Job Board Integration | One-click JD import from LinkedIn Jobs, Indeed, and other major job boards via their APIs or structured data, removing the need to copy-paste URLs. |
| 6 | Interview Preparation Q&A | After generating the optimised CV, produce a set of likely interview questions derived from the JD, with suggested talking points based on the candidate’s experience. |
| 7 | Skills Gap Analysis | Identify skills listed as required in the JD that are absent from the candidate’s CV, and suggest courses, certifications, or projects to close the gap. |
| 8 | Batch Processing | Accept a single CV and a list of JDs, producing a full set of tailored documents for each role in one run — ideal for high-volume job searches. |
| 9 | User Accounts & Application History | Optional account creation to save past optimisation runs, track which roles were applied to, and re-download previously generated documents. |
| 10 | Salary Estimation | Parse compensation signals from the JD and cross-reference them with market data to provide a realistic salary range for the target role and location. |
| 11 | Browser Extension | A lightweight browser extension for Chrome/Firefox that adds a one-click “Optimise my CV for this job” button on supported job-board pages. |
| 12 | Email Delivery | Send the generated PDF bundle directly to the candidate’s inbox after generation, as a convenience alternative to the download buttons. |
| 13 | OCR Support for Scanned CVs | Integrate an OCR engine (e.g. Tesseract) to extract text from image-based or scanned PDF CVs, removing the current text-PDF-only limitation. |
| 14 | Alternative LLM Backends | Add support for self-hosted or alternative LLM providers (e.g. Anthropic Claude, Google Gemini, Ollama) so that users are not locked into OpenAI. |
MIT