amachine.am_app
def
create_app(experiments_root: pathlib.Path) -> fastapi.applications.FastAPI:
19def create_app(experiments_root: Path) -> FastAPI: 20 21 @asynccontextmanager 22 async def lifespan(app: FastAPI): 23 app.state.experiments_root = experiments_root 24 yield 25 26 app = FastAPI(title="amachine", lifespan=lifespan) 27 28 # ------------------------------------------------------------------------- 29 # Development Middleware: Prevent JS Caching 30 # ------------------------------------------------------------------------- 31 32 @app.middleware("http") 33 async def prevent_js_caching(request: Request, call_next): 34 response = await call_next(request) 35 if request.url.path.endswith(".js"): 36 response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" 37 response.headers["Pragma"] = "no-cache" 38 response.headers["Expires"] = "0" 39 return response 40 41 app.add_middleware( 42 CORSMiddleware, 43 allow_origins=["*"], 44 allow_methods=["*"], 45 allow_headers=["*"], 46 ) 47 48 # ------------------------------------------------------------------------- 49 # WebSocket 50 # ------------------------------------------------------------------------- 51 52 @app.websocket("/ws") 53 async def websocket_endpoint(websocket: WebSocket): 54 await websocket.accept() 55 try: 56 while True: 57 raw = await websocket.receive_text() 58 msg = orjson.loads(raw) 59 await _handle_message(websocket, msg, app.state.experiments_root) 60 except WebSocketDisconnect: 61 pass 62 63 # ------------------------------------------------------------------------- 64 # REST (convenience / direct access) 65 # ------------------------------------------------------------------------- 66 67 @app.get("/api/experiments", response_model=list[ExperimentSummary]) 68 def list_experiments(): 69 return scan_experiments(app.state.experiments_root) 70 71 @app.get("/api/experiments/{experiment_id}", response_model=ExperimentDetail) 72 def experiment_detail(experiment_id: str): 73 try: 74 return get_experiment( app.state.experiments_root, experiment_id ) 75 except FileNotFoundError as e: 76 raise HTTPException(status_code=404, detail=str(e)) 77 78 # ------------------------------------------------------------------------- 79 # Static UI 80 # ------------------------------------------------------------------------- 81 82 if _UI_DIR.exists(): 83 app.mount("/", StaticFiles(directory=_UI_DIR, html=True), name="ui") 84 85 return app