from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from fastapi.staticfiles import StaticFiles import logging import os from app.core.config import settings from app.core.database import create_tables, SessionLocal from app.models.document import Document, ChatMessage import shutil from app.api.endpoints import documents, chat from app.services.vector_store import VectorStore # Configure logging logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) # Create FastAPI app app = FastAPI( title=settings.PROJECT_NAME, description="A comprehensive PDF-based Q&A chatbot system", version="1.0.0", docs_url="/docs", redoc_url="/redoc" ) # Add CORS middleware app.add_middleware( CORSMiddleware, allow_origins=settings.BACKEND_CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include API routes app.include_router( documents.router, prefix=f"{settings.API_V1_STR}/documents", tags=["documents"] ) app.include_router( chat.router, prefix=f"{settings.API_V1_STR}/chat", tags=["chat"] ) # Serve static frontend (exported Next.js) at root frontend_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "frontend_out")) if os.path.isdir(frontend_path): app.mount("/", StaticFiles(directory=frontend_path, html=True), name="frontend") # Health check endpoint @app.get("/health") def health_check(): """Health check endpoint""" return { "status": "healthy", "service": settings.PROJECT_NAME, "version": "1.0.0" } # Root endpoint @app.get("/") def root(): """Root endpoint with API information""" return { "message": "PDF Q&A Chatbot API", "version": "1.0.0", "docs": "/docs", "health": "/health" } # Startup event @app.on_event("startup") async def startup_event(): """Initialize application on startup""" # Create database tables create_tables() # Ensure directories exist os.makedirs(settings.UPLOAD_DIR, exist_ok=True) os.makedirs(settings.CHROMA_PERSIST_DIRECTORY, exist_ok=True) # --- ERASE ALL DOCUMENTS, CHAT MESSAGES, AND VECTORS ON STARTUP --- # 1. Delete all rows from documents and chat_messages tables db = SessionLocal() try: db.query(Document).delete() db.query(ChatMessage).delete() db.commit() finally: db.close() # 2. Remove all files in chroma_db directory (but keep the directory) chroma_dir = settings.CHROMA_PERSIST_DIRECTORY for filename in os.listdir(chroma_dir): file_path = os.path.join(chroma_dir, filename) try: if os.path.isfile(file_path) or os.path.islink(file_path): os.unlink(file_path) elif os.path.isdir(file_path): shutil.rmtree(file_path) except Exception as e: logging.warning(f"Failed to delete {file_path}: {e}") # 3. Explicitly clear ChromaDB vector store vector_store = VectorStore() vector_store.clear_all() logging.info("All documents, chat messages, and vector store erased on startup.") # --- END ERASE --- logging.info("Application started successfully") # Shutdown event @app.on_event("shutdown") async def shutdown_event(): """Cleanup on application shutdown""" logging.info("Application shutting down") if __name__ == "__main__": import uvicorn uvicorn.run( "main:app", host="0.0.0.0", port=8000, reload=True, log_level="info" )