Spaces:
No application file
No application file
File size: 3,054 Bytes
b2efd24 | 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 | """
FastAPI backend — optional REST API alongside Gradio UI.
Run: uvicorn main:app --host 0.0.0.0 --port 8000 --reload
"""
import os
import uuid
import io
from dotenv import load_dotenv
load_dotenv()
import pandas as pd
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from app.models.schemas import EvaluationRequest, EvaluationResponse, Candidate
from app.services.evaluation_service import perform_hybrid_evaluation
app = FastAPI(
title="AI Recruitment Engine",
description="Hybrid 5-stage candidate evaluation pipeline",
version="1.0.0",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)
# Simple in-memory cache (use Redis/DB in production)
_cache: dict = {}
@app.get("/health")
async def health():
return {"status": "ok", "service": "AI Recruitment Engine"}
@app.post("/upload-csv")
async def upload_csv(file: UploadFile = File(...)):
if not (file.filename or "").endswith(".csv"):
raise HTTPException(status_code=400, detail="Please upload a .csv file.")
try:
content = await file.read()
df = pd.read_csv(io.BytesIO(content)).fillna("")
candidates = []
for _, row in df.iterrows():
candidates.append(Candidate(
id=str(uuid.uuid4()),
name=str(row.get("name", "Unknown")),
email=str(row.get("email", "")),
skills=str(row.get("skills", row.get("parsed_skills", ""))),
experience=str(row.get("experience", row.get("parsed_work_experience", ""))),
projects=str(row.get("projects", "")),
education=str(row.get("education", row.get("parsed_metadata_education", ""))),
resume_text=str(row.get("resume_text", row.get("parsed_summary", ""))),
))
return {"count": len(candidates), "candidates": candidates}
except Exception as e:
raise HTTPException(status_code=500, detail=f"CSV parse error: {e}")
@app.post("/evaluate", response_model=EvaluationResponse)
async def evaluate(request: EvaluationRequest):
if not request.jd:
raise HTTPException(status_code=400, detail="Job Description is required.")
if not request.candidates:
raise HTTPException(status_code=400, detail="At least one candidate is required.")
response = await perform_hybrid_evaluation(request.jd, request.candidates)
for rank in response.shortlist:
_cache[rank.candidate_id] = rank.model_dump()
_cache.update(response.details)
return response
@app.get("/candidate/{candidate_id}")
async def get_candidate(candidate_id: str):
if candidate_id not in _cache:
raise HTTPException(status_code=404, detail="Candidate report not found.")
return _cache[candidate_id]
if __name__ == "__main__":
import uvicorn
uvicorn.run(
app,
host=os.getenv("APP_HOST", "0.0.0.0"),
port=int(os.getenv("APP_PORT", "8000")),
)
|