Spaces:
Running
Running
File size: 2,191 Bytes
3f2df04 9f09117 36d7e96 fd0bd3b 36d7e96 fd0bd3b 9f09117 fd0bd3b 3f2df04 36d7e96 3f2df04 fd0bd3b 36d7e96 fd0bd3b 9f09117 fd0bd3b 9f09117 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | import logging
import time
import traceback
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from app.routers.api import router as api_router
from app.services.analytics import init_db
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
init_db()
yield
app = FastAPI(
title="NEM Battery SCADA Data Explorer",
description="Explore 4-second BESS SCADA data from Australia's National Electricity Market.",
version="1.0.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["GET"],
allow_headers=["*"],
)
app.include_router(api_router)
@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""
Catch-all for any exception not already handled by a specific handler or
HTTPException. Logs the full traceback so silent 500s become visible in
the application log, then returns a JSON 500 response.
"""
logger.error(
"Unhandled exception on %s %s\n%s",
request.method,
request.url,
traceback.format_exc(),
)
return JSONResponse(
status_code=500,
content={"detail": "An internal server error occurred. Please try again."},
)
STATIC_DIR = Path(__file__).parent / "static"
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
# Bust the browser cache for /static/js/app.js and /static/css/style.css on
# every container start so deploys don't get served stale assets. Each new
# container produces a new __VERSION__ value; the HTML is rendered once at
# startup and served from memory.
_BUILD_VERSION = str(int(time.time()))
_INDEX_HTML = (
(STATIC_DIR / "index.html")
.read_text()
.replace("__VERSION__", _BUILD_VERSION)
)
@app.get("/", include_in_schema=False)
async def index():
return HTMLResponse(content=_INDEX_HTML)
|