| """ |
| FastAPI server exposing OpenEnv interface over HTTP. |
| Endpoints: POST /reset, POST /step, GET /state, GET /health, GET /tasks |
| """ |
|
|
| import sys |
| import os |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
|
| from fastapi import FastAPI, Request, HTTPException |
| from fastapi.middleware.cors import CORSMiddleware |
| from pydantic import BaseModel |
| from typing import Optional |
| import uvicorn |
|
|
| from env.cache import CDNCacheEnv, TASK_CONFIGS |
| from env.models import Action, StepResult |
|
|
| app = FastAPI(title="CDN Cache Optimizer - OpenEnv", version="1.0.0") |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| _env: Optional[CDNCacheEnv] = None |
|
|
|
|
| @app.get("/health") |
| def health(): |
| return {"status": "ok", "env": "cdn-cache-optimizer"} |
|
|
| @app.post("/health") |
| def health_post(): |
| return {"status": "ok", "env": "cdn-cache-optimizer"} |
|
|
| @app.get("/tasks") |
| def list_tasks(): |
| return { |
| task_id: { |
| "name": cfg.name, |
| "difficulty": cfg.difficulty, |
| "description": cfg.description, |
| "cache_capacity_mb": cfg.cache_capacity_mb, |
| "episode_length": cfg.episode_length, |
| } |
| for task_id, cfg in TASK_CONFIGS.items() |
| } |
|
|
| @app.post("/reset") |
| async def reset(request: Request): |
| global _env |
| task_id = "task_easy" |
| seed = 42 |
| try: |
| body = await request.json() |
| task_id = body.get("task_id", "task_easy") |
| seed = body.get("seed", 42) |
| except Exception: |
| pass |
| if task_id not in TASK_CONFIGS: |
| raise HTTPException(status_code=400, detail=f"Unknown task_id '{task_id}'.") |
| _env = CDNCacheEnv(task_id=task_id, seed=seed) |
| obs = _env.reset() |
| return {"observation": obs.dict(), "task": _env.config.dict()} |
|
|
| @app.post("/step") |
| async def step(request: Request): |
| global _env |
| if _env is None: |
| raise HTTPException(status_code=400, detail="Call /reset first.") |
| if _env._done: |
| raise HTTPException(status_code=400, detail="Episode done. Call /reset.") |
| evict_file_id = None |
| try: |
| body = await request.json() |
| evict_file_id = body.get("evict_file_id", None) |
| except Exception: |
| pass |
| action = Action(evict_file_id=evict_file_id) |
| result: StepResult = _env.step(action) |
| return result.dict() |
|
|
| @app.get("/state") |
| def state(): |
| global _env |
| if _env is None: |
| raise HTTPException(status_code=400, detail="Call /reset first.") |
| return _env.state() |
|
|
| @app.get("/") |
| def root(): |
| return { |
| "name": "CDN Cache Optimizer", |
| "spec": "OpenEnv v1", |
| "endpoints": ["/reset", "/step", "/state", "/health", "/tasks"], |
| "tasks": list(TASK_CONFIGS.keys()), |
| } |
|
|
| if __name__ == "__main__": |
| uvicorn.run("api.main:app", host="0.0.0.0", port=7860, reload=False) |