Recruitment_Copilot / README.md
Ashgen12's picture
Recruitment Copilot
14fdc5e verified
|
Raw
History Blame Contribute Delete
9.05 kB
---
title: Recruitment Copilot
emoji: 🎯
colorFrom: green
colorTo: blue
sdk: docker
app_port: 7860
pinned: false
license: mit
short_description: Agentic recruitment copilot for HR teams.
---
# Recruitment Copilot
An end-to-end agentic recruitment workspace built on **Google ADK** + **FastMCP**, with a Next.js chat UI rendered through the free **Crayon UI** components from the Thesys SDK.
It lets a recruiter:
- πŸ” Find candidates by natural-language queries (`"give me top AI engineers"`, `"anyone with NLP background"`).
- πŸ“„ Ingest scanned or text PDFs β€” Gemini OCR is used as a fallback when `pypdf` returns nothing.
- πŸ“‹ Pull all company HR policies in one click, rendered as a tabbed infographic with a donut chart.
- πŸ“ Draft a structured job posting from a chat brief β€” full markdown post + skill-weighting bar chart.
- πŸ“… Schedule interviews β€” auto-generates a Google Meet link, builds an `.ics`, and emails both attendees via SMTP.
- βœ‰οΈ Compose follow-up emails: the agent returns three tonal drafts (formal / casual / polite); pick one, give a recipient, and the email goes out via SMTP.
## Architecture
```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Netlify │───▢│ HF Spaces (Docker)│───▢│ Gemini API β”‚
β”‚ Next.js β”‚ β”‚ FastAPI + ADK + β”‚ β”‚ (LLM + OCR) β”‚
β”‚ frontend β”‚ β”‚ MCP server β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ”‚ Qdrant Cloud β”‚
β”‚ β”‚ (vector index) β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Άβ”‚ Supabase β”‚
β”‚ β”‚ Storage (PDFs) β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
└─────────────▢│ Gmail SMTP β”‚
β”‚ (app password) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```
### Backend
- **FastAPI** serves the chat SSE stream and proxies tool calls.
- **Google ADK** agent (`gemini-2.5-pro`) orchestrates 10 MCP tools.
- **FastMCP** exposes those tools over `/mcp-server/sse`:
| Tool | Purpose |
|---|---|
| `ingest_resume_pdf` | Parse a PDF (pypdf β†’ Gemini OCR fallback) and persist to SQLite + Qdrant |
| `semantic_candidate_search` | Vector search via Qdrant Cloud |
| `candidate_metadata_query` | Keyword search over local SQLite, role-aware filtering |
| `compute_job_match_score` | Score a single candidate against a JD |
| `get_policy_info` | Return company HR policies (donut + tabs UI) |
| `manage_application_status` | Track candidate stages |
| `manage_interview_records` | Schedule interviews + auto-email Google Meet invite |
| `generate_job_posting` | Draft a job posting from natural-language fields |
| `bulk_ingest_reference_resumes` | Bootstrap demo data |
| `email_compose` | Draft 3 tone variants β†’ send via SMTP |
### Frontend
- **Next.js 14** (App Router) with a streaming chat UI.
- **Crayon UI** (`@crayonai/react-ui`) for cards, callouts, charts (bar/pie/donut/radar), tabs, tags, buttons.
- A small **chart auto-picker** chooses bar / donut / radar based on the shape of the data the backend returns, so visualisations adapt to the response.
## Local development
### Prerequisites
- Python 3.11+
- Node.js 18+
- A Gemini API key β€” https://aistudio.google.com/apikey
### One-shot bring-up (Windows / PowerShell)
```powershell
copy .env.example .env # then fill in GEMINI_API_KEY at minimum
.\start-all.ps1
```
This installs dependencies, starts FastAPI on `http://127.0.0.1:7860` and Next.js on `http://127.0.0.1:3000`. Use `.\stop-all.ps1` to shut both down.
### Manual
```bash
# backend
cd backend
pip install -r requirements.txt
uvicorn main:app --host 0.0.0.0 --port 7860
# frontend (in another shell)
cd frontend
npm install
npm run dev
```
## Configuration
All runtime config is read from `.env`. See [`.env.example`](.env.example) for the full list with inline links to where each credential is generated.
| Group | Vars | Required for |
|---|---|---|
| Gemini | `GEMINI_API_KEY`, `GEMINI_MODEL`, `GEMINI_EMBEDDING_MODEL` | LLM, embeddings, scanned-PDF OCR |
| Qdrant | `QDRANT_URL`, `QDRANT_API_KEY`, `QDRANT_COLLECTION` | Semantic candidate search |
| Object storage | `S3_ENDPOINT`, `S3_ACCESS_KEY_ID`, `S3_SECRET_ACCESS_KEY`, `S3_BUCKET`, `S3_REGION`, optional `S3_PUBLIC_BASE_URL` | Persistent resume PDF storage (Supabase Storage / Backblaze / S3 / MinIO) |
| SMTP | `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_FROM`, `SMTP_USE_TLS` | Auto-email interview invites + composed emails |
| Misc | `BACKEND_URL`, `CALENDLY_EVENT_URL`, `THESYS_API_KEY` | Frontend β†’ backend wiring (Netlify), optional integrations |
## Deployment (free tier)
```
GitHub repo β†’ Netlify (frontend) ──▢ HF Space Docker (backend)
β”œβ”€β”€β–Ά Qdrant Cloud
β”œβ”€β”€β–Ά Supabase Storage
└──▢ Gmail SMTP
```
### 1. Backend on Hugging Face Spaces (Docker)
1. Create a new Space β†’ choose **Docker β†’ Blank**.
2. The repo's root [`Dockerfile`](Dockerfile) is picked up automatically.
3. In **Settings β†’ Variables and secrets**, add every key from `.env.example` (Gemini / Qdrant / S3 / SMTP). Set `CORS_ORIGINS=https://<your-netlify-site>.netlify.app`.
4. `git push` this repo to the Space remote β€” HF builds and exposes the API at `https://<user>-recruitment-copilot.hf.space`.
### 2. Frontend on Netlify
1. Import this repo in Netlify.
2. Set **Base directory** to `frontend`.
3. Add env var `BACKEND_URL=https://<user>-recruitment-copilot.hf.space`.
4. Deploy.
### 3. External services (all free, no card)
- **Qdrant Cloud** β€” https://cloud.qdrant.io β†’ 1 GB free cluster.
- **Supabase Storage** β€” https://supabase.com β†’ Free project β†’ create private `resumes` bucket β†’ Settings β†’ Storage β†’ S3 access keys.
- **Gemini API** β€” https://aistudio.google.com/apikey.
- **Gmail SMTP** β€” https://myaccount.google.com/apppasswords (requires 2-step verification).
## API surface
| Endpoint | Purpose |
|---|---|
| `GET /health` | Backend liveness |
| `GET /mcp-health` | List of registered MCP tools |
| `GET /api/tooling/status` | Reports which optional integrations are configured |
| `POST /api/upload?session_id=…` | Multipart PDF resume upload |
| `POST /api/chat` | SSE stream β€” chat with the agent |
| `GET /api/candidates/{external_id}` | Full candidate profile (markdown + card + chart) |
| `POST /api/bootstrap/sync-reference-resumes` | Copy sample PDFs into the project storage dir |
| `POST /api/bootstrap/reference-resumes` | Bulk-ingest the synced PDFs |
| `GET /mcp-server/sse` | MCP SSE stream endpoint |
| `POST /mcp-server/messages/?session_id=…` | MCP SSE message channel |
### SSE event contract (`/api/chat`)
| Event | Payload |
|---|---|
| `status` | `{ message }` |
| `token` | `{ delta }` (incremental text) |
| `genui` | `{ summary, markdown?, cards?, chart?, table?, tabs? }` |
| `done` | `{ message }` (final text) |
| `error` | `{ message }` |
## Project layout
```
.
β”œβ”€β”€ backend/
β”‚ β”œβ”€β”€ agent/ # Google ADK runtime + agent definition
β”‚ β”œβ”€β”€ core/ # Settings, DB session, models, schemas, utils
β”‚ β”œβ”€β”€ mcp_server/ # FastMCP server + 10 tool modules
β”‚ β”‚ └── tools/
β”‚ β”œβ”€β”€ services/ # Candidate / search / ingestion / storage / notifications
β”‚ β”œβ”€β”€ scripts/ # Reference-resume sync utilities
β”‚ └── main.py # FastAPI app + chat SSE stream
β”œβ”€β”€ frontend/
β”‚ └── src/
β”‚ β”œβ”€β”€ app/api/ # Next.js API proxy routes (chat, upload, candidates)
β”‚ └── components/ # Chat UI + Crayon-powered renderer
β”œβ”€β”€ Dockerfile # HF Spaces backend image
β”œβ”€β”€ start-all.ps1 / stop-all.ps1
β”œβ”€β”€ .env.example
β”œβ”€β”€ LICENSE
└── README.md
```
## License
MIT β€” see [LICENSE](LICENSE).