Skip to main content

Personalised job search pipeline: scrape, rank, and rate jobs against your resume

Project description

Jobs Radar

Personalised job search pipeline: scrape → tag → embed → rank → rate.

Features

  • Resume parsing — paste raw resume text, get structured output (target roles, skills, seniority, experience) via OpenAI structured outputs
  • Parallel scraping — scrapes Indeed across multiple queries and locations concurrently using ThreadPoolExecutor
  • Dedup + tagging — removes duplicate listings, tags each job for seniority, entry-level, remote, clearance, and experience range using regex
  • Hybrid vector search — dense (BGE) + sparse (BM25) search with Reciprocal Rank Fusion via Qdrant in-memory
  • LLM-as-judge rating — each result is scored 1–10 against the candidate's resume using gpt-4o-mini
  • Feedback loop — rate jobs 1–5 stars; liked/disliked examples are injected into the judge prompt on future searches to personalise ratings over time
  • Single-table persistence — search results and user feedback live in one SQLite table (job_results), keyed by job_url; re-submitting feedback updates the row, no duplicates
  • CSV export — every scrape is auto-saved to ~/.jobs-radar/jobs_{timestamp}.csv, downloadable from the UI
  • Streamlit UI — parse resume, search jobs with inline feedback, browse and rate recent results
  • REST API — FastAPI backend, useful for scripting or other clients

Stack

  • Python 3.12, FastAPI, Streamlit
  • OpenAI API (gpt-4o-mini by default)
  • Qdrant (in-memory) + fastembed
  • jobspy (Indeed scraping)
  • SQLite (results + feedback storage)
  • uv (dependency management)

Installation

pip install jobs-radar
# or with uv
uv add jobs-radar

Or run from source:

git clone https://github.com/your-username/jobs-radar
cd jobs-radar
uv sync

Setup

cp .env.example .env  # fill in OPENAI_API_KEY

Data (SQLite DB + CSVs) is stored in ~/.jobs-radar/ by default. Override with DATA_DIR in your .env.

Running

You need two terminals — one for the API server and one for the UI.

From a pip/uv install:

# terminal 1 — start the API server
jobs-radar-serve

# terminal 2 — open the UI
jobs-radar-ui

From source:

# terminal 1 — API
uvicorn jobs_radar.main:app --reload

# terminal 2 — UI
streamlit run jobs_radar/ui.py

Then open http://localhost:8501 in your browser. API docs at http://localhost:8000/docs.

Configuration

All settings are read from environment variables or a .env file:

Variable Default Description
OPENAI_API_KEY Required
DATA_DIR ~/.jobs-radar Where SQLite DB and CSVs are stored
API_HOST 0.0.0.0 FastAPI bind host
API_PORT 8000 FastAPI port
API_BASE http://localhost:8000 URL the Streamlit UI uses to reach the API

API Endpoints

Method Path Description
POST /parse Parse resume text → structured profile
POST /search Scrape, embed, rank, and rate jobs
GET /results/recent Load the most recent search results
POST /feedback Save user rating for a job

Project Structure

jobs_radar/
  main.py          # FastAPI routes
  pipeline.py      # scrape, dedup, tag, validate
  vector_store.py  # Qdrant setup, upsert, hybrid search
  llm.py           # resume parsing, job rating, judge prompt
  feedback.py      # SQLite — job_results table, save/load functions
  models.py        # Pydantic models
  config.py        # pydantic-settings — all env/config vars
  cli.py           # jobs-radar-serve and jobs-radar-ui entrypoints
  ui.py            # Streamlit UI
tests/             # pytest suite (54 tests)

Data Model

All results and feedback share one SQLite table (~/.jobs-radar/feedback.db):

Column Source
job_url (PK) scraper
title, company, location, ... scraper
llm_rating, relevance_score, llm_reasoning system
user_rating, notes user feedback
search_id, saved_at system

Re-running a search updates system fields for any URL already in the DB while preserving user_rating and notes.

Notes

  • Qdrant runs in-memory — the vector index is not persisted between server restarts. The SQLite DB and CSV exports are the durable layer.
  • fastembed downloads model weights on the first upsert_jobs call (~30–60s). Subsequent calls are fast.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jobs_radar-0.1.2.tar.gz (133.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jobs_radar-0.1.2-py3-none-any.whl (15.6 kB view details)

Uploaded Python 3

File details

Details for the file jobs_radar-0.1.2.tar.gz.

File metadata

  • Download URL: jobs_radar-0.1.2.tar.gz
  • Upload date:
  • Size: 133.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for jobs_radar-0.1.2.tar.gz
Algorithm Hash digest
SHA256 b7481f5f27dcd29a5bc1591de230b05fb656104e273efb8e020cc37c7b043dc9
MD5 4ea70c8168e382788acda4ae280c8243
BLAKE2b-256 b018f375840114cef0dd6e86940a4db4d281f8eb760c01fa489965a11bd6092f

See more details on using hashes here.

File details

Details for the file jobs_radar-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: jobs_radar-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 15.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for jobs_radar-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 204180ee4ad679e493a94351802ce5012197f5671b79db6f82695553066cc319
MD5 6ecdeb4e5db869f627bbdeae81c4f73c
BLAKE2b-256 614a436de90434f5af696c3279ae1d85663b6debbc614f5534cf42c2ec2f1438

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page