File size: 3,116 Bytes
3f44a73
e020ac8
 
3f44a73
e020ac8
 
 
3f44a73
 
 
e020ac8
 
 
3f44a73
e020ac8
 
3f44a73
 
 
 
e020ac8
 
3f44a73
 
e020ac8
 
 
 
 
 
 
 
 
 
 
 
 
89d2b21
e020ac8
 
89d2b21
e020ac8
 
 
 
 
bf03cdf
e020ac8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3f44a73
e020ac8
 
 
3f44a73
 
 
 
e020ac8
 
 
3f44a73
 
 
e020ac8
3f44a73
 
e020ac8
3f44a73
 
 
 
 
e020ac8
 
3f44a73
e020ac8
3f44a73
 
 
 
 
 
 
 
e020ac8
3f44a73
e020ac8
 
3f44a73
 
 
 
 
 
 
e020ac8
 
3f44a73
 
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
"""
FastAPI Application Entry Point
Supports MLX (local) and Docker Model Runner (containerized) modes
"""
import logging
from contextlib import asynccontextmanager

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

from .config import settings
from .api.v1.router import router, init_services
from .services.llm_service import get_llm_service

logger = logging.getLogger(__name__)
logging.basicConfig(level=settings.log_level)


@asynccontextmanager
async def lifespan(app: FastAPI):
    """Manage application lifecycle"""
    # ===== STARTUP =====
    logger.info("πŸš€ FastAPI application starting...")
    logger.info(f"Environment: {settings.fastapi_env}")
    logger.info(f"Debug mode: {settings.debug}")
    
    # Get appropriate LLM service based on DEBUG flag
    logger.info("πŸš€ Initializing LLM service...")
    
    mlx_config = {
        "model_name": settings.llm_model_name_mlx,
        "max_tokens": settings.llm_max_tokens,
        "temperature": settings.llm_temperature,
        "device": settings.llm_device
    }
    
    docker_config = {
        "model_name": settings.llm_model,
        "max_tokens": settings.llm_max_tokens,
        "temperature": settings.llm_temperature,
        "docker_url": settings.runner_url,
        "timeout": settings.docker_timeout
    }
    
    llm_service = get_llm_service(
        debug=settings.debug,
        settings=settings,
        mlx_config=mlx_config,
        docker_config=docker_config
    )
    
    # Load model/initialize connection
    if await llm_service.load_model():
        logger.info("βœ… LLM service ready")
    else:
        logger.warning("⚠️  LLM service initialization failed - will use fallback")
    
    # Pass llm_service to router module
    from .api.v1 import router as router_module
    router_module.llm_service = llm_service
    
    # Initialize other services
    logger.info("πŸš€ Initializing data services...")
    await init_services()
    logger.info("βœ… All services initialized")
    
    yield
    
    # ===== SHUTDOWN =====
    logger.info("πŸ›‘ Application shutting down...")


# Create FastAPI app
app = FastAPI(
    title="LLM Data Analyzer",
    description="MLX LLM + Data Analysis Backend (Dual-mode: MLX or Docker Model Runner)",
    version="0.2.0",
    lifespan=lifespan
)

# CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Include router
app.include_router(router)

logger.info("βœ… FastAPI application configured")


# Root endpoint
@app.get("/")
async def root():
    """Root endpoint with API information"""
    return {
        "service": "LLM Data Analyzer API",
        "version": "0.2.0",
        "docs_url": "/docs",
        "health_url": "/api/v1/health",
        "mode": "MLX (local)" if settings.debug else "Docker Model Runner"
    }


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "backend.app.main:app",
        host="0.0.0.0",
        port=8000,
        reload=settings.fastapi_env == "development"
    )