A web app that generates personalized cover letters from job descriptions and user details, then renders the output into a downloadable PDF.
The app now uses OpenRouter only for LLM generation, with the allowed model list defined in YAML and surfaced in the UI dropdown.
- OpenRouter-powered cover letter generation
- Job application question answering using the same resume/projects context
- Resume PDF tailoring from structured
resume.yaml - YAML-driven model allowlist (
config/model.yaml) - Backend model validation (rejects unknown slugs)
- React frontend with model dropdown fetched from backend
- PDF generation and download
- Dockerized deployment
frontend/: React appbackend/: Flask app serving APIs + frontend buildbackend/api_service/: Prompt construction, model config loading, OpenRouter callsbackend/models/: Pydantic schemas for structured LLM outputspdf_service/: ReportLab PDF generationresume.yaml: Structured resume source used for tailored resume generationconfig/: YAML model configurationstatic/: Resume and static assets
- Python 3.9+
- Node.js 18+
- OpenRouter API key
python -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txtcd frontend
npm install
cd ..Create .env:
OPENROUTER_API_KEY=your_openrouter_api_key_here
# Optional attribution headers:
# OPENROUTER_HTTP_REFERER=https://your-app-domain.com
# OPENROUTER_APP_TITLE=Cover Letter GeneratorEdit config/model.yaml:
openrouter:
base_url: https://openrouter.ai/api/v1
default_model: openai/gpt-4.1-mini
models:
- label: GPT-4.1 Mini
slug: openai/gpt-4.1-miniPlace your resume PDF at static/resume.pdf for cover-letter and question-answer context.
Edit resume.yaml for generated resume content; the backend renders tailored resume PDFs from this YAML file.
chmod +x run.sh
./run.sh- Frontend:
http://localhost:3002 - Backend:
http://localhost:5000
source .venv/bin/activate
python backend/app.pyIn another terminal:
cd frontend
PORT=3002 npm startdocker build -t cover-letter-generator .
docker run -p 8080:8080 -e OPENROUTER_API_KEY=your_key_here cover-letter-generatorGET /api/models: Returns configured model list and default modelPOST /api/analyze: Generates cover letter text using selected model slug (or default)POST /api/answer-questions: Generates answers for pasted application questions using the same candidate contextPOST /api/generate-resume: Generates a tailored resume PDF fromresume.yamlPOST /api/generate-pdf: Builds PDF from generated textGET /api/download/<filename>: Downloads generated PDF
- Backend enforces model allowlist from
config/model.yaml. - Backend loads YAML at startup and fails fast if invalid.
POST /api/analyzereturns400for unknown model slugs.