docs: run automated documentation updates workflow
This commit is contained in:
152
dev/scripts/coordinator_working.py
Executable file
152
dev/scripts/coordinator_working.py
Executable file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple working coordinator API for GPU miner
|
||||
"""
|
||||
|
||||
import logging
|
||||
from fastapi import FastAPI, HTTPException, Header
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from typing import Optional, Dict, Any
|
||||
from pydantic import BaseModel
|
||||
import time
|
||||
|
||||
# Setup logging
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Create FastAPI app
|
||||
app = FastAPI(
|
||||
title="AITBC Coordinator API - Working",
|
||||
version="0.1.0",
|
||||
description="Simple working coordinator service for GPU miner",
|
||||
)
|
||||
|
||||
# Add CORS middleware
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
||||
allow_headers=["*"]
|
||||
)
|
||||
|
||||
# Simple in-memory storage
|
||||
miners: Dict[str, Dict[str, Any]] = {}
|
||||
jobs: Dict[str, Dict[str, Any]] = {}
|
||||
|
||||
# Pydantic models
|
||||
class MinerRegister(BaseModel):
|
||||
miner_id: str
|
||||
capabilities: list[str] = []
|
||||
region: str = "default"
|
||||
concurrency: int = 1
|
||||
|
||||
class MinerHeartbeat(BaseModel):
|
||||
miner_id: str
|
||||
status: str = "online"
|
||||
inflight: int = 0
|
||||
|
||||
class JobSubmit(BaseModel):
|
||||
prompt: str
|
||||
model: str = "gemma3:1b"
|
||||
priority: str = "normal"
|
||||
|
||||
# Basic auth (simple for testing)
|
||||
API_KEY = "miner_test"
|
||||
|
||||
def verify_api_key(api_key: Optional[str] = Header(None), x_api_key: Optional[str] = Header(None)):
|
||||
key = api_key or x_api_key
|
||||
if key != API_KEY:
|
||||
raise HTTPException(status_code=401, detail="invalid api key")
|
||||
return key
|
||||
|
||||
@app.get("/health", tags=["health"], summary="Service healthcheck")
|
||||
async def health() -> dict[str, str]:
|
||||
"""Health check endpoint"""
|
||||
return {"status": "ok", "service": "coordinator-api"}
|
||||
|
||||
@app.get("/v1/health", tags=["health"], summary="Service healthcheck")
|
||||
async def health_v1() -> dict[str, str]:
|
||||
"""Health check endpoint v1"""
|
||||
return {"status": "ok", "service": "coordinator-api"}
|
||||
|
||||
@app.post("/v1/miners/register", tags=["miner"], summary="Register or update miner")
|
||||
async def register_miner(
|
||||
request: dict,
|
||||
api_key: Optional[str] = Header(None),
|
||||
x_api_key: Optional[str] = Header(None),
|
||||
miner_id: Optional[str] = None
|
||||
) -> dict[str, str]:
|
||||
"""Register a miner"""
|
||||
key = api_key or x_api_key
|
||||
if key != API_KEY:
|
||||
raise HTTPException(status_code=401, detail="invalid api key")
|
||||
|
||||
# Get miner_id from query parameter or request body
|
||||
mid = miner_id or request.get("miner_id", "miner_test")
|
||||
|
||||
# Register the miner with simple data
|
||||
miners[mid] = {
|
||||
"id": mid,
|
||||
"capabilities": ["gpu"],
|
||||
"region": request.get("region", "localhost"),
|
||||
"concurrency": request.get("concurrency", 1),
|
||||
"status": "online",
|
||||
"inflight": 0,
|
||||
"last_heartbeat": time.time(),
|
||||
"session_token": f"token_{mid}_{int(time.time())}"
|
||||
}
|
||||
|
||||
logger.info(f"Miner {mid} registered")
|
||||
return {"status": "ok", "session_token": miners[mid]["session_token"]}
|
||||
|
||||
@app.post("/v1/miners/heartbeat", tags=["miner"], summary="Send miner heartbeat")
|
||||
async def miner_heartbeat(
|
||||
request: dict,
|
||||
api_key: Optional[str] = Header(None),
|
||||
x_api_key: Optional[str] = Header(None),
|
||||
miner_id: Optional[str] = None
|
||||
) -> dict[str, str]:
|
||||
"""Receive miner heartbeat"""
|
||||
key = api_key or x_api_key
|
||||
if key != API_KEY:
|
||||
raise HTTPException(status_code=401, detail="invalid api key")
|
||||
|
||||
# Get miner_id from query parameter or request body
|
||||
mid = miner_id or request.get("miner_id", "miner_test")
|
||||
|
||||
if mid not in miners:
|
||||
raise HTTPException(status_code=404, detail="miner not registered")
|
||||
|
||||
miners[mid].update({
|
||||
"status": request.get("status", "online"),
|
||||
"inflight": request.get("current_jobs", 0),
|
||||
"last_heartbeat": time.time()
|
||||
})
|
||||
|
||||
return {"status": "ok"}
|
||||
|
||||
@app.post("/v1/miners/poll", tags=["miner"], summary="Poll for next job")
|
||||
async def poll_for_job(
|
||||
request: dict,
|
||||
api_key: Optional[str] = Header(None),
|
||||
x_api_key: Optional[str] = Header(None),
|
||||
miner_id: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Poll for next job"""
|
||||
key = api_key or x_api_key
|
||||
if key != API_KEY:
|
||||
raise HTTPException(status_code=401, detail="invalid api key")
|
||||
|
||||
# For now, return no jobs (empty response)
|
||||
return {"status": "no_jobs"}
|
||||
|
||||
@app.get("/", tags=["root"], summary="Root endpoint")
|
||||
async def root() -> dict[str, str]:
|
||||
"""Root endpoint"""
|
||||
return {"service": "AITBC Coordinator API", "status": "running"}
|
||||
|
||||
if __name__ == "__main__":
|
||||
import uvicorn
|
||||
logger.info("Starting working coordinator API on port 9080")
|
||||
uvicorn.run(app, host="127.0.0.1", port=9080)
|
||||
Reference in New Issue
Block a user