diff --git a/app.py b/app.py index abd49e26b..cfd73e83f 100644 --- a/app.py +++ b/app.py @@ -47,6 +47,7 @@ from fastapi.responses import JSONResponse, FileResponse, HTMLResponse from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles from starlette.middleware.base import BaseHTTPMiddleware +from starlette.middleware.gzip import GZipMiddleware # Core imports from core.constants import ( @@ -104,6 +105,16 @@ app.add_middleware( ], ) +# ========= RESPONSE COMPRESSION (gzip) ========= +# The frontend's text assets (style.css, index.html, the JS bundles) shipped +# uncompressed on every cold load. gzip cuts CSS/JS/HTML by ~75-85% on the wire +# with no behavioural change. Starlette's GZipMiddleware excludes +# `text/event-stream` by default, so the SSE streams (chat, shell, research, +# model-probe — all served with media_type="text/event-stream") are never +# compressed or buffered; only complete bodies over minimum_size are. The +# security-header middleware composes cleanly on top. +app.add_middleware(GZipMiddleware, minimum_size=1024, compresslevel=6) + # ========= SECURITY HEADERS MIDDLEWARE ========= app.add_middleware(SecurityHeadersMiddleware)