File size: 3,080 Bytes
d5c9ae8
 
a2e3298
 
 
 
257c70f
a2e3298
 
 
 
d5c9ae8
a2e3298
d5c9ae8
 
257c70f
d5c9ae8
a2e3298
257c70f
a2e3298
 
 
 
8de8d71
a2e3298
04123af
a2e3298
 
 
 
04123af
a2e3298
 
 
04123af
a2e3298
 
 
04123af
d5c9ae8
a2e3298
 
 
79d9d09
a2e3298
 
 
 
 
 
 
 
 
 
 
 
 
 
95db209
a2e3298
 
 
 
 
 
 
 
d5c9ae8
a2e3298
 
 
d5c9ae8
e0196d0
 
a2e3298
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e0196d0
d5c9ae8
 
a2e3298
 
80e7d10
a2e3298
 
 
 
95db209
a2e3298
 
 
 
 
 
 
 
 
 
 
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
import logging
from contextlib import asynccontextmanager
from datetime import datetime
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse

from config import config
from services.text_service import text_service
from services.vision_service import vision_service
from routers import text_router, vision_router

# Logging Setup
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
)
logger = logging.getLogger("main")

@asynccontextmanager
async def lifespan(app: FastAPI):
    """Application lifecycle manager"""
    logger.info("=" * 60)
    logger.info("🤖 STARTING SMOLLM2 MULTIMODAL API")
    logger.info("=" * 60)
    
    try:
        # Initialize text service
        logger.info("Initializing Text Service...")
        await text_service.initialize()
        
        # Initialize vision service
        logger.info("Initializing Vision Service...")
        await vision_service.initialize()
        
        logger.info("=" * 60)
        logger.info("✓ All services initialized successfully")
        logger.info("=" * 60)
        
    except Exception as e:
        logger.critical(f"Startup failed: {e}")
        raise
    
    yield
    
    # Cleanup
    logger.info("Shutting down services...")
    await text_service.cleanup()
    await vision_service.cleanup()
    logger.info("Shutdown complete")

# Create FastAPI application
app = FastAPI(
    title="SmolLM2 Multimodal API",
    version="3.0",
    description="Production-ready API for SmolLM2 text and vision models",
    lifespan=lifespan
)

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

# Include routers
app.include_router(text_router.router)
app.include_router(vision_router.router)

@app.get("/")
async def root():
    """Root endpoint with API information"""
    return {
        "name": "SmolLM2 Multimodal API",
        "version": "3.0",
        "endpoints": {
            "text": "/v1/text/chat/completions",
            "vision": "/v1/vision/analyze",
            "health": "/health"
        },
        "docs": "/docs"
    }

@app.get("/health")
async def health_check():
    """Comprehensive health check"""
    return {
        "status": "healthy",
        "services": {
            "text": text_service.is_ready(),
            "vision": vision_service.is_ready()
        },
        "timestamp": datetime.utcnow().isoformat()
    }

@app.get("/ping")
async def ping():
    """Simple ping endpoint"""
    all_ready = text_service.is_ready() and vision_service.is_ready()
    
    if not all_ready:
        return JSONResponse(
            status_code=503,
            content={"status": "initializing", "ready": False}
        )
    
    return {"status": "pong", "ready": True}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "main:app",
        host=config.HOST,
        port=config.PORT,
        log_level="info"
    )