""" FusionOps OpenEnv Server FastAPI application exposing the scheduling environment via HTTP and WebSocket. """ from __future__ import annotations import json import uuid from typing import Optional from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi.responses import HTMLResponse, JSONResponse from pydantic import BaseModel from src.models import Graph from src.environment import FusionOpsEnv, parse_action from src.tasks import load_task, get_task_config, list_tasks app = FastAPI(title="FusionOps", description="ML Graph Scheduling Environment") # Store active sessions sessions: dict[str, FusionOpsEnv] = {} class ResetRequest(BaseModel): task: str = "task1_linear" class StepRequest(BaseModel): command: str class ResetResponse(BaseModel): session_id: str observation: str done: bool = False reward: float = 0.0 class StepResponse(BaseModel): observation: str reward: float done: bool info: dict = {} score: Optional[float] = None # ============================================================ # HTTP Endpoints # ============================================================ @app.get("/") async def root(): return {"status": "ok", "environment": "fusionops", "tasks": list_tasks()} @app.post("/reset") async def reset(request: ResetRequest = ResetRequest()): task_name = request.task try: graph = load_task(task_name) except ValueError as e: return JSONResponse(status_code=400, content={"error": str(e)}) cfg = get_task_config(task_name) env = FusionOpsEnv(graph, max_steps=cfg["max_steps"]) result = env.reset() session_id = str(uuid.uuid4()) sessions[session_id] = env return ResetResponse( session_id=session_id, observation=result.observation, done=result.done, reward=result.reward, ) @app.post("/step/{session_id}") async def step(session_id: str, request: StepRequest): if session_id not in sessions: return JSONResponse(status_code=404, content={"error": "Session not found"}) env = sessions[session_id] action = parse_action(request.command, env.graph) if action is None: return StepResponse( observation="Failed to parse action. Use format: SCHEDULE ops=[0,1] config=[128,128,1] retain=[]", reward=-0.1, done=False, info={"error": "Parse error"}, ) result = env.step(action) response = StepResponse( observation=result.observation, reward=result.reward, done=result.done, info=result.info, ) if result.done: response.score = env.get_score() # Clean up session del sessions[session_id] return response @app.get("/state/{session_id}") async def get_state(session_id: str): if session_id not in sessions: return JSONResponse(status_code=404, content={"error": "Session not found"}) return sessions[session_id].get_state() @app.get("/tasks") async def get_tasks(): result = {} for name in list_tasks(): cfg = get_task_config(name) result[name] = cfg return result @app.get("/web") async def web_ui(): """Simple web UI for testing.""" return HTMLResponse("""
Use the API endpoints: