Skip to main content

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.

Metadata

Release files for jobs-radar 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for jobs-radar 0.1.2
File Size Uploaded
jobs_radar-0.1.2.tar.gz 133.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for jobs-radar 0.1.2
File Interpreter ABI Platform
jobs_radar-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 148.9 kB

Release files / jobs_radar-0.1.2.tar.gz

Download URL jobs_radar-0.1.2.tar.gz
Size 133.2 kB
Tags Source
SHA-256 checksum
How to use checksums
b7481f5f27dcd29a5bc1591de230b05fb656104e273efb8e020cc37c7b043dc9
BLAKE2b-256 checksum
How to use checksums
b018f375840114cef0dd6e86940a4db4d281f8eb760c01fa489965a11bd6092f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release files / jobs_radar-0.1.2-py3-none-any.whl

Download URL jobs_radar-0.1.2-py3-none-any.whl
Size 15.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
204180ee4ad679e493a94351802ce5012197f5671b79db6f82695553066cc319
BLAKE2b-256 checksum
How to use checksums
614a436de90434f5af696c3279ae1d85663b6debbc614f5534cf42c2ec2f1438
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page