1"""FastAPI application for Pintle Engine Design.
4 cd /home/adnan/EngineDesign
5 uvicorn backend.main:app --reload --port 8000
10from pathlib
import Path
11from contextlib
import asynccontextmanager
13from fastapi
import FastAPI, Request
14from fastapi.exceptions
import RequestValidationError
15from fastapi.middleware.cors
import CORSMiddleware
16from fastapi.responses
import JSONResponse
19project_root = Path(__file__).resolve().parents[1]
20if str(project_root)
not in sys.path:
21 sys.path.insert(0, str(project_root))
32 from engine
import accel
as _accel
35 print(
"[accel] numba kernels warmed (ED_ACCEL=numba)")
37 print(
"[accel] disabled; using the Python path")
38except Exception
as _ed_err:
39 print(f
"[accel] unavailable, using Python path: {_ed_err}")
46for router_name
in [
'config',
'configs_store',
'documents',
'users',
'evaluate',
'timeseries',
'flight',
'geometry',
'optimizer',
'layerx']:
48 router_module = __import__(f
'backend.routers.{router_name}', fromlist=[router_name])
49 _optional_routers[router_name] = router_module
50 except (ImportError, TypeError)
as e:
51 print(f
"Warning: Router '{router_name}' unavailable (non-critical): {e}")
55 """Application lifespan.
57 Live state is per-user now (backend/session.py), so there is no global config
58 to load at boot: each user's session loads configs/default.yaml on creation,
59 the first time that user hits the API. Nothing to do here.
65 title=
"Hotbench Engine API",
66 description=
"Liquid engine design and analysis: Forward Mode, Time-Series, the optimizer layers and Layer X",
73 t =
" ".join(str(text).
split())
75 return "Something went wrong."
76 t = t[0].upper() + t[1:]
77 return t
if t[-1]
in ".!?" else t +
"."
81 loc = [str(p)
for p
in err.get(
"loc", ())
if p
not in (
"body",
"query",
"path")]
82 field =
" ".join(loc).replace(
"_",
" ")
83 msg = str(err.get(
"msg")
or "is not valid").removeprefix(
"Value error, ")
84 return f
"{field}: {msg}" if field
else msg
88 """FastAPI's request-validation list ([{loc, msg, type}, ...]) as the one plain sentence every
89 error response carries (``{"detail": "<sentence>"}``). Every problem, each named by its field,
90 joined with '; ' -- as feed-twin's backend/errors.validation_sentence does. A sentence that
91 names only the first leaves the person fixing one field per round trip."""
92 said =
"; ".join(p
for p
in (
_one_problem(e)
for e
in errors)
if p)
94 return "Some of the values were not accepted."
98@app.exception_handler(RequestValidationError)
100 errors = list(exc.errors())
107 "errors": [{
"loc": [str(p)
for p
in e.get(
"loc", ())],
"msg": str(e.get(
"msg",
""))}
for e
in errors],
112@app.exception_handler(Exception)
116 first = (str(exc).strip().splitlines()
or [
""])[0][:200]
117 what = f
"{type(exc).__name__}: {first}" if first
else type(exc).__name__
118 return JSONResponse(status_code=500, content={
"detail": f
"The engine design server hit an error ({what})."})
120if 'layerx' in _optional_routers:
122 app.add_middleware(_optional_routers[
'layerx'].UploadSizeGuard)
128 "http://localhost:5173",
129 "http://localhost:3000",
130 "http://127.0.0.1:5173",
131 "http://127.0.0.1:3000",
132 "https://engine-design.starberkeley.org",
134 allow_credentials=
True,
146app.include_router(control.router)
149for router_name, router_module
in _optional_routers.items():
151 app.include_router(router_module.router)
152 print(f
"✅ Loaded router: {router_name}")
153 except Exception
as e:
154 print(f
"Warning: Failed to include router '{router_name}': {e}")
159 """Root endpoint - API info."""
161 "name":
"Pintle Engine Design API",
167@app.get("/api/health")
169 """Health check endpoint.
171 A liveness probe with no user context, so it no longer reports config_loaded
172 (that is a per-user fact now -- see GET /api/config).
174 return {
"status":
"healthy"}
static std::vector< string_t > split(const string_t &reference_string)
split the string input to reference tokens
JSONResponse _unhandled_as_sentence(Request request, Exception exc)
str _one_problem(dict err)
str validation_sentence(list errors)
JSONResponse _validation_as_sentence(Request request, RequestValidationError exc)