mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-11 09:27:41 +00:00
* fix(salary): split combined name-and-city workbook columns
The IDA demonstration workbook heads its company column "Firmanavn og by"
and stores "Ørsted A/S, Fredericia" in that one cell. After the header is
detected, convert_salary_excel copied the whole cell into company with
city "". salary_lookup --city only reads entry["city"], so the documented
lookup for Ørsted in Fredericia missed.
When the company header also names a city and there is no city column,
split the cell on the last ", ". A Company-only header still keeps commas
in the name.
* fix(salary): split a combined name-and-city cell on the last comma
Real IDA cells have no space after the separating comma
("Ørsted A/S,Fredericia"), and some company names contain ", "
themselves ("Rambøll Danmark A/S, Odense,Odense C"). Splitting on the
last ", " missed almost every real row, so --city still dropped out.
split_combined_company_city now splits on the last "," and strips both
parts. Test fixtures use the real unspaced cell shape, and a new unit
test covers a company name that contains a comma. The docstrings,
CHANGELOG entry, tools/README_SALARY_TOOL.md and the README salary
section describe the new split.
* docs(changelog): move the combined-city entry under Unreleased
The merge of master brought in the 1.7.3 release section, which left
this PR's Fixed entry under an already released version. Move it to
the Unreleased Fixed list.
* chore: drop the CHANGELOG hunk, the file is frozen since #800
Release notes are generated from PR titles now.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Mads Lorentzen <madslorentzen17@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
126 lines
4.4 KiB
Markdown
126 lines
4.4 KiB
Markdown
# Salary Benchmark Tool
|
|
|
|
## What is this?
|
|
|
|
The salary lookup tool (`salary_lookup.py`) lets you benchmark company salaries against a baseline from your own data. It's used during the `/apply` workflow to show how a company's compensation compares to market rates.
|
|
|
|
**This tool is optional.** If you don't have salary data, the salary step is simply skipped during `/apply`.
|
|
|
|
## How it works
|
|
|
|
The tool reads a `salary_data.json` file in the repo root containing company salary benchmarks. It uses fuzzy matching to find companies by name, handling Danish/Nordic characters, legal suffixes (A/S, ApS), and common spelling variations.
|
|
|
|
The data format supports any index-based or absolute salary data. For example:
|
|
- Index 100 = median salary, higher is better
|
|
- Absolute salary values in your currency
|
|
- Any custom metric you want to track
|
|
|
|
## Data format
|
|
|
|
The tool expects `salary_data.json` with this structure:
|
|
|
|
```json
|
|
{
|
|
"metadata": {
|
|
"source": "My Union Statistics 2025",
|
|
"index_baseline": 100,
|
|
"index_label": "Index",
|
|
"baseline_description": "Index 100 = median salary for private sector"
|
|
},
|
|
"companies": [
|
|
{
|
|
"company": "Novo Nordisk A/S",
|
|
"city": "Bagsværd",
|
|
"categories": {
|
|
"all_employees": { "count": 500, "index": 108.5 },
|
|
"engineering": { "count": 120, "index": 112.3 }
|
|
}
|
|
},
|
|
{
|
|
"company": "Ørsted A/S",
|
|
"city": "Fredericia",
|
|
"categories": {
|
|
"all_employees": { "count": 200, "index": 105.2 }
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### Fields
|
|
|
|
- **metadata.source**: Where the data comes from (for reference)
|
|
- **metadata.index_baseline**: The baseline value (e.g., 100 for index-based data)
|
|
- **metadata.index_label**: Label for the index column in output
|
|
- **metadata.baseline_description**: Human-readable explanation of the baseline
|
|
- **companies[].company**: Company name (required)
|
|
- **companies[].city**: City/location (optional, used for filtering)
|
|
- **companies[].categories**: Named salary categories, each with `count` and/or `index`
|
|
|
|
## Setup options
|
|
|
|
### Option A: Create salary_data.json manually
|
|
|
|
Create the file by hand with data from any source: union statistics, Glassdoor, salary surveys, networking, or personal research.
|
|
|
|
### Option B: Convert from Excel
|
|
|
|
If you have salary data in an Excel file:
|
|
|
|
```bash
|
|
pip install openpyxl
|
|
python3 tools/convert_salary_excel.py path/to/salary-data.xlsx \
|
|
--source "My Salary Data 2025" \
|
|
--baseline 100 \
|
|
--baseline-desc "Index 100 = median salary"
|
|
```
|
|
|
|
On Windows, use `py` if that is how Python is exposed on your PATH. If your system uses `python` instead of `python3`, substitute that in the examples.
|
|
|
|
The converter auto-detects the Excel layout:
|
|
- Looks for a "Company"/"Firma" column and an optional "City"/"By" column
|
|
- A combined header such as "Firmanavn og by" or "Company and City" (no separate city column) is split on the last comma, with both parts stripped, so `salary_lookup.py --city` can filter. Cells look like "Ørsted A/S,Fredericia"; a company name may itself contain ", " ("Rambøll Danmark A/S, Odense,Odense C")
|
|
- Treats remaining columns as salary data (auto-pairs count/index columns)
|
|
|
|
### Option C: Build from research
|
|
|
|
Start with an empty template and add companies as you research them:
|
|
|
|
```json
|
|
{
|
|
"metadata": {
|
|
"source": "Personal research",
|
|
"index_baseline": 0,
|
|
"index_label": "Monthly salary (DKK)",
|
|
"baseline_description": "Approximate monthly salary before tax"
|
|
},
|
|
"companies": [
|
|
{
|
|
"company": "Example Corp",
|
|
"city": "Copenhagen",
|
|
"categories": {
|
|
"entry_level": { "index": 42000 },
|
|
"senior": { "index": 55000 }
|
|
}
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
python3 salary_lookup.py "Novo Nordisk"
|
|
python3 salary_lookup.py "Ørsted" --city "Fredericia"
|
|
python3 salary_lookup.py "COWI" --json
|
|
python3 salary_lookup.py --list-all
|
|
python3 salary_lookup.py --validate # pre-flight check your salary_data.json
|
|
```
|
|
|
|
## Important notes
|
|
|
|
- The data file (`salary_data.json`) is **excluded from git** (see `.gitignore`). Your salary data may be proprietary or confidential.
|
|
- If the data file is missing, `salary_lookup.py` exits with a helpful error message and the `/apply` workflow skips the salary benchmark step.
|
|
- The fuzzy matcher handles Danish company name variations: legal suffixes, Nordic characters, anglicized spellings, and partial matches.
|
|
- `--validate` checks your data file for malformed category values and duplicate company names and prints a report, without performing a lookup.
|