Spaces:
Sleeping
Sleeping
| 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") | |
| 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) | |
| 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)) | |
| def step(action: ActionModel): | |
| try: | |
| result = env.step(action) | |
| return result | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| def state(): | |
| try: | |
| return env._get_obs() | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| 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() | |