Spaces:
Running
Running
| # Load environment variables | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| from contextlib import asynccontextmanager | |
| from fastapi import FastAPI | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from loguru import logger | |
| from api.auth import PasswordAuthMiddleware | |
| from api.routers import ( | |
| auth, | |
| chat, | |
| config, | |
| context, | |
| embedding, | |
| embedding_rebuild, | |
| episode_profiles, | |
| insights, | |
| knowledge_graph, | |
| models, | |
| monitoring, | |
| notebooks, | |
| notes, | |
| ocr, | |
| podcasts, | |
| quiz, | |
| research, | |
| search, | |
| settings, | |
| source_chat, | |
| sources, | |
| speaker_profiles, | |
| study_plans, | |
| transformations, | |
| diagrams, | |
| ) | |
| from api.routers import commands as commands_router | |
| from open_notebook.database.async_migrate import AsyncMigrationManager | |
| # Import commands to register them in the API process | |
| try: | |
| logger.info("Commands imported in API process") | |
| except Exception as e: | |
| logger.error(f"Failed to import commands in API process: {e}") | |
| async def lifespan(app: FastAPI): | |
| """ | |
| Lifespan event handler for the FastAPI application. | |
| Runs database migrations automatically on startup. | |
| """ | |
| # Startup: Run database migrations | |
| logger.info("Starting API initialization...") | |
| try: | |
| migration_manager = AsyncMigrationManager() | |
| current_version = await migration_manager.get_current_version() | |
| logger.info(f"Current database version: {current_version}") | |
| if await migration_manager.needs_migration(): | |
| logger.warning("Database migrations are pending. Running migrations...") | |
| await migration_manager.run_migration_up() | |
| new_version = await migration_manager.get_current_version() | |
| logger.success(f"Migrations completed successfully. Database is now at version {new_version}") | |
| else: | |
| logger.info("Database is already at the latest version. No migrations needed.") | |
| except Exception as e: | |
| logger.error(f"CRITICAL: Database migration failed: {str(e)}") | |
| logger.exception(e) | |
| # Fail fast - don't start the API with an outdated database schema | |
| raise RuntimeError(f"Failed to run database migrations: {str(e)}") from e | |
| logger.success("API initialization completed successfully") | |
| # Yield control to the application | |
| yield | |
| # Shutdown: cleanup if needed | |
| logger.info("API shutdown complete") | |
| app = FastAPI( | |
| title="Open Notebook API", | |
| description="API for Open Notebook - Research Assistant", | |
| version="0.2.2", | |
| lifespan=lifespan, | |
| ) | |
| # Add password authentication middleware first | |
| # Exclude /api/auth/status and /api/config from authentication | |
| app.add_middleware(PasswordAuthMiddleware, excluded_paths=["/", "/health", "/docs", "/openapi.json", "/redoc", "/api/auth/status", "/api/config"]) | |
| # Add CORS middleware last (so it processes first) | |
| # Allow requests from: | |
| # - localhost development (http://localhost:3000) | |
| # - Hugging Face Space backend (https://baveshraam-open-notebook.hf.space) | |
| # - Any frontend deployment (can be restricted further in production) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=[ | |
| "http://localhost:3000", | |
| "http://127.0.0.1:3000", | |
| "https://baveshraam-open-notebook.hf.space", | |
| "*" # Allow all origins - can be restricted later | |
| ], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Include routers | |
| app.include_router(auth.router, prefix="/api", tags=["auth"]) | |
| app.include_router(config.router, prefix="/api", tags=["config"]) | |
| app.include_router(notebooks.router, prefix="/api", tags=["notebooks"]) | |
| app.include_router(search.router, prefix="/api", tags=["search"]) | |
| app.include_router(models.router, prefix="/api", tags=["models"]) | |
| app.include_router(transformations.router, prefix="/api", tags=["transformations"]) | |
| app.include_router(notes.router, prefix="/api", tags=["notes"]) | |
| app.include_router(embedding.router, prefix="/api", tags=["embedding"]) | |
| app.include_router(embedding_rebuild.router, prefix="/api/embeddings", tags=["embeddings"]) | |
| app.include_router(settings.router, prefix="/api", tags=["settings"]) | |
| app.include_router(context.router, prefix="/api", tags=["context"]) | |
| app.include_router(sources.router, prefix="/api", tags=["sources"]) | |
| app.include_router(insights.router, prefix="/api", tags=["insights"]) | |
| app.include_router(commands_router.router, prefix="/api", tags=["commands"]) | |
| app.include_router(podcasts.router, prefix="/api", tags=["podcasts"]) | |
| app.include_router(episode_profiles.router, prefix="/api", tags=["episode-profiles"]) | |
| app.include_router(speaker_profiles.router, prefix="/api", tags=["speaker-profiles"]) | |
| app.include_router(chat.router, prefix="/api", tags=["chat"]) | |
| app.include_router(source_chat.router, prefix="/api", tags=["source-chat"]) | |
| app.include_router(quiz.router, prefix="/api", tags=["quiz"]) | |
| app.include_router(research.router, prefix="/api", tags=["research"]) | |
| app.include_router(knowledge_graph.router, prefix="/api", tags=["knowledge-graph"]) | |
| app.include_router(monitoring.router, prefix="/api", tags=["monitoring"]) | |
| app.include_router(ocr.router, prefix="/api", tags=["ocr"]) | |
| app.include_router(study_plans.router, prefix="/api", tags=["study-plans"]) | |
| app.include_router(diagrams.router, prefix="/api", tags=["diagrams"]) | |
| async def root(): | |
| return {"message": "Open Notebook API is running"} | |
| async def health(): | |
| return {"status": "healthy"} | |