File size: 4,627 Bytes
c75184e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8a1fc38
 
 
aa027f8
 
c75184e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8a1fc38
 
 
c75184e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8a1fc38
 
 
 
 
c75184e
 
 
 
 
 
 
5331784
c75184e
 
 
 
 
 
 
8a1fc38
 
aa027f8
 
c75184e
6d66e14
 
c75184e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
FastAPI Application β€” Advanced Mathematics Assistant Backend.

This is the main entry point for the backend API server.
Run with: uvicorn backend.src.main:app --host 0.0.0.0 --port 8080
"""

import logging
import time
from contextlib import asynccontextmanager

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from backend.src.config import settings
from backend.src.services.firebase_service import init_firebase
from backend.src.api.v1 import chat
from backend.src.api.v1 import progress
from backend.src.api.v1 import documents
from backend.src.api.v1 import symbolic

# ── Logging Setup ──────────────────────────────────────────────────────
logging.basicConfig(
    level=getattr(logging, settings.log_level.upper(), logging.INFO),
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logger = logging.getLogger("math_assistant.app")


# ── Application Lifespan ──────────────────────────────────────────────
@asynccontextmanager
async def lifespan(app: FastAPI):
    """Startup and shutdown events for the FastAPI application."""
    logger.info("πŸš€ Starting Advanced Mathematics Assistant API...")
    logger.info(f"   Environment: {settings.environment}")
    logger.info(f"   LLM Model: {settings.llm_model}")
    logger.info(f"   Vector DB: {settings.vector_db_type}")

    # Initialize Firebase Admin SDK
    init_firebase()

    # Pre-build knowledge base on startup (optional, lazy by default)
    # Uncomment the following to eagerly build on startup:
    # from backend.src.services.vector_service import build_pipeline
    # build_pipeline()

    yield  # Application is running

    logger.info("πŸ›‘ Shutting down Advanced Mathematics Assistant API.")


# ── FastAPI App ────────────────────────────────────────────────────────
app = FastAPI(
    title="Advanced Mathematics Assistant API",
    description=(
        "AI-powered math tutoring API for Indian school students (Class 6-12 + JEE). "
        "Uses RAG retrieval, SymPy symbolic computation, and LLM-based step-by-step solutions."
    ),
    version="1.0.0",
    lifespan=lifespan,
)

from backend.src.api.limiter import limiter, _rate_limit_exceeded_handler, RateLimitExceeded
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)


# ── CORS Middleware ────────────────────────────────────────────────────
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:3000",      # React dev server
        "http://localhost:5173",      # Vite dev server
        "http://localhost:8501",      # Streamlit
        "https://advanced-math-ai.vercel.app", # Vercel production
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# ── Routes ─────────────────────────────────────────────────────────────
app.include_router(chat.router)
app.include_router(progress.router)
app.include_router(documents.router)
app.include_router(symbolic.router)

from backend.src.api.v1 import quiz
app.include_router(quiz.router, prefix="/api/v1/quiz", tags=["Quiz"])

@app.get("/health")
async def health_check():
    """Health check endpoint β€” returns API status and knowledge base info.

    Returns HTTP 200 with:
    - status: "ok"
    - environment: current environment
    - kb_docs: number of indexed knowledge base documents (0 if not yet built)
    """
    kb_docs = 0
    try:
        from backend.src.services.vector_service import _PIPELINE_CACHE
        store = _PIPELINE_CACHE.get("store")
        if store:
            kb_docs = store.get_document_count()
    except Exception:
        pass

    return {
        "status": "ok",
        "environment": settings.environment,
        "version": "1.0.0",
        "kb_docs": kb_docs,
        "llm_model": settings.llm_model,
        "vector_db": settings.vector_db_type,
    }


@app.get("/")
async def root():
    """Root endpoint β€” redirect info."""
    return {
        "message": "Advanced Mathematics Assistant API",
        "docs": "/docs",
        "health": "/health",
    }