Back to Templates

Tailor your Google Docs CV to any job using Ollama and Groq

Created by

Created by: Rishi || rishiii
Rishi

Last update

Last update 3 hours ago

Share


🎯 CV Keyword Optimizer

An AI-powered n8n workflow that automatically tailors your resume to any job description by injecting relevant keywords β€” without touching your formatting, layout, or design.


How It Works

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        User Input (Form)                        β”‚
β”‚         CV Google Docs Link  +  Job URL or Pasted JD            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  1. Read CV from Google Docs API                                 β”‚
β”‚  2. Extract full CV text (handles tables, paragraphs, etc.)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  3. Get Job Description                                          β”‚
β”‚     β”œβ”€β”€ URL provided? β†’ Scrape job page, strip HTML to text      β”‚
β”‚     β”‚     └── Scrape failed? β†’ Fall back to manual JD            β”‚
β”‚     └── No URL? β†’ Use manually pasted JD directly                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  4. 🏠 Local Ollama (llama3.1:8b)                                β”‚
β”‚     Analyzes JD + CV β†’ Extracts & ranks 10-20 ATS keywords      β”‚
β”‚     Output: keyword, priority, target bullet, reason             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  5. ☁️ Groq API (Llama 3.3 70B)                                  β”‚
β”‚     Takes ranked keywords + CV β†’ Produces find/replace pairs     β”‚
β”‚     Naturally weaves keywords into experience bullet points      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  6. Copy original CV via Google Drive API                        β”‚
β”‚     (preserves ALL formatting, tables, styles)                   β”‚
β”‚                                                                  β”‚
β”‚  7. Apply replacements via Google Docs batchUpdate API            β”‚
β”‚     (replaceAllText β€” formatting stays intact)                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  8. Output                                                       β”‚
β”‚     βœ… New Google Doc link                                       β”‚
β”‚     πŸ“‹ Changelog: original text β†’ updated text + keywords added  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Why Two AI Models?

Step Model Why
Keyword Extraction Ollama llama3.1:8b (local) Free, private, no API costs. Reasoning about which keywords actually matter for ATS
Text Rewriting Groq llama-3.3-70b-versatile (cloud) Larger model = better at natural language. Produces find/replace pairs that read naturally

What Gets Modified

  • βœ… Experience/work bullet points
  • βœ… Skills/technical skills lines
  • ❌ Name, contact info, education, dates, company names, job titles β€” never touched

Formatting Preservation

The workflow copies your original Google Doc (not recreates it), then uses replaceAllText to swap text in-place. This means:

  • βœ… Tables, columns, fonts, colors β€” all preserved
  • βœ… Bold, italic, underline β€” all preserved
  • βœ… Custom spacing, margins β€” all preserved
  • βœ… Original doc is untouched (changes go to the copy)

Setup Steps

Prerequisites

1. Install & Start Ollama

# macOS
brew install ollama

# Start the Ollama server
ollama serve

# Pull the model (in another terminal)
ollama pull llama3.1:8b

Verify it's running:

curl http://localhost:11434/api/tags

2. Get a Groq API Key

  1. Go to console.groq.com
  2. Sign up / log in
  3. Navigate to API Keys β†’ Create a new key
  4. Copy the key (starts with gsk_...)

3. Configure Environment

cd cv-generator

# Create .env from template
cp .env.example .env

# Edit .env and add your Groq key
# GROQ_API_KEY=gsk_your_key_here

4. Start n8n

docker compose up -d

n8n will be available at http://localhost:5678

Default credentials:

  • Username: admin
  • Password: changeme

⚠️ Change these in docker-compose.yml for production use.

5. Import the Workflow

  1. Open n8n at http://localhost:5678
  2. Go to Workflows β†’ Import from File
  3. Select cv-keyword-optimizer.json
  4. You'll see credential warnings on some nodes β€” that's expected

6. Set Up Google Credentials

  1. In n8n, go to Settings β†’ Credentials
  2. Create a Google Docs OAuth2 credential
    • Follow n8n's OAuth2 setup guide for Google
    • Required scopes: https://www.googleapis.com/auth/documents
  3. Create a Google Drive OAuth2 credential
    • Required scopes: https://www.googleapis.com/auth/drive
  4. Click each node with a ⚠️ warning β†’ select your credential from the dropdown

7. Activate & Use

  1. Toggle the workflow Active
  2. Open the form URL shown in the trigger node (or go to http://localhost:5678/form/cv-keyword-optimizer-form)
  3. Fill in:
    • Google Docs CV Link (required)
    • Job Posting URL or Job Description (at least one)
  4. Submit and wait ~30-60 seconds
  5. Get your optimized CV link + detailed changelog

Project Structure

cv-generator/
β”œβ”€β”€ cv-keyword-optimizer.json   # n8n workflow definition
β”œβ”€β”€ docker-compose.yml          # n8n container config
β”œβ”€β”€ .env                        # Environment variables (not committed)
β”œβ”€β”€ .env.example                # Template for .env
β”œβ”€β”€ .gitignore                  # Ignores .env
└── README.md                   # This file

Troubleshooting

Issue Solution
Ollama connection refused Make sure ollama serve is running. n8n reaches it via host.docker.internal:11434
Groq 429 rate limit Free tier has limits. Wait a minute and retry
Scraping fails on LinkedIn LinkedIn blocks scrapers. Paste the JD manually instead
Google Docs auth error Re-check OAuth2 credentials in n8n. Ensure correct scopes
Replacements don't apply The AI's "find" text must exactly match the CV. Check the Changes Summary for what was attempted
Empty response from Ollama Model may still be loading. First run takes longer. Timeout is set to 5 min