SmartHire-AI / api /README.md
Vishu2006's picture
Initial commit: SmartHire-AI FastAPI + Streamlit
91e794e
|
Raw
History Blame Contribute Delete
6.23 kB

SmartHire AI β€” REST API Reference

Base URL: http://localhost:8000
Interactive Docs: http://localhost:8000/docs
Redoc: http://localhost:8000/redoc


Start the API

# Install new dependencies first (one time)
pip install fastapi uvicorn[standard] python-multipart

# Start the API server
uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload

# Or double-click RUN_API.bat on Windows

The Streamlit UI still runs separately:

streamlit run app/streamlit_app.py   # port 8501
uvicorn api.main:app --port 8000     # port 8000

Endpoints

Health

Method Endpoint Description
GET / Root β€” confirms server is running
GET /health Health check with timestamp
GET /model/info Loaded model metadata

Core Matching

POST /match

Match resumes against a job description. Returns ranked candidates.

Form fields:

Field Type Required Description
resumes File(s) βœ… PDF, DOCX, or TXT resume files
jd_text string one of JD as plain text
jd_file File one of JD as file
similarity_weight float ❌ 0.5–0.9, default 0.7

Example (JavaScript fetch):

const form = new FormData();
form.append("resumes", resumeFile1);
form.append("resumes", resumeFile2);
form.append("jd_text", "We are looking for a Python ML Engineer...");
form.append("similarity_weight", "0.7");

const res = await fetch("http://localhost:8000/match", {
  method: "POST",
  body: form,
});
const data = await res.json();

Response:

{
  "status": "success",
  "duration_sec": 1.23,
  "total_candidates": 2,
  "summary": {
    "total_candidates": 2,
    "average_score": 72.5,
    "highest_score": 85.0,
    "highly_recommended": 1,
    "recommended": 1,
    "consider": 0,
    "not_recommended": 0
  },
  "candidates": [
    {
      "rank": 1,
      "name": "John_Doe",
      "score_pct": 85.0,
      "semantic_similarity": 91.2,
      "skill_coverage_pct": 75.0,
      "recommendation": "Highly Recommended",
      "confidence": "High",
      "percentile_rank": 100.0,
      "matching_skills": ["python", "pytorch", "docker"],
      "missing_skills": ["kubernetes"],
      "critical_missing": [],
      "important_missing": ["kubernetes"],
      "resume_only_skills": ["flask", "pandas"],
      "ai_insight": "Strong contextual alignment..."
    }
  ],
  "parse_errors": []
}

Skills

POST /skills

Extract and compare skills from a single resume vs JD.

Form fields:

Field Type Required Description
resume File βœ… Resume file
jd_text string βœ… JD text

Response:

{
  "status": "success",
  "candidate": "John_Doe",
  "matching_skills": ["python", "pytorch"],
  "missing_skills": ["kubernetes"],
  "critical_missing": [],
  "skill_coverage_pct": 75.0,
  "weighted_coverage_pct": 80.0,
  "jd_skills": ["python", "pytorch", "kubernetes"],
  "resume_skills": ["python", "pytorch", "flask"]
}

Vector Index

POST /index/build

Encode and store resumes in the persistent vector index.

Field Type Required Description
resumes File(s) βœ… Resume files to index
rebuild bool ❌ Clear index first (default false)

POST /index/search

Instantly search the index for the best matching resumes.

Field Type Required Description
jd_text string one of JD text
jd_file File one of JD file
top_k int ❌ Number of results (default 5, max 20)

Response:

{
  "status": "success",
  "duration_ms": 12.4,
  "total_found": 2,
  "results": [
    {
      "rank": 1,
      "name": "John_Doe",
      "similarity_pct": 95.8,
      "indexed_at": "2026-07-01T20:29:18",
      "text_length": 1763,
      "embedding_dim": 768,
      "preview": "john doe machine learning engineer..."
    }
  ]
}

GET /index/info

Get index stats (count, backend, dim, etc.)

GET /index/candidates

List all indexed candidates with metadata.

POST /index/add

Add a single resume to the existing index without rebuilding.

DELETE /index/clear

Wipe the entire index.


Utilities

POST /parse

Parse a file and return raw + cleaned text. Good for debugging.

POST /embed

Encode any text and return its raw embedding vector.


Frontend Integration (React/Next.js example)

// api/smarthire.js

const BASE_URL = "http://localhost:8000";

// Match resumes against a JD
export async function matchResumes(resumeFiles, jdText, similarityWeight = 0.7) {
  const form = new FormData();
  resumeFiles.forEach(f => form.append("resumes", f));
  form.append("jd_text", jdText);
  form.append("similarity_weight", similarityWeight);

  const res = await fetch(`${BASE_URL}/match`, { method: "POST", body: form });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

// Build vector index
export async function buildIndex(resumeFiles, rebuild = false) {
  const form = new FormData();
  resumeFiles.forEach(f => form.append("resumes", f));
  form.append("rebuild", rebuild);

  const res = await fetch(`${BASE_URL}/index/build`, { method: "POST", body: form });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

// Search the vector index
export async function searchIndex(jdText, topK = 5) {
  const form = new FormData();
  form.append("jd_text", jdText);
  form.append("top_k", topK);

  const res = await fetch(`${BASE_URL}/index/search`, { method: "POST", body: form });
  if (!res.ok) throw new Error(await res.text());
  return res.json();
}

// Get model info
export async function getModelInfo() {
  const res = await fetch(`${BASE_URL}/model/info`);
  return res.json();
}

CORS

By default the API allows all origins (*).
For production, update allow_origins in api/main.py:

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://your-frontend.com"],
    ...
)