Spaces:
Sleeping
Sleeping
File size: 9,046 Bytes
cee0a62 14fdc5e cee0a62 14fdc5e cee0a62 14fdc5e cee0a62 14fdc5e cee0a62 14fdc5e | 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 | ---
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).
|