Spaces:
Sleeping
Sleeping
| from collections.abc import AsyncIterator | |
| from contextlib import asynccontextmanager | |
| from pathlib import Path | |
| from fastapi import FastAPI | |
| from fastapi.responses import FileResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from app.api.routes import create_router | |
| from app.core.config import get_settings | |
| from app.db.database import create_session_factory, init_db | |
| from app.db.repository import Repository | |
| def _configure_pipeline_api(app: FastAPI) -> None: | |
| if getattr(app.state, "pipeline_api_configured", False): | |
| return | |
| settings = get_settings() | |
| settings.data_dir.mkdir(parents=True, exist_ok=True) | |
| engine, session_factory = create_session_factory(settings.database_url) | |
| init_db(engine) | |
| repo = Repository(session_factory) | |
| app.include_router(create_router(repo)) | |
| _prioritize_api_routes(app) | |
| app.state.pipeline_api_configured = True | |
| def _prioritize_api_routes(app: FastAPI) -> None: | |
| app.router.routes.sort( | |
| key=lambda route: 0 if getattr(route, "path", "").startswith("/api") else 1 | |
| ) | |
| def _configure_frontend(app: FastAPI) -> None: | |
| settings = get_settings() | |
| frontend_dir = settings.frontend_dir | |
| if frontend_dir is None: | |
| return | |
| index_html = frontend_dir / "index.html" | |
| assets_dir = frontend_dir / "assets" | |
| if assets_dir.exists(): | |
| app.mount("/assets", StaticFiles(directory=assets_dir), name="assets") | |
| if not index_html.exists(): | |
| return | |
| def frontend_index() -> FileResponse: | |
| return FileResponse(index_html) | |
| def frontend_fallback(path: str) -> FileResponse: | |
| candidate = _safe_frontend_file(frontend_dir, path) | |
| if candidate is not None and candidate.exists() and candidate.is_file(): | |
| return FileResponse(candidate) | |
| return FileResponse(index_html) | |
| def _safe_frontend_file(frontend_dir: Path, path: str) -> Path | None: | |
| if not path or path.startswith("api/"): | |
| return None | |
| root = frontend_dir.resolve() | |
| candidate = (root / path).resolve() | |
| if root == candidate or root in candidate.parents: | |
| return candidate | |
| return None | |
| async def lifespan(app: FastAPI) -> AsyncIterator[None]: | |
| _configure_pipeline_api(app) | |
| yield | |
| def create_app(*, initialize: bool = True) -> FastAPI: | |
| app = FastAPI( | |
| title="Fast Follow Structure Generator", | |
| lifespan=None if initialize else lifespan, | |
| ) | |
| def health() -> dict[str, str]: | |
| return {"status": "ok"} | |
| if initialize: | |
| _configure_pipeline_api(app) | |
| _configure_frontend(app) | |
| return app | |
| app = create_app(initialize=False) | |