Why: - Long benchmark and process runs block HTTP clients; task #20 required async execution. Changes: - SQLite jobs table + GET /jobs and GET /jobs/{id} - POST /benchmarks?background=true and POST /documents/{id}/process?background=true return 202 + job_id - FastAPI BackgroundTasks execute work in-process; sync paths unchanged Impact: - Jobs are lost on server restart (Option A, no external queue) Co-authored-by: Cursor <cursoragent@cursor.com>
342 lines
5.7 KiB
Markdown
342 lines
5.7 KiB
Markdown
# API Reference
|
|
|
|
Complete documentation of all REST API endpoints.
|
|
|
|
---
|
|
|
|
## Base URL
|
|
|
|
```
|
|
http://localhost:8000
|
|
```
|
|
|
|
---
|
|
|
|
## Endpoints
|
|
|
|
### Documents
|
|
|
|
#### `GET /documents`
|
|
|
|
List all uploaded documents.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"items": [
|
|
{
|
|
"id": "doc-abc123",
|
|
"filename": "insurance.docx",
|
|
"paragraph_count": 245,
|
|
"chunk_counts": {
|
|
"recursive": 218,
|
|
"fixed_size": 117
|
|
},
|
|
"created_at": "2026-07-25T10:00:00"
|
|
}
|
|
],
|
|
"total": 1,
|
|
"offset": 0,
|
|
"limit": 50
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### `POST /documents`
|
|
|
|
Upload a document (.docx or .doc).
|
|
|
|
**Request:**
|
|
- Content-Type: `multipart/form-data`
|
|
- Body: `file` (binary)
|
|
|
|
**Response (201):**
|
|
```json
|
|
{
|
|
"id": "doc-abc123",
|
|
"filename": "insurance.docx",
|
|
"paragraph_count": 245,
|
|
"chunk_counts": {},
|
|
"created_at": "2026-07-25T10:00:00"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### `DELETE /documents/{doc_id}`
|
|
|
|
Delete a document and its vectors.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"deleted": true,
|
|
"document_id": "doc-abc123"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### `POST /documents/{doc_id}/process`
|
|
|
|
Run chunking strategies on a document.
|
|
|
|
**Query parameters:**
|
|
- `background` (bool, default `false`) — when `true`, enqueue processing and return **202** with a `job_id`; poll `GET /jobs/{job_id}`.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"strategies": [
|
|
"recursive",
|
|
"fixed_size",
|
|
"semantic",
|
|
"contextual_retrieval",
|
|
"semantic_parent_child"
|
|
]
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"document_id": "doc-abc123",
|
|
"strategies_completed": [
|
|
{
|
|
"strategy": "recursive",
|
|
"status": "completed",
|
|
"chunks_produced": 218
|
|
}
|
|
],
|
|
"strategies_failed": []
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Strategies
|
|
|
|
#### `GET /strategies`
|
|
|
|
List all available chunking strategies.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"strategies": [
|
|
{
|
|
"name": "recursive",
|
|
"description": "Cascade splitting: headers > double newline > ..."
|
|
},
|
|
{
|
|
"name": "fixed_size",
|
|
"description": "Fixed-size token splitting with overlap"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Queries
|
|
|
|
#### `POST /queries`
|
|
|
|
Ask a question against a document using a specific strategy.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"document_id": "doc-abc123",
|
|
"strategy": "recursive",
|
|
"question": "What are the main topics?",
|
|
"top_k": 5
|
|
}
|
|
```
|
|
|
|
**Response (201):**
|
|
```json
|
|
{
|
|
"query_id": "q-xyz789",
|
|
"document_id": "doc-abc123",
|
|
"strategy": "recursive",
|
|
"question": "What are the main topics?",
|
|
"answer": "The document covers insurance regulations...",
|
|
"retrieved_chunks": [
|
|
{
|
|
"chunk_id": "recursive_doc_000045",
|
|
"score": 0.892,
|
|
"text": " chunk content...",
|
|
"parent_id": null
|
|
}
|
|
],
|
|
"latency_breakdown": {
|
|
"embed_seconds": 0.15,
|
|
"search_seconds": 0.02,
|
|
"answer_seconds": 1.23,
|
|
"total_seconds": 1.40
|
|
},
|
|
"token_usage": {
|
|
"prompt_tokens": 1250,
|
|
"completion_tokens": 150,
|
|
"total_tokens": 1400
|
|
},
|
|
"created_at": "2026-07-25T12:00:00"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### `GET /queries/{query_id}`
|
|
|
|
Retrieve a past query.
|
|
|
|
**Response:** Same as POST /queries response.
|
|
|
|
---
|
|
|
|
### Benchmarks
|
|
|
|
#### `POST /benchmarks`
|
|
|
|
Run a benchmark comparing multiple strategies.
|
|
|
|
**Query parameters:**
|
|
- `background` (bool, default `false`) — when `true`, enqueue the run and return **202** with a `job_id`; poll `GET /jobs/{job_id}` for status and result.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"document_id": "doc-abc123",
|
|
"strategies": ["recursive", "fixed_size", "semantic"],
|
|
"questions_file": "files/questions.json",
|
|
"top_k": 5,
|
|
"dry_run": false
|
|
}
|
|
```
|
|
|
|
**Response (201):**
|
|
```json
|
|
{
|
|
"experiment_id": "exp-abc123",
|
|
"document_id": "doc-abc123",
|
|
"strategies_used": ["recursive", "fixed_size", "semantic"],
|
|
"questions_count": 21,
|
|
"aggregate_metrics": {
|
|
"recursive": {
|
|
"avg_context_relevance": 8.5,
|
|
"avg_answer_similarity": 7.8,
|
|
"avg_faithfulness": 9.2,
|
|
"hallucination_rate": 0.05,
|
|
"total_questions": 21,
|
|
"failed_questions": 0
|
|
}
|
|
},
|
|
"best_strategy": "recursive",
|
|
"total_latency_seconds": 120.5,
|
|
"estimated_cost_usd": 0.22,
|
|
"created_at": "2026-07-25T12:00:00"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### `GET /benchmarks/{experiment_id}`
|
|
|
|
Retrieve experiment results.
|
|
|
|
**Response:** Same as POST /benchmarks response.
|
|
|
|
---
|
|
|
|
#### `GET /benchmarks/{experiment_id}/report`
|
|
|
|
Generate HTML report.
|
|
|
|
**Query Parameters:**
|
|
- `view`: `managerial` (default) or `technical`
|
|
|
|
**Response:** HTML page
|
|
|
|
---
|
|
|
|
#### `GET /experiments`
|
|
|
|
List all experiments.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"items": [
|
|
{
|
|
"id": "exp-abc123",
|
|
"document_id": "doc-abc123",
|
|
"strategies_used": ["recursive", "fixed_size"],
|
|
"created_at": "2026-07-25T12:00:00"
|
|
}
|
|
],
|
|
"total": 1,
|
|
"offset": 0,
|
|
"limit": 50
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Jobs
|
|
|
|
Background execution for long-running benchmarks and document processing (FastAPI `BackgroundTasks` + SQLite job records).
|
|
|
|
#### `GET /jobs`
|
|
|
|
List jobs (newest first).
|
|
|
|
**Query parameters:** `job_type`, `status`, `offset`, `limit`
|
|
|
|
#### `GET /jobs/{job_id}`
|
|
|
|
Poll job status. When `status` is `completed`, `result` contains the same payload as the synchronous endpoint would return; when `failed`, `error` is set.
|
|
|
|
**Response (202 enqueue body from POST with `background=true`):**
|
|
```json
|
|
{
|
|
"job_id": "abc123",
|
|
"job_type": "benchmark",
|
|
"status": "pending",
|
|
"poll_url": "/jobs/abc123"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Error Responses
|
|
|
|
All errors return:
|
|
```json
|
|
{
|
|
"detail": "Error message",
|
|
"type": "ErrorClassName"
|
|
}
|
|
```
|
|
|
|
| Status Code | Error Type | Description |
|
|
|-------------|------------|-------------|
|
|
| 400 | ChunkingError | Invalid request |
|
|
| 400 | QueryError | Query failed |
|
|
| 400 | BenchmarkError | Benchmark failed |
|
|
| 404 | QueryError | Resource not found |
|
|
| 422 | ValidationError | Invalid request body |
|
|
|
|
---
|
|
|
|
## Rate Limits
|
|
|
|
None configured. For production, consider adding rate limiting.
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
None configured. For production, add API key or OAuth2 authentication.
|