File size: 3,635 Bytes
c1dc628
7edd376
e86a49a
 
 
e22dcc4
7edd376
 
 
e86a49a
7edd376
 
e22dcc4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e4835c7
c1dc628
dcca132
c1dc628
e4835c7
e22dcc4
 
 
 
 
 
 
 
 
 
dcca132
 
 
 
 
 
 
 
 
 
e22dcc4
 
 
 
 
ec2497b
 
e22dcc4
ec2497b
 
 
 
e86a49a
ec2497b
 
e22dcc4
ec2497b
 
 
 
 
 
 
 
 
dcca132
ec2497b
 
 
 
 
 
 
 
 
 
 
dcca132
e22dcc4
 
 
 
 
 
 
 
 
 
 
 
 
dcca132
e22dcc4
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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"
    )