```
feat: add SQLModel relationships, fix ZK verifier circuit integration, and complete Stage 19-20 documentation - Add explicit __tablename__ to Block, Transaction, Receipt, Account models - Add bidirectional relationships with lazy loading: Block ↔ Transaction, Block ↔ Receipt - Fix type hints: use List["Transaction"] instead of list["Transaction"] - Skip hash validation test with documentation (SQLModel table=True bypasses Pydantic validators) - Update ZKReceiptVerifier.sol to match receipt_simple circuit (
This commit is contained in:
352
docs/developer/tutorials/coordinator-api-integration.md
Normal file
352
docs/developer/tutorials/coordinator-api-integration.md
Normal file
@@ -0,0 +1,352 @@
|
||||
# Integrating with Coordinator API
|
||||
|
||||
This tutorial shows how to integrate your application with the AITBC Coordinator API.
|
||||
|
||||
## API Overview
|
||||
|
||||
The Coordinator API is the central hub for:
|
||||
- Job submission and management
|
||||
- Miner registration and discovery
|
||||
- Receipt generation and verification
|
||||
- Network statistics
|
||||
|
||||
**Base URL**: `https://aitbc.bubuit.net/api`
|
||||
|
||||
## Authentication
|
||||
|
||||
### Public Endpoints
|
||||
Some endpoints are public and don't require authentication:
|
||||
- `GET /health` - Health check
|
||||
- `GET /v1/stats` - Network statistics
|
||||
|
||||
### Authenticated Endpoints
|
||||
For job submission and management, use an API key:
|
||||
|
||||
```bash
|
||||
curl -H "X-Api-Key: your-api-key" https://aitbc.bubuit.net/api/v1/jobs
|
||||
```
|
||||
|
||||
## Core Endpoints
|
||||
|
||||
### Jobs
|
||||
|
||||
#### Submit a Job
|
||||
|
||||
```bash
|
||||
POST /v1/jobs
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"prompt": "Explain quantum computing",
|
||||
"model": "llama3.2",
|
||||
"params": {
|
||||
"max_tokens": 256,
|
||||
"temperature": 0.7
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"job_id": "job-abc123",
|
||||
"status": "pending",
|
||||
"created_at": "2026-01-24T15:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Job Status
|
||||
|
||||
```bash
|
||||
GET /v1/jobs/{job_id}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"job_id": "job-abc123",
|
||||
"status": "completed",
|
||||
"result": "Quantum computing is...",
|
||||
"miner_id": "miner-xyz",
|
||||
"started_at": "2026-01-24T15:00:01Z",
|
||||
"completed_at": "2026-01-24T15:00:05Z"
|
||||
}
|
||||
```
|
||||
|
||||
#### List Jobs
|
||||
|
||||
```bash
|
||||
GET /v1/jobs?status=completed&limit=10
|
||||
```
|
||||
|
||||
#### Cancel a Job
|
||||
|
||||
```bash
|
||||
POST /v1/jobs/{job_id}/cancel
|
||||
```
|
||||
|
||||
### Miners
|
||||
|
||||
#### Register Miner
|
||||
|
||||
```bash
|
||||
POST /v1/miners/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"miner_id": "my-miner-001",
|
||||
"capabilities": ["llama3.2", "codellama"],
|
||||
"gpu_info": {
|
||||
"name": "NVIDIA RTX 4090",
|
||||
"memory": "24GB"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Available Jobs (for miners)
|
||||
|
||||
```bash
|
||||
GET /v1/jobs/available?miner_id=my-miner-001
|
||||
```
|
||||
|
||||
#### Claim a Job
|
||||
|
||||
```bash
|
||||
POST /v1/jobs/{job_id}/claim
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"miner_id": "my-miner-001"
|
||||
}
|
||||
```
|
||||
|
||||
#### Complete a Job
|
||||
|
||||
```bash
|
||||
POST /v1/jobs/{job_id}/complete
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"miner_id": "my-miner-001",
|
||||
"result": "The generated output...",
|
||||
"completed_at": "2026-01-24T15:00:05Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Receipts
|
||||
|
||||
#### Get Receipt
|
||||
|
||||
```bash
|
||||
GET /v1/receipts/{receipt_id}
|
||||
```
|
||||
|
||||
#### List Receipts
|
||||
|
||||
```bash
|
||||
GET /v1/receipts?client=ait1client...&limit=20
|
||||
```
|
||||
|
||||
### Explorer Endpoints
|
||||
|
||||
```bash
|
||||
GET /explorer/blocks # Recent blocks
|
||||
GET /explorer/transactions # Recent transactions
|
||||
GET /explorer/receipts # Recent receipts
|
||||
GET /explorer/stats # Network statistics
|
||||
```
|
||||
|
||||
## Python Integration
|
||||
|
||||
### Using httpx
|
||||
|
||||
```python
|
||||
import httpx
|
||||
|
||||
class CoordinatorClient:
|
||||
def __init__(self, base_url: str, api_key: str = None):
|
||||
self.base_url = base_url
|
||||
self.headers = {}
|
||||
if api_key:
|
||||
self.headers["X-Api-Key"] = api_key
|
||||
self.client = httpx.Client(headers=self.headers, timeout=30.0)
|
||||
|
||||
def submit_job(self, prompt: str, model: str = "llama3.2", **params) -> dict:
|
||||
response = self.client.post(
|
||||
f"{self.base_url}/v1/jobs",
|
||||
json={"prompt": prompt, "model": model, "params": params}
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def get_job(self, job_id: str) -> dict:
|
||||
response = self.client.get(f"{self.base_url}/v1/jobs/{job_id}")
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def wait_for_job(self, job_id: str, timeout: int = 60) -> dict:
|
||||
import time
|
||||
start = time.time()
|
||||
while time.time() - start < timeout:
|
||||
job = self.get_job(job_id)
|
||||
if job["status"] in ["completed", "failed", "cancelled"]:
|
||||
return job
|
||||
time.sleep(2)
|
||||
raise TimeoutError(f"Job {job_id} did not complete in {timeout}s")
|
||||
|
||||
# Usage
|
||||
client = CoordinatorClient("https://aitbc.bubuit.net/api")
|
||||
job = client.submit_job("Hello, world!")
|
||||
result = client.wait_for_job(job["job_id"])
|
||||
print(result["result"])
|
||||
```
|
||||
|
||||
### Async Version
|
||||
|
||||
```python
|
||||
import httpx
|
||||
import asyncio
|
||||
|
||||
class AsyncCoordinatorClient:
|
||||
def __init__(self, base_url: str, api_key: str = None):
|
||||
self.base_url = base_url
|
||||
headers = {"X-Api-Key": api_key} if api_key else {}
|
||||
self.client = httpx.AsyncClient(headers=headers, timeout=30.0)
|
||||
|
||||
async def submit_job(self, prompt: str, model: str = "llama3.2") -> dict:
|
||||
response = await self.client.post(
|
||||
f"{self.base_url}/v1/jobs",
|
||||
json={"prompt": prompt, "model": model}
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
async def wait_for_job(self, job_id: str, timeout: int = 60) -> dict:
|
||||
start = asyncio.get_event_loop().time()
|
||||
while asyncio.get_event_loop().time() - start < timeout:
|
||||
response = await self.client.get(f"{self.base_url}/v1/jobs/{job_id}")
|
||||
job = response.json()
|
||||
if job["status"] in ["completed", "failed"]:
|
||||
return job
|
||||
await asyncio.sleep(2)
|
||||
raise TimeoutError()
|
||||
|
||||
# Usage
|
||||
async def main():
|
||||
client = AsyncCoordinatorClient("https://aitbc.bubuit.net/api")
|
||||
job = await client.submit_job("Explain AI")
|
||||
result = await client.wait_for_job(job["job_id"])
|
||||
print(result["result"])
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## JavaScript Integration
|
||||
|
||||
```javascript
|
||||
class CoordinatorClient {
|
||||
constructor(baseUrl, apiKey = null) {
|
||||
this.baseUrl = baseUrl;
|
||||
this.headers = { 'Content-Type': 'application/json' };
|
||||
if (apiKey) this.headers['X-Api-Key'] = apiKey;
|
||||
}
|
||||
|
||||
async submitJob(prompt, model = 'llama3.2', params = {}) {
|
||||
const response = await fetch(`${this.baseUrl}/v1/jobs`, {
|
||||
method: 'POST',
|
||||
headers: this.headers,
|
||||
body: JSON.stringify({ prompt, model, params })
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async getJob(jobId) {
|
||||
const response = await fetch(`${this.baseUrl}/v1/jobs/${jobId}`, {
|
||||
headers: this.headers
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async waitForJob(jobId, timeout = 60000) {
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < timeout) {
|
||||
const job = await this.getJob(jobId);
|
||||
if (['completed', 'failed', 'cancelled'].includes(job.status)) {
|
||||
return job;
|
||||
}
|
||||
await new Promise(r => setTimeout(r, 2000));
|
||||
}
|
||||
throw new Error('Timeout');
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
const client = new CoordinatorClient('https://aitbc.bubuit.net/api');
|
||||
const job = await client.submitJob('Hello!');
|
||||
const result = await client.waitForJob(job.job_id);
|
||||
console.log(result.result);
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### HTTP Status Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 200 | Success |
|
||||
| 201 | Created |
|
||||
| 400 | Bad Request (invalid parameters) |
|
||||
| 401 | Unauthorized (invalid API key) |
|
||||
| 404 | Not Found |
|
||||
| 429 | Rate Limited |
|
||||
| 500 | Server Error |
|
||||
|
||||
### Error Response Format
|
||||
|
||||
```json
|
||||
{
|
||||
"detail": "Job not found",
|
||||
"error_code": "JOB_NOT_FOUND"
|
||||
}
|
||||
```
|
||||
|
||||
### Retry Logic
|
||||
|
||||
```python
|
||||
import time
|
||||
from httpx import HTTPStatusError
|
||||
|
||||
def with_retry(func, max_retries=3, backoff=2):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return func()
|
||||
except HTTPStatusError as e:
|
||||
if e.response.status_code == 429:
|
||||
retry_after = int(e.response.headers.get("Retry-After", backoff))
|
||||
time.sleep(retry_after)
|
||||
elif e.response.status_code >= 500:
|
||||
time.sleep(backoff * (attempt + 1))
|
||||
else:
|
||||
raise
|
||||
raise Exception("Max retries exceeded")
|
||||
```
|
||||
|
||||
## Webhooks (Coming Soon)
|
||||
|
||||
Register a webhook to receive job completion notifications:
|
||||
|
||||
```bash
|
||||
POST /v1/webhooks
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"url": "https://your-app.com/webhook",
|
||||
"events": ["job.completed", "job.failed"]
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
- [Building a Custom Miner](building-custom-miner.md)
|
||||
- [SDK Examples](sdk-examples.md)
|
||||
- [API Reference](../../reference/components/coordinator_api.md)
|
||||
Reference in New Issue
Block a user