File size: 5,304 Bytes
363cda9 |
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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# API Layer π
> FastAPI backend decoupling agents from frontends.
## Quick Start
```bash
# 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:**
```json
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:
```python
# 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
- [x] Candidate database router
|