"""FastAPI control surface for the agent (served on localhost). Start / stop the worker pool, tune the worker count live (trades desktop responsiveness for throughput), and watch GPU load + progress + the server-side queue. Config is env-seeded; the worker count is adjustable here on the fly. """ from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse, JSONResponse from .config import Config from .gpu import read_gpu from .worker import Worker cfg = Config.from_env() worker = Worker(cfg) app = FastAPI(title="FabledCurator GPU agent") @app.on_event("startup") def _maybe_autostart() -> None: # With AUTO_START set, a container restart (host reboot, or `restart: # unless-stopped` after a crash) resumes the worker on its own — the slots # then ride out a still-down curator via lease backoff. Lets the agent # survive a redeploy with nobody at the desktop to click Start. if cfg.auto_start and cfg.token: worker.start() @app.get("/", response_class=HTMLResponse) def index() -> str: return _PAGE @app.post("/start") def start(): worker.start() return JSONResponse(worker.status()) @app.post("/stop") def stop(): worker.stop() return JSONResponse(worker.status()) @app.post("/concurrency") async def concurrency(request: Request): body = await request.json() worker.set_concurrency(int(body.get("value", 1))) return JSONResponse(worker.status()) @app.post("/auto") async def auto(request: Request): body = await request.json() worker.set_auto(bool(body.get("value", True))) return JSONResponse(worker.status()) @app.get("/status") def status(): s = worker.status() s["fc_url"] = cfg.fc_url s["configured"] = bool(cfg.token) s["gpu"] = read_gpu() try: s["queue"] = worker.client.queue_status() except Exception: s["queue"] = None return JSONResponse(s) _PAGE = """
FC: — · token —