owenkaplinsky's picture
update from github stable code (#3)
3370983 verified
|
raw
history blame
5.3 kB

API Layer πŸ”Œ

FastAPI backend decoupling agents from frontends.

Quick Start

# Local
uvicorn src.api.app:app --reload --port 8080

# Docker
docker compose --env-file .env -f docker/docker-compose.yml up supervisor_api

Docs: http://localhost:8080/docs

Endpoints

Supervisor Agent /api/v1/supervisor

Method Endpoint Description
POST /chat Batch response with context compaction
POST /chat/stream SSE streaming with context compaction ⚠️
POST /raw/chat Batch response, direct agent (no compaction)
POST /raw/chat/stream SSE streaming, direct agent ⚠️
POST /new Create new chat session
GET /health Health check

⚠️ Note: Streaming endpoints have known issues. Use batch endpoints (/chat or /raw/chat) for reliable operation.

With vs Raw endpoints:

  • /chat and /chat/stream use CompactingSupervisor wrapper (auto context management)
  • /raw/chat and /raw/chat/stream bypass wrapper (direct agent access, useful for debugging)

Streaming (SSE) events:

event: token    β†’ {"content": "Hello"}
event: done     β†’ {"thread_id": "abc123", "token_count": 150}
event: error    β†’ {"error": "Something went wrong"}

CV Upload /api/v1/cv

Method Endpoint Description
POST /submit Submit application + CV
GET /health Health check

Submit flow:

  1. Save CV file to disk
  2. Register candidate in DB
  3. Parse CV β†’ Markdown (GPT-4 Vision)
  4. Update parsed path in DB

Database /api/v1/db

Method Endpoint Description
POST /query Flexible query any table
GET /candidates List candidates with filters
GET /candidates/{id} Get full candidate profile by UUID
GET /candidates/email/{email} Get full candidate profile by email
GET /cv-screening List CV screening results
GET /voice-screening List voice screening results
GET /interviews List interview scheduling
GET /decisions List final decisions
GET /stats Database statistics
GET /health Health check

Full Candidate Profile (/candidates/{id} and /candidates/email/{email}):

Returns ALL data for a candidate including related records (by default include_relations=true):

  • Base fields: id, full_name, email, phone_number, cv_file_path, parsed_cv_file_path, status, created_at, updated_at
  • cv_screening_results: list of CV screening scores and feedback
  • voice_screening_results: list of voice screening transcripts and scores
  • interview_scheduling: list of scheduled interviews
  • final_decision: hiring decision with rationale (if any)

Use ?include_relations=false to fetch only base candidate fields.

Flexible Query Example:

POST /api/v1/db/query
{
    "table": "candidates",
    "filters": {"status": "applied"},
    "fields": ["id", "full_name", "email"],
    "include_relations": true,
    "limit": 10,
    "offset": 0,
    "sort_by": "created_at",
    "sort_order": "desc"
}

Supported filter operators:

  • $eq, $ne: equality/inequality
  • $gt, $gte, $lt, $lte: comparisons
  • $in, $nin: list membership
  • $like, $ilike: pattern matching

Structure

src/api/
β”œβ”€β”€ app.py              ← FastAPI app + CORS + router mounting
β”œβ”€β”€ routers/
β”‚   β”œβ”€β”€ supervisor.py   ← Chat endpoints (regular + streaming)
β”‚   β”œβ”€β”€ cv_upload.py    ← CV submission endpoint
β”‚   └── database.py     ← Flexible database query endpoints
└── schemas/
    β”œβ”€β”€ supervisor_chat.py  ← ChatRequest, ChatResponse
    β”œβ”€β”€ cv_upload.py        ← SubmitResponse
    └── database.py         ← QueryRequest, QueryResponse, etc.

SDK Clients

Frontends use SDK clients instead of raw HTTP:

# Supervisor
from src.sdk import SupervisorClient
client = SupervisorClient()
for chunk in client.stream("Show candidates", thread_id):
    print(chunk.content)

# CV Upload
from src.sdk import CVUploadClient
client = CVUploadClient()
response = client.submit(name, email, phone, cv_file, filename)

# Database Queries
from src.sdk import DatabaseClient
db = DatabaseClient()

# List candidates
candidates = db.get_candidates(status="applied", include_relations=True)
for c in candidates.data:
    print(c["full_name"], c["status"])

# Get full candidate profile by email
profile = db.get_candidate_by_email("ada@example.com")
print(profile.data["cv_screening_results"])

# Flexible query with filters
results = db.query(
    table="cv_screening_results",
    filters={"overall_fit_score": {"$gte": 0.8}},
    sort_by="overall_fit_score",
    sort_order="desc"
)

# Get database stats
stats = db.get_stats()
print(stats.stats["candidates"]["by_status"])

Environment

Variable Default Used By
OPENAI_API_KEY required Validated at startup
CV_UPLOAD_PATH src/database/cvs/uploads CV router
CV_PARSED_PATH src/database/cvs/parsed CV router
POSTGRES_* varies Database connection

TODO

  • Voice agent router
  • Candidate database router