Skip to content

AI-powered CV optimization using CrewAI Flow. This application uses AI agents to iteratively improve your CV to match specific job descriptions.

License

Notifications You must be signed in to change notification settings

heseber/cv_writer

Repository files navigation

CV Optimizer

AI-powered CV optimization using CrewAI Flow. This application uses AI agents to iteratively improve your CV to match specific job descriptions.

Features

  • Iterative Optimization: AI reviewer and writer agents work together to improve your CV
  • Multiple Input Formats: Support for text, markdown, and PDF files
  • Web Scraping: Extract job descriptions directly from URLs
  • Multi-LLM Support: Works with OpenAI, Anthropic, and Ollama (local models)
  • Multi-Language Translation: Translate your optimized CV to any language (German, French, Spanish, etc.)
  • Flexible Configuration: Configure via files, environment variables, or CLI arguments
  • Detailed Feedback: Get comprehensive feedback history for all iterations
  • Production Ready: Clean, professional markdown output

Installation

Prerequisites

  • Python 3.10 or higher (< 3.14)
  • pip or uv package manager

Install Dependencies

# Using pip
pip install -e .

# Or using uv (recommended)
uv pip install -e .

Quick Start

1. Set Up API Keys

Create a .env file in the project root:

# For OpenAI (default)
OPENAI_API_KEY=your_openai_api_key_here

# For Anthropic
ANTHROPIC_API_KEY=your_anthropic_api_key_here

# For Ollama (optional, defaults to localhost)
OLLAMA_BASE_URL=http://localhost:11434

2. Run the Optimizer

Basic usage:

cv-optimizer --job-description job.txt --cv my_cv.md

With additional options:

cv-optimizer \
  --job-description https://example.com/job-posting \
  --cv my_cv.pdf \
  --additional-docs portfolio.pdf \
  --additional-docs certifications.md \
  --llm-provider openai \
  --max-iterations 5 \
  --output-dir ./results

Usage

Command Line Options

Required Arguments

  • --job-description, -j: Job description source (file path or URL)
  • --cv, -c: Path to your CV file

Optional Arguments

  • --additional-docs, -a: Additional supporting documents (can be used multiple times)
  • --llm-provider, -p: LLM provider (openai, anthropic, ollama)
  • --llm-model, -m: Specific model name
  • --max-iterations, -i: Maximum number of iterations (default: 3)
  • --config: Path to custom config file
  • --output-dir, -o: Output directory for results
  • --translate-to, -t: Target language code for translation (e.g., 'de', 'fr', 'es')
  • --translation-llm-provider: LLM provider for translation (if different from main)
  • --translation-llm-model: LLM model for translation (if different from main)

Supported File Formats

Input Files

  • Text: .txt
  • Markdown: .md, .markdown
  • PDF: .pdf

Job Description Sources

  • Local files (text, markdown, PDF)
  • URLs (web scraping)

Configuration

Configuration follows a hierarchy (lowest to highest precedence):

  1. Default values
  2. Config file (src/cv_writer/config/cv_optimizer.yaml)
  3. Environment variables
  4. CLI arguments

Config File Example

Create a custom config file:

llm:
  provider: openai
  model: gpt-4o
  temperature: 0.7

optimizer:
  max_iterations: 3
  save_intermediate_versions: false

output:
  directory: ./output
  cv_filename_pattern: "cv_optimized_{timestamp}.md"
  feedback_filename_pattern: "cv_review_history_{timestamp}.md"

translation:
  enabled: false
  target_language: null
  llm_provider: null  # Uses main LLM if not specified
  llm_model: null     # Uses main LLM if not specified

Use it:

cv-optimizer --config my_config.yaml --job-description job.txt --cv cv.md

Environment Variables

Override configuration with environment variables:

export LLM_PROVIDER=anthropic
export LLM_MODEL=claude-sonnet-4-5
export MAX_ITERATIONS=5
export OUTPUT_DIRECTORY=./my_output

cv-optimizer --job-description job.txt --cv cv.md

Translation Environment Variables

# Enable translation with environment variables
export TRANSLATE_TO=de
export TRANSLATION_LLM_PROVIDER=ollama
export TRANSLATION_LLM_MODEL=llama3.1

cv-optimizer --job-description job.txt --cv cv.md

How It Works

The Optimization Flow

  1. Initialization

    • Parse job description and CV
    • Load supporting documents
    • Initialize LLM and configuration
  2. Review Phase

    • Reviewer agent analyzes CV against job requirements
    • Provides detailed, actionable feedback
    • Makes APPROVE or REVISE decision
  3. Routing Decision

    • If APPROVED: Save outputs and complete
    • If REVISE and iterations < max: Continue to writing
    • If max iterations reached: Save current version
  4. Writing Phase

    • Writer agent creates improved CV version
    • Addresses all reviewer feedback
    • Incorporates information from supporting documents
    • Returns to review phase
  5. Output Generation

    • Save final optimized CV (clean markdown)
    • Save feedback history with all iterations

Agent Roles

Reviewer Agent

  • Experienced HR professional persona
  • Critically assesses CV alignment with job requirements
  • Provides structured, actionable feedback
  • Makes binary APPROVE/REVISE decisions

Writer Agent

  • Professional CV writer persona
  • Creates compelling career narratives
  • Follows reviewer feedback meticulously
  • Optimizes for ATS and human readers

Translator Agent

  • Professional translator specializing in career documents
  • Translates CVs while preserving formatting and impact
  • Adapts terminology for target language markets
  • Maintains exact markdown structure

Output

The application generates the following files:

  1. Optimized CV (cv_optimized_[timestamp].md)

    • Clean markdown format
    • No explanations or metadata
    • Production-ready document
  2. Translated CV ([basename]_[language].md) - Optional

    • Appears only when --translate-to is specified
    • Uses the same basename as English version with language code appended
    • Language code suffix (e.g., cv_optimized_20251113_123456_de.md)
    • Preserves exact formatting of original
  3. Feedback History (cv_review_history_[timestamp].md)

    • Chronological feedback from all iterations
    • Reviewer decisions and comments
    • Improvement suggestions
    • Timestamps for each iteration

Examples

Example 1: Basic Usage with OpenAI

export OPENAI_API_KEY=your_key_here

cv-optimizer \
  --job-description job_posting.txt \
  --cv my_cv.md

Example 2: Using Anthropic with Additional Documents

export ANTHROPIC_API_KEY=your_key_here

cv-optimizer \
  --job-description https://example.com/job \
  --cv cv.pdf \
  --additional-docs portfolio.md \
  --additional-docs certifications.pdf \
  --llm-provider anthropic \
  --max-iterations 5

Example 3: Using Local Ollama Model

# Start Ollama server first
# ollama serve

cv-optimizer \
  --job-description job.txt \
  --cv cv.md \
  --llm-provider ollama \
  --llm-model llama3.1 \
  --max-iterations 3

Example 4: Translation to German

export OPENAI_API_KEY=your_key_here

cv-optimizer \
  --job-description job.txt \
  --cv cv.md \
  --translate-to de

Example 5: Translation with Different LLM

# Use Claude for translation while using GPT-4o for optimization
cv-optimizer \
  --job-description job.txt \
  --cv cv.md \
  --llm-provider openai \
  --translate-to de \
  --translation-llm-provider anthropic \
  --translation-llm-model claude-sonnet-4-5

# Use local Ollama model for translation to save costs
cv-optimizer \
  --job-description job.txt \
  --cv cv.md \
  --translate-to fr \
  --translation-llm-provider ollama \
  --translation-llm-model llama3.1

Example 6: Custom Configuration

cv-optimizer \
  --config my_config.yaml \
  --job-description job.md \
  --cv cv.md \
  --output-dir ./custom_output \
  --max-iterations 4

Development

Project Structure

cv_writer/
├── src/cv_writer/
│   ├── __init__.py
│   ├── main.py                      # CLI entry point
│   ├── config/
│   │   ├── config_loader.py         # Configuration management
│   │   └── cv_optimizer.yaml        # Default config
│   ├── crews/
│   │   ├── reviewer_crew/           # Reviewer agent & tasks
│   │   ├── translator_crew/         # Translator agent & tasks
│   │   └── writer_crew/             # Writer agent & tasks
│   ├── flows/
│   │   └── cv_optimization_flow.py  # Main optimization flow
│   ├── models/
│   │   └── state_models.py          # Pydantic state models
│   ├── tools/
│   │   ├── document_parser.py       # Document processing
│   │   ├── pdf_reader.py            # PDF extraction
│   │   └── web_scraper.py           # Web scraping
│   └── utils/
│       ├── file_handler.py          # File I/O operations
│       └── llm_factory.py           # LLM instantiation
├── tests/                           # Unit tests
├── pyproject.toml                   # Project dependencies
└── README.md                        # This file

Running Tests

# Install test dependencies
pip install pytest pytest-mock

# Run tests
pytest tests/

# Run with coverage
pytest --cov=cv_writer tests/

Visualizing the Flow

Generate a flow diagram:

python -m cv_writer.main plot

Configuration Reference

LLM Providers

OpenAI

  • Provider: openai
  • Default Model: gpt-4o
  • Environment Variable: OPENAI_API_KEY
  • Other Models: gpt-5.1, gpt-5, gpt-4, gpt-3.5-turbo, etc.

Anthropic

  • Provider: anthropic
  • Default Model: claude-sonnet-4-5
  • Environment Variable: ANTHROPIC_API_KEY
  • Other Models: claude-3-5-sonnet-20241022, claude-3-opus-20240229, etc.

Ollama

  • Provider: ollama
  • Default Model: llama3.1
  • Environment Variable: OLLAMA_BASE_URL (optional)
  • Other Models: llama2, mistral, codellama, etc.
  • Note: Requires Ollama server running locally

Parameters

  • max_iterations: Number of review-revise cycles (default: 3)
  • temperature: LLM creativity (0.0-1.0, default: 0.7)
  • output_directory: Where to save results (default: ./output)

Troubleshooting

Common Issues

"OPENAI_API_KEY environment variable not set"

  • Ensure you've created a .env file with your API key
  • Or export the variable: export OPENAI_API_KEY=your_key

"Failed to extract text from PDF"

  • Ensure pypdf is installed: pip install pypdf
  • Some PDFs may have image-based text (not supported)
  • Try converting to text or markdown first

"Failed to fetch URL"

  • Check your internet connection
  • Some websites block scraping
  • Try saving the job description to a file instead

"Max iterations reached"

  • Increase iterations: --max-iterations 5
  • Review feedback history to understand issues
  • Consider manually incorporating feedback

Future Enhancements

  • Web-based user interface
  • Multiple output formats (DOCX)
  • Cover letter generation
  • A/B testing of CV versions
  • Industry-specific templates
  • Integration with job boards
  • Batch translation to multiple languages simultaneously

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please ensure:

  • Code follows existing style
  • Tests are included
  • Documentation is updated
  • Type hints are used

Support

For issues, questions, or contributions:

  1. Check existing documentation
  2. Review troubleshooting section
  3. Open an issue with detailed information

Credits

Built with:


Version: 0.2.0
Status: Production Ready
Python: 3.10-3.13

About

AI-powered CV optimization using CrewAI Flow. This application uses AI agents to iteratively improve your CV to match specific job descriptions.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages