thereisnohr / ui /api_client.py
jbeiroa's picture
Initial clean deploy of demo app
74711df
import requests
import time
from typing import Any, Dict, List, Optional
class APIClient:
def __init__(self, base_url: str = "http://localhost:8000/api"):
self.base_url = base_url
def _get(self, endpoint: str, params: Optional[Dict] = None) -> Any:
response = requests.get(f"{self.base_url}/{endpoint}", params=params, timeout=120.0)
response.raise_for_status()
return response.json()
def _post(self, endpoint: str, json_data: Optional[Dict] = None) -> Any:
response = requests.post(f"{self.base_url}/{endpoint}", json=json_data, timeout=120.0)
response.raise_for_status()
return response.json()
# Tasks
def get_task(self, task_id: int) -> Dict:
return self._get(f"tasks/{task_id}")
def poll_task(self, task_id: int, interval: float = 2.0, timeout: int = 300) -> Dict:
start_time = time.time()
while time.time() - start_time < timeout:
task = self.get_task(task_id)
if task["status"] in ["COMPLETED", "FAILED"]:
return task
time.sleep(interval)
raise TimeoutError(f"Task {task_id} timed out after {timeout} seconds")
# Jobs
def list_jobs(self, skip: int = 0, limit: int = 100) -> List[Dict]:
return self._get("jobs/", params={"skip": skip, "limit": limit})
def get_job(self, job_id: int) -> Dict:
return self._get(f"jobs/{job_id}")
def create_job(self, title: str, description: str) -> Dict:
return self._post("jobs/", json_data={"title": title, "description": description})
def rank_job(self, job_id: int, top_k: int = 5) -> Dict:
return self._post(f"jobs/{job_id}/rank", json_data={"top_k": top_k})
# Candidates
def list_candidates(self, skip: int = 0, limit: int = 100) -> List[Dict]:
return self._get("candidates/", params={"skip": skip, "limit": limit})
def get_candidate(self, candidate_id: int) -> Dict:
return self._get(f"candidates/{candidate_id}")
# Ingest
def ingest_resumes(self, input_dir: str, pattern: str = "*.pdf") -> Dict:
return self._post("ingest/resumes", json_data={"input_dir": input_dir, "pattern": pattern})
def upload_resumes(self, files: List[Any]) -> Dict:
if not files:
raise ValueError("No files provided for upload")
payload = []
for file in files:
# We must use 'files' as the field name to match backend: list[UploadFile] = File(...)
payload.append(("files", (file.name, file.getvalue(), "application/pdf")))
url = f"{self.base_url}/ingest/upload"
try:
response = requests.post(url, files=payload, timeout=120.0)
if response.status_code != 200:
try:
detail = response.json().get("detail", response.text)
except:
detail = response.text
raise Exception(f"Upload failed ({response.status_code}) at {url}: {detail}")
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"Connection error to {url}: {e}")
# Matches
def list_matches(self, job_id: Optional[int] = None, skip: int = 0, limit: int = 100) -> List[Dict]:
params = {"skip": skip, "limit": limit}
if job_id:
params["job_id"] = job_id
return self._get("matches/", params=params)
def get_match(self, match_id: int) -> Dict:
return self._get(f"matches/{match_id}")
def generate_prep(self, match_id: int) -> Dict:
return self._post(f"matches/{match_id}/prep")