# AI Recruitment System — Complete Codebase Scaffold
This document contains a complete, runnable scaffold for the Agentic AI Recruitment
System described in your Phase 1 report. It is a monorepo-style structure with
example implementations, stubs where heavy models or paid APIs would be used, and
local-run options using Docker Compose.
> **Important**: This scaffold focuses on correctness, testability, and clear
integration points for large models (GPT-4/LLaMA/Whisper). For production use,
you'll need to provide model checkpoints, API keys, GPUs, and secure credentials.
---
## Repository structure
```
ai-recruitment/
├── backend/
│ ├── agents/
│ │ ├── resume_agent.py
│ │ ├── test_agent.py
│ │ ├── interview_agent.py
│ │ └── feedback_agent.py
│ ├── app/
│ │ └── [Link]
│ ├── [Link]
│ └── Dockerfile
├── frontend/
│ ├── [Link]
│ ├── [Link]
│ ├── pages/
│ │ ├── [Link]
│ │ └── api/[Link]
│ └── components/
│ └── [Link]
├── infra/
│ ├── [Link]
│ └── k8s/
│ ├── [Link]
│ └── [Link]
├── models/
│ ├── finetune_sbert.py
│ └── prompt_templates.md
├── data/
│ └── [Link]
└── [Link]
```
---
## How to use this scaffold (quick)
1. Install Docker & Docker Compose.
2. From repo root: `docker-compose up --build`
3. Backend services expose ports: ResumeAgent:5001, TestAgent:5002,
InterviewAgent:5003, FeedbackAgent:5004, Coordinator API:8000
4. Frontend will run on port 3000.
---
# Files & Code
Below are the key files with complete code. Save them into the file tree above.
---
## backend/[Link]
```text
fastapi==0.95.2
uvicorn[standard]==0.22.0
requests==2.31.0
pydantic==1.10.11
python-multipart==0.0.6
spacy==3.5.4
sentence-transformers==2.2.2
transformers==4.34.0
torch==2.2.0
sqlalchemy==1.4.52
psycopg2-binary==2.9.6
redis==4.7.0
milvus==2.3.0
python-dotenv==1.0.0
openai==1.0.0
scikit-learn==1.4.2
xgboost==1.7.6
shap==0.42.1
```
---
## backend/Dockerfile
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY [Link] ./
RUN pip install --no-cache-dir -r [Link]
COPY . /app
ENV PYTHONUNBUFFERED=1
CMD ["uvicorn", "[Link]:app", "--host", "[Link]", "--port", "8000"]
```
---
## backend/app/[Link]
```python
from fastapi import FastAPI, UploadFile, File, HTTPException
from pydantic import BaseModel
import requests
import os
# Agents endpoints (in docker-compose they will be routed)
RESUME_AGENT = [Link]('RESUME_AGENT_URL', '[Link]
TEST_AGENT = [Link]('TEST_AGENT_URL', '[Link]
INTERVIEW_AGENT = [Link]('INTERVIEW_AGENT_URL', '[Link]
FEEDBACK_AGENT = [Link]('FEEDBACK_AGENT_URL', '[Link]
app = FastAPI(title='Coordinator API')
class ShortlistRequest(BaseModel):
job_description: str
role: str
company_parameters: dict = {}
@[Link]('/upload_resume')
async def upload_resume(file: UploadFile = File(...)):
# Forward resume to Resume Agent
files = {'resume': ([Link], await [Link](), file.content_type)}
r = [Link](f"{RESUME_AGENT}/parse_resume", files=files)
if r.status_code != 200:
raise HTTPException(status_code=500, detail='Resume parsing failed')
return [Link]()
@[Link]('/create_test')
async def create_test(payload: ShortlistRequest):
r = [Link](f"{TEST_AGENT}/generate_test", json=[Link]())
return [Link]()
@[Link]('/conduct_interview')
async def conduct_interview(candidate_id: str, audio_file: UploadFile = File(...)):
files = {'audio': (audio_file.filename, await audio_file.read(),
audio_file.content_type)}
r = [Link](f"{INTERVIEW_AGENT}/analyze_audio?
candidate_id={candidate_id}", files=files)
return [Link]()
@[Link]('/final_feedback')
async def final_feedback(candidate_id: str, results: dict):
payload = {"candidate_id": candidate_id, "results": results}
r = [Link](f"{FEEDBACK_AGENT}/generate_feedback", json=payload)
return [Link]()
```
---
## backend/agents/resume_agent.py
```python
# Simple resume parsing microservice using spaCy and SBERT embeddings
from fastapi import FastAPI, UploadFile, File
import spacy
from sentence_transformers import SentenceTransformer
import tempfile
import json
app = FastAPI(title='Resume Agent')
# load spaCy model (ensure installed in environment)
try:
nlp = [Link]('en_core_web_trf')
except Exception:
# fallback to small model for local dev
import os
[Link]('python -m spacy download en_core_web_sm')
nlp = [Link]('en_core_web_sm')
embedder = SentenceTransformer('all-mpnet-base-v2')
@[Link]('/parse_resume')
async def parse_resume(resume: UploadFile = File(...)):
content = await [Link]()
text = [Link](errors='ignore')
doc = nlp(text)
# very simple extraction: names, skills (entity label WORK_OF_ART as proxy),
education heuristic
entities = [([Link], ent.label_) for ent in [Link]]
# naive skill extraction: top noun chunks
skills = list({[Link]() for chunk in doc.noun_chunks})[:50]
# compute embedding for resume
embedding = [Link]([text])[0].tolist()
result = {
'filename': [Link],
'text_snippet': text[:1000],
'entities': entities,
'skills': skills,
'embedding': embedding
}
return result
```
---
## backend/agents/test_agent.py
```python
from fastapi import FastAPI
from pydantic import BaseModel
import os
import openai
app = FastAPI(title='Test Agent')
openai.api_key = [Link]('OPENAI_API_KEY', None)
class TestRequest(BaseModel):
job_description: str
role: str
company_parameters: dict = {}
@[Link]('/generate_test')
async def generate_test(req: TestRequest):
# Use a prompt template to create an adaptive test. For local dev we return a
stub.
prompt = f"Generate 5 MCQs of varying difficulty for the role {[Link]} based
on: {req.job_description}"
if openai.api_key:
completion = [Link](
model='gpt-4o-mini',
messages=[{"role": "system", "content": "You are a test generator."},
{"role": "user", "content": prompt}],
max_tokens=800
)
text = [Link][0].[Link]
return {'generated_test': text}
else:
# stub test
return {'generated_test': [
{'q': 'What is Big O of binary search?', 'options': ['O(n)', 'O(log
n)', 'O(1)', 'O(n log n)'], 'answer': 'O(log n)'},
{'q': 'Which HTTP method is idempotent?', 'options': ['POST', 'PUT',
'PATCH', 'DELETE'], 'answer': 'PUT'}
]}
```
---
## backend/agents/interview_agent.py
```python
from fastapi import FastAPI, UploadFile, File
import os
app = FastAPI(title='Interview Agent')
@[Link]('/analyze_audio')
async def analyze_audio(candidate_id: str, audio: UploadFile = File(...)):
# For production: run Whisper transcription and RoBERTa-based emotion
detection.
# Here we accept audio and return a stubbed transcript + sentiment.
data = await [Link]()
# Save temporarily if needed
with open(f"/tmp/{candidate_id}_audio", 'wb') as f:
[Link](data)
# STUB: pretend we transcribed
transcript = "Hello, I am excited about this opportunity. I have worked on X, Y
and Z."
sentiment = {'emotion': 'positive', 'score': 0.88}
return {'candidate_id': candidate_id, 'transcript': transcript, 'sentiment':
sentiment}
```
---
## backend/agents/feedback_agent.py
```python
from fastapi import FastAPI
from pydantic import BaseModel
import os
import openai
app = FastAPI(title='Feedback Agent')
openai.api_key = [Link]('OPENAI_API_KEY', None)
class FeedbackRequest(BaseModel):
candidate_id: str
results: dict
@[Link]('/generate_feedback')
async def generate_feedback(req: FeedbackRequest):
# Create a personalized report using LLM. Use a stub if openai key missing.
prompt = f"Generate a short feedback report for candidate {req.candidate_id}
given results: {[Link]}"
if openai.api_key:
completion = [Link](
model='gpt-4o-mini',
messages=[{"role":"user","content":prompt}],
max_tokens=400
)
report = [Link][0].[Link]
return {'report': report}
else:
return {'report': f"Candidate {req.candidate_id} performed well in coding;
needs improvement in system design and communication."}
```
---
## backend/[Link] (in infra/[Link])
```yaml
version: '3.8'
services:
coordinator:
build: ../backend
container_name: coordinator
ports:
- "8000:8000"
environment:
- RESUME_AGENT_URL=[Link]
- TEST_AGENT_URL=[Link]
- INTERVIEW_AGENT_URL=[Link]
- FEEDBACK_AGENT_URL=[Link]
depends_on:
- resume-agent
- test-agent
- interview-agent
- feedback-agent
resume-agent:
build: ../backend
command: uvicorn agents.resume_agent:app --host [Link] --port 5001
container_name: resume-agent
test-agent:
build: ../backend
command: uvicorn agents.test_agent:app --host [Link] --port 5002
container_name: test-agent
interview-agent:
build: ../backend
command: uvicorn agents.interview_agent:app --host [Link] --port 5003
container_name: interview-agent
feedback-agent:
build: ../backend
command: uvicorn agents.feedback_agent:app --host [Link] --port 5004
container_name: feedback-agent
# Frontend service can be added similarly or run locally via `yarn dev` from
frontend/
```
---
## frontend/[Link]
```json
{
"name": "ai-recruitment-frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev -p 3000",
"build": "next build",
"start": "next start -p 3000"
},
"dependencies": {
"next": "13.5.7",
"react": "18.2.0",
"react-dom": "18.2.0",
"swr": "2.2.0",
"axios": "1.4.0"
}
}
```
---
## frontend/pages/[Link]
```jsx
import React, {useState} from 'react'
import axios from 'axios'
export default function Home(){
const [file, setFile] = useState(null)
const [result, setResult] = useState(null)
const upload = async ()=>{
if(!file) return alert('choose resume')
const fd = new FormData()
[Link]('file', file)
const r = await [Link]('[Link] fd, {headers:
{'Content-Type': 'multipart/form-data'}})
setResult([Link])
}
return (
<div style={{padding:40}}>
<h1>AI Campus Recruit — Demo</h1>
<input type="file" onChange={e=>setFile([Link][0])} />
<button onClick={upload}>Upload Resume</button>
<pre>{result && [Link](result, null, 2)}</pre>
</div>
)
}
```
---
## frontend/components/[Link]
```jsx
import React from 'react'
export default function Dashboard({data}){
return (
<div>
<h2>College Dashboard (Demo)</h2>
<p>Total candidates: {data?.total || 0}</p>
<p>Avg score: {data?.avg_score || 0}</p>
</div>
)
}
```
---
## models/finetune_sbert.py
```python
# Example script to fine-tune SBERT on domain-specific skill pairs
from sentence_transformers import SentenceTransformer, InputExample, losses
from [Link] import DataLoader
train_examples = [InputExample(texts=['python programming','python'], label=0.9),]
model = SentenceTransformer('all-mpnet-base-v2')
train_dataloader = DataLoader(train_examples, shuffle=True, batch_size=8)
train_loss = [Link](model)
[Link](train_objectives=[(train_dataloader, train_loss)], epochs=1)
[Link]('./models/sbert_finetuned')
```
---
## infra/k8s/[Link] (skeleton)
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: resume-agent
spec:
replicas: 1
selector:
matchLabels:
app: resume-agent
template:
metadata:
labels:
app: resume-agent
spec:
containers:
- name: resume-agent
image: your-registry/resume-agent:latest
ports:
- containerPort: 5001
```
---
## data/[Link]
```markdown
Resume JSON schema (example):
{
"filename": "...",
"text_snippet": "...",
"entities": [["Name","PERSON"]],
"skills": ["python","c++",...],
"embedding": [0.123, ...]
}
```
---
# Running locally (detailed)
1. Backend-only local run without Docker:
- Create venv: `python -m venv venv && source venv/bin/activate`
- `pip install -r backend/[Link]`
- Run coordinator: `uvicorn [Link]:app --reload --port 8000`
- Run agents (in separate terminals):
- `uvicorn [Link].resume_agent:app --reload --port 5001`
- `uvicorn [Link].test_agent:app --reload --port 5002`
- `uvicorn [Link].interview_agent:app --reload --port 5003`
- `uvicorn [Link].feedback_agent:app --reload --port 5004`
2. Frontend:
- `cd frontend && npm install && npm run dev`
- Open [Link]
3. Docker Compose (recommended for dev sandbox):
- `cd infra && docker-compose up --build`
---
# Next steps & integration notes
- Replace LLM stubs with production-grade models:
- For GPT-style generation, use OpenAI's GPT-4 / local Llama-3 with proper prompt
engineering.
- For speech -> use Whisper large v3 or a hosted ASR.
- For embeddings, run SBERT fine-tuning and persist vectors to Milvus.
- Add authentication (OAuth, JWT) and RBAC for dashboards.
- Implement SHAP and fairness monitoring in XGBoost ranking pipeline.
- Add persistent DB (Postgres) and Redis caching; update services to talk to DB.
- Add automated testing (PyTest) and CI pipelines (GitHub Actions).
---
# Final notes
This scaffold provides a complete, end-to-end starting point. It contains runnable
microservices and clear integration points for your model choices. If you'd like, I
can:
- Split this scaffold into individual files and provide a zip you can download.
- Replace the LLM stubs with working calls to a specific model you have access to
(OpenAI, Anthropic, or a local Llama checkpoint).
- Add database schemas, SQLAlchemy models and a sample dataset loader.
Tell me which of the above you'd like next and I'll produce it.