Spaces:
Sleeping
Sleeping
File size: 14,159 Bytes
7ff6662 945ae45 7ff6662 b15fd58 df898a6 b15fd58 df898a6 b15fd58 df898a6 7ff6662 b617fcc 53c490d b617fcc 7ff6662 b617fcc 7ff6662 b617fcc 7ff6662 f479a80 47b43eb 2a811e0 f479a80 7ff6662 4eafa75 7ff6662 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 | ---
title: JAA ATS Tool
emoji: π€
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false
license: mit
---
# Job Automation Agent β PM Edition
Automated Product Manager job search, AI-powered assessment, ATS-optimized resume generation, and Google Sheets reporting β all in one pipeline.
---
## What It Does
| Step | What Happens |
|------|--------------|
| 1 | Parses your PDF resume (Kimi-K2.6, ~5s) |
| 2 | Scrapes PM-only jobs from **LinkedIn, Indeed, Glassdoor, Remotive, WeWorkRemotely** β ALL selected roles Γ locations, last N days |
| 3 | Filters non-PM roles at scrape time; dedup by URL + (title, company) + 30-day SQLite history; platform-level total cap |
| 4 | Fetches FULL job descriptions in bulk (parallel HTTP / single browser session) |
| 5 | Assesses ALL jobs using 7 parallel AI models (10-model pool via NVIDIA API) |
| 6 | Generates ATS-optimized resumes for ALL jobs β DOCX **and PDF**, After β₯ Before guaranteed, target 95% |
| 7 | Writes everything to your Google Sheet with direct job links |
| 8 | Saves local Excel report + resumes in `data/output/resumes/YYYY-MM-DD/` |
| 9 | Saves run to history β reload past runs in one click from the History panel |
---
## Quick Start
```powershell
# 1. Install dependencies
pip install -r requirements.txt
playwright install chromium
# 2. Copy and fill in your API keys
copy .env.example .env
# Edit .env with your NVIDIA_API_KEY, GOOGLE_SHEET_ID, etc.
# 3. Place your resume PDF
# Copy your resume to: data/resume/resume.pdf
# 4. Connect Google (one-time browser login)
python connect_google.py
# 5. Run a test (5 jobs)
# In config.py: ASSESSMENT["test_mode"] = True
python main.py
# 6. Run full production mode (all 100+ PM jobs)
# In config.py: ASSESSMENT["test_mode"] = False
python main.py
# 7. Or use the Streamlit UI
streamlit run ui.py
```
---
## ever-jobs Integration (160+ Platforms)
This project integrates the [ever-jobs](https://github.com/ever-jobs/ever-jobs) NestJS service, which provides REST API access to 160+ job board scrapers.
### Prerequisites
- **Docker Desktop** (preferred): [Install Docker Desktop](https://docs.docker.com/desktop/install/windows-install/)
- OR **Node.js 24.x** for npm subprocess fallback
### Setup (one-time)
```bash
# Clone ever-jobs to vendor/ directory (done automatically during setup)
git clone https://github.com/ever-jobs/ever-jobs.git vendor/ever-jobs --depth=1
# Start via Docker (preferred)
cd vendor/ever-jobs && docker compose up -d
# Verify API is running
curl http://localhost:3001/health
# OR from Python:
python -c "from src.ever_jobs_bridge.server import is_running; print(is_running())"
```
### Automatic Startup
The pipeline calls `ensure_running()` automatically before any ever-jobs platforms are scraped. It tries Docker first, falls back to `npm run start` if Docker is unavailable.
### Platform Selection
The UI has a single **"π Job Platforms"** section with three groups. Selecting LinkedIn, Indeed, Glassdoor, Remotive, WeWorkRemotely, or Naukri uses their dedicated high-quality scrapers; all other platforms go through the ever-jobs REST API.
| Group | Count | Description |
|-------|-------|-------------|
| Search Boards | 94 | General job boards. India-relevant defaults pre-selected. |
| ATS Platforms | 37 | Greenhouse, Lever, Workday etc. β companies post jobs here. NOT resume scoring. |
| Company Pages | 39 | Direct career pages (Flipkart, Swiggy, Amazon, Google, etc.) |
**India default platforms:** linkedin, naukri, indeed, glassdoor, google, bdjobs, internshala, bayt, iimjobs, foundit
### ATS Clarification
> **Important:** "ATS" in ever-jobs means Applicant Tracking System **PLATFORMS**
> (tools companies use to post jobs, like Greenhouse or Lever).
> It does **NOT** mean ATS resume scoring.
>
> Our ATS resume scoring (`src/ats_scorer.py`) uses a 70% JD keyword match +
> 30% resume quality hybrid and is **NOT changed** by this integration.
### Performance Notes
| Selection | Expected Time |
|-----------|---------------|
| Default 10 platforms | ~1β3 minutes |
| 30 platforms | ~3β5 minutes |
| 100+ platforms | 5β10 minutes (warning shown in UI) |
Playwright-based scrapers (some company pages) are inherently slower than API-based boards.
### Cross-Platform Deduplication
In addition to URL-based dedup, a **content fingerprint** (SHA-256 of normalized title+company) catches cross-platform duplicates. For example, the same "Product Manager at Google" posting on LinkedIn AND Greenhouse (different URLs) is detected and deduplicated.
---
## Project Structure
```
Job Automation Agent/
βββ main.py # Main pipeline (6-step orchestrator)
βββ config.py # All configuration β models, platforms, ATS settings
βββ ui.py # Streamlit UI (4 tabs: Search, Results, Job Details, Research)
βββ connect_google.py # One-time Google OAuth setup
βββ setup_google.py # Service account alternative
βββ requirements.txt
βββ .env # API keys (never commit)
βββ .env.example # Template for .env
β
βββ src/
β βββ resume_parser.py # PDF β plain text (pdfplumber)
β βββ llm_client.py # GLM 5.1 wrapper (profile extract, resume customize)
β βββ model_pool.py # 10-model parallel AI pool (NVIDIA API)
β βββ job_assessor.py # Phase 1 keyword scoring + Phase 2 LLM assessment
β βββ job_history.py # SQLite dedup store (data/job_history.db)
β βββ ats_scorer.py # Hybrid ATS scoring (70% JD match + 30% quality)
β βββ resume_customizer.py # LLM-tailored DOCX resume generator
β βββ gsheets.py # Google Sheets + Drive upload
β βββ excel_reporter.py # Local Excel report
β βββ odysseus_llm_core.py # Deep research LLM core
β β
β βββ ever_jobs_bridge/ # ever-jobs NestJS REST API adapter
β β βββ __init__.py # Package init
β β βββ server.py # Docker/npm server lifecycle (start/stop/health)
β β βββ client.py # HTTP client for POST /api/jobs/search
β β βββ mapper.py # IJob JSON β Job dataclass mapper
β β βββ platforms.py # 170 platform catalog with group metadata
β β
β βββ scrapers/
β β βββ base.py # Job dataclass + BaseScraper + is_pm_role() filter
β β βββ linkedin.py # LinkedIn scraper (requests + BeautifulSoup)
β β βββ indeed.py # Indeed scraper (Playwright for JS rendering)
β β βββ glassdoor.py # Glassdoor scraper (Playwright)
β β βββ naukri.py # Naukri (disabled β blocked by Akamai)
β β βββ ever_jobs.py # EverJobsScraper (REST adapter for 160+ platforms)
β β
β βββ research/
β βββ deep_researcher.py # Odysseus IterResearch engine (ThinkβSearchβExtractβSynthesize)
β βββ search.py # DuckDuckGo + Bing fallback, 12h cache
β
βββ data/
βββ resume/resume.pdf # Your resume (add this)
βββ job_history.db # Dedup SQLite DB (auto-created)
βββ research_cache/ # 12h DuckDuckGo result cache
βββ output/
βββ resumes/ # Generated DOCX resumes (Company_JobTitle.docx)
βββ reports/ # Excel reports
```
---
## Configuration (`config.py`)
### AI Models (10-model pool via NVIDIA API)
| Model | Speed | Phase 2 | Notes |
|-------|-------|---------|-------|
| Kimi-K2.6 | ~5s/batch | β
| Fastest, handles most work |
| Step-3.7-Flash | ~8-35s | β
| |
| Qwen3.5-397b | ~9s | β
| |
| Qwen3.5-122b-v2 | ~12s | β
| |
| GPT-OSS-120b | ~11s | β
| |
| Qwen3.5-122b | ~40s | β
| |
| DeepSeek-v4-Pro | ~42s | β
| |
| DeepSeek-v4-Flash | ~229s | β | Too slow for phase 2 |
| GLM-5.1 | ~234s | β | Used for resume parsing only |
| MiniMax-M2.7 | ~908s | β | Blocked/rate-limited |
### Key Settings
```python
ASSESSMENT = {
"min_score_for_llm_resume": 6, # LLM-tailored resume for score >= this
"generate_all_resumes": True, # Template resume for ALL PM jobs
"max_llm_resumes": 30, # Max LLM resumes per run
"dedup_days": 30, # Skip jobs seen in last 30 days
"test_mode": True, # β Set False for full production run
"test_jobs_limit": 5, # Max jobs in test mode
}
```
---
## ATS Scoring Method
Hybrid scoring: **70% JD Match + 30% Resume Quality**
- **JD Match (70%)**: Extract keywords FROM the specific job description β match against resume using word-boundary regex (`(?<!\w)kw(?!\w)`) β same approach as Resume-Matcher
- **Resume Quality (30%)**: 6-factor structural analysis (measurable achievements, contact info, education, etc.)
- **Iterative optimization**: Up to 3 LLM attempts to push score up, gap report fed back each iteration
- **Fallback**: `_inject_missing_keywords()` weaves still-missing terms naturally
### Keyword extraction is JD-driven, skills-only, and honest (industry standard)
- Keywords are extracted **from each JD itself** (not a fixed stored list), but
**skills-only**: a term is kept only if it's a recognised skill/tool/method/
domain/soft-skill in our gazetteer. Prose nouns (Goals, Authority, Enterprise,
Productivityβ¦) can never become "keywords" β exactly how real checkers like
Jobalytics work (they match against a curated skills list, not every word).
- **Dedicated, categorized SKILLS section** (Tools & Analytics / Methodologies /
Domains / Core Competencies) β the #1 ATS keyword vehicle, placed after the
summary, parsed and counted by Jobalytics/Resume Worded.
- **Quality over quantity**: cover the JD's real skills (~20β26), each 1β3Γ,
across the skills section + summary + woven bullets. Best practice is 15β25
keywords at 60β80% coverage β NOT 100 stuffed terms.
- **No cap, distributed smartly.** Every meaningful missing keyword is kept β
woven into relevant bullets first (the ideal, never-penalised place), then any
remainder spread across several short sentences (each its own paragraph, β€10
items). A single long comma-dump is *deliberately not* produced:
`_strip_keyword_spam` removes any 15+-separator line before scoring, exactly as
real ATS checkers and recruiters discount stuffing β so distributing keeps them
all counted without looking like spam.
- **Buzzwords removed.** Vague abstractions (innovation, solutions, tools,
leadership, leverage, scalableβ¦) are never injected β real checkers like Resume
Worded penalise them.
- **Honest expectation:** 90%+ is reached on JDs that genuinely fit the
candidate's background. Out-of-domain JDs score honestly lower β that reflects
reality (and matches third-party checkers), rather than a faked number.
- The displayed score is a **conservative estimate** (leans low vs our raw
internal coverage); always verify the final resume on Jobalytics/Simplify.
**Benchmark results** (correctly differentiates β full resume + capable LLM):
- In-domain PM JDs (Airtel, generic PM) β ~83β87
- Out-of-domain JDs (SecOps, lending) β ~60β70, honestly
---
## Google Sheet Columns
| Column | Description |
|--------|-------------|
| Batch Date | When the run happened |
| Rank | Score rank within this batch |
| Job Title / Company / Location | Job details |
| Platform | LinkedIn / Indeed / Glassdoor |
| Relevance Score | AI assessment (1β10) |
| ATS Before (%) | ATS score on original resume |
| ATS After (%) | ATS score on tailored resume |
| ATS Improvement | After β Before |
| Resume Quality | Structural quality score |
| Priority | High / Medium / Low |
| Matching / Missing Skills | Gap analysis |
| AI Recommendation | LLM reasoning |
| Apply Link | Direct job URL (clickable) |
| Resume Link | Google Drive link to tailored resume |
| Application Status | Dropdown: Not Applied β Offer |
---
## Environment Variables (`.env`)
```
NVIDIA_API_KEY=nvapi-... # GLM 5.1 + primary key
NVIDIA_API_KEY_2=nvapi-... # DeepSeek-v4-Pro, MiniMax
NVIDIA_API_KEY_3=nvapi-... # Kimi-K2.6
NVIDIA_API_KEY_4=nvapi-... # Qwen3.5-122b
NVIDIA_API_KEY_5=nvapi-... # GPT-OSS-120b
NVIDIA_API_KEY_6=nvapi-... # DeepSeek-v4-Flash
NVIDIA_API_KEY_7=nvapi-... # Qwen3.5-397b, Qwen3.5-122b-v2
NVIDIA_API_KEY_8=nvapi-... # Step-3.7-Flash
GOOGLE_SHEET_ID=1Ehxt3eo... # Your Google Sheet ID
RESUME_PATH=data/resume/resume.pdf
```
---
## Logging & Debugging
Every pipeline run writes a timestamped log to `data/logs/run_YYYY-MM-DD_HH-MM-SS.log`.
To diagnose failures:
1. Run a search from the UI
2. Switch to the **π Logs** tab
3. Errors show in red, warnings in yellow
4. Use **Download Full Log File** to share or inspect offline
5. Previous runs are also listed in the selector
The log captures:
- Every scrape attempt (role, location, raw result count)
- Full Python tracebacks on any exception
- All `print()` output from scrapers and LLM clients
- Playwright browser output
---
## Known Issues / Pending
| Issue | Status | Notes |
|-------|--------|-------|
| Google Drive upload `'Client' object has no attribute 'auth'` | Pending fix | gspread auth method mismatch |
| LLM resumes = 0 (GLM timeout during customization) | Pending fix | Switch to Kimi/Step for resume generation |
| Naukri blocked by Akamai | Permanent skip | Returns 406 / "Access Denied" with Playwright |
| Google OAuth "Access blocked" | Fixed | Add email as test user at GCP console |
---
## Running the UI
```powershell
streamlit run ui.py
# Opens at http://localhost:8501
# Tabs:
# 1. Search β configure and run the full pipeline
# 2. Results β view all assessed jobs with scores
# 3. Job Details β expand any job for full AI breakdown
# 4. Deep Research β Odysseus engine to research companies
```
|