--- 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://.netlify.app`. 4. `git push` this repo to the Space remote β€” HF builds and exposes the API at `https://-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://-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).