from __future__ import annotations from contextlib import asynccontextmanager from pathlib import Path from typing import AsyncIterator import uvicorn from fastapi import FastAPI from fastapi.responses import FileResponse from fastapi.staticfiles import StaticFiles from sqlmodel import SQLModel from tracker.agent_api import router as agent_router from tracker.api import router as api_router from tracker.backup_api import router as backup_router from tracker.auth_http import ( apply_auth_middleware, apply_session_middleware, register_auth_routes, ) from tracker.config import TrackerConfig, load_config from tracker.db import get_engine_for_config, migrate_tracker_schema, seed_exercises_if_empty from tracker.planner_api import router as planner_router STATIC_DIR = Path(__file__).resolve().parent.parent / "static" @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncIterator[None]: cfg = app.state.tracker_config db_engine = get_engine_for_config(cfg) app.state.db_engine = db_engine SQLModel.metadata.create_all(db_engine) migrate_tracker_schema(db_engine, cfg) seed_exercises_if_empty(db_engine) yield def health() -> dict[str, str]: return {"status": "ok"} def root() -> FileResponse: return FileResponse(STATIC_DIR / "index.html") def build_app_from_config(config: TrackerConfig) -> FastAPI: application = FastAPI(title="Workout Tracker", lifespan=lifespan) application.state.tracker_config = config register_auth_routes(application) application.include_router(api_router) application.include_router(backup_router) application.include_router(planner_router) application.include_router(agent_router) application.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static") application.add_api_route("/health", health, methods=["GET"]) application.add_api_route("/api/health", health, methods=["GET"]) application.add_api_route("/", root, methods=["GET"]) apply_auth_middleware(application) apply_session_middleware(application, config) return application def build_app() -> FastAPI: return build_app_from_config(load_config()) app = build_app() def main() -> None: cfg = load_config() uvicorn.run("tracker.app:app", host=cfg.host, port=cfg.port, reload=True) if __name__ == "__main__": main()