PowerGrid / server /app.py
saiteja020's picture
Finished
c24a61e
Raw
History Blame Contribute Delete
3.1 kB
import os
import sys
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
# Ensure project root is on sys.path even if run from inside this directory
_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
if _ROOT not in sys.path:
sys.path.insert(0, _ROOT)
from openenv.models import ActionModel, ObservationModel, StepResult, ResetConfig
from server.env import BESSEnvironment
from backend.api.routes import router as api_router
# Setup paths and environment
_HERE = os.path.dirname(os.path.abspath(__file__))
_ROOT = os.path.abspath(os.path.join(_HERE, ".."))
frontend_dir = os.path.join(_ROOT, "frontend", "dist")
data_path = os.path.join(_ROOT, "data", "pjm_data.csv")
app = FastAPI(
title="PowerGrid RL Platform",
version="2.0.0",
description="OpenEnv simulation + React frontend API (SAC Agent)"
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Frontend API routes (/api/*)
app.include_router(api_router)
# Serve built frontend assets
if os.path.exists(os.path.join(frontend_dir, "assets")):
app.mount("/assets", StaticFiles(directory=os.path.join(frontend_dir, "assets")), name="assets")
@app.get("/{full_path:path}")
async def serve_frontend(full_path: str):
# 1. Check if the requested path is a specific file (e.g., favicon, robots.txt)
file_path = os.path.join(frontend_dir, full_path)
if full_path and os.path.isfile(file_path):
return FileResponse(file_path)
# 2. Otherwise, serve index.html for SPA routing
index_path = os.path.join(frontend_dir, "index.html")
if os.path.exists(index_path):
return FileResponse(index_path)
# 3. Fallback to API health check if frontend is missing
return {"status": "ok", "message": "BESS-RL Platform API is running"}
# Environment instance (shared across requests)
env = BESSEnvironment(data_path=data_path)
@app.post("/reset", response_model=ObservationModel)
def reset(config: ResetConfig = ResetConfig()):
try:
obs = env.reset(seed=config.seed, task=config.task)
return obs
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/step", response_model=StepResult)
def step(action: ActionModel):
try:
result = env.step(action)
return result
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/state", response_model=ObservationModel)
def state():
try:
return env._get_obs()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/info")
def info():
return {
"task": env.task,
"max_steps": env.max_steps,
"current_step": env.current_step,
"soc": env.soc
}
def main():
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", 8000)))
if __name__ == "__main__":
main()