Spaces:
Sleeping
Sleeping
| """ | |
| Main entry point for Rubric AI. | |
| Runs both FastAPI backend and NiceGUI frontend on a single Uvicorn process. | |
| Designed for deployment on Hugging Face Spaces (port 7860). | |
| """ | |
| import re | |
| from starlette.middleware.base import BaseHTTPMiddleware | |
| from backend.app import create_app | |
| from backend.core.config import settings | |
| from frontend.ui import init_frontend | |
| from nicegui import ui | |
| # Create FastAPI application | |
| app = create_app() | |
| # Import API routes (registers @app decorators) | |
| import frontend.api_routes # noqa: F401 | |
| # Middleware to allow iframe embedding on HF Spaces | |
| class AllowIframeMiddleware(BaseHTTPMiddleware): | |
| async def dispatch(self, request, call_next): | |
| response = await call_next(request) | |
| # Remove X-Frame-Options to allow HF Spaces iframe embedding | |
| if "x-frame-options" in response.headers: | |
| del response.headers["x-frame-options"] | |
| # Remove or modify Content-Security-Policy frame-ancestors directive | |
| if "content-security-policy" in response.headers: | |
| csp = response.headers["content-security-policy"] | |
| # Remove frame-ancestors directive entirely to allow any iframe embedding | |
| csp = re.sub(r"frame-ancestors\s+[^;]+;?\s*", "", csp) | |
| if csp.strip(): | |
| response.headers["content-security-policy"] = csp | |
| else: | |
| del response.headers["content-security-policy"] | |
| return response | |
| app.add_middleware(AllowIframeMiddleware) | |
| # Initialize NiceGUI frontend routes BEFORE mounting | |
| init_frontend() | |
| # Mount NiceGUI onto FastAPI (modifies app in place) | |
| # This must happen at module level so Uvicorn can import 'main:app' | |
| ui.run_with( | |
| app, | |
| title="Rubric AI", | |
| favicon="favicon.png", | |
| storage_secret=settings.SUPABASE_ANON_KEY or "rubric-ai-secret", | |
| mount_path="/", | |
| reconnect_timeout=10, # Handle HF Spaces proxy timeouts | |
| ) | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run( | |
| "main:app", | |
| host=settings.HOST, | |
| port=settings.PORT, | |
| reload=True, | |
| ) | |