Spaces:
Sleeping
Sleeping
File size: 3,475 Bytes
6cc8ae1 | 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 | """
FastAPI main application.
Cattle Breed Classifier API.
"""
import sys
from pathlib import Path
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
# Ensure project root is in path
PROJECT_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(PROJECT_ROOT))
from backend.app.core.config import get_settings
from backend.app.core.logging import logger
from backend.app.api.routes import health, predict, metadata
from backend.app.services.inference import inference_service
from backend.app.services.breed_info import breed_info_service
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown events."""
# Startup
logger.info("Starting Cattle Breed Classifier API...")
try:
inference_service.load()
breed_info_service.load()
logger.info("All services loaded successfully")
except Exception as e:
logger.error(f"Startup error: {e}")
logger.info("API started with limited functionality")
yield
# Shutdown
logger.info("Shutting down...")
def create_app() -> FastAPI:
"""Create and configure FastAPI application."""
settings = get_settings()
app = FastAPI(
title=settings.app_name,
version=settings.app_version,
description=(
"API for classifying Indian cattle breeds using deep learning. "
"Supports image upload, URL, and base64 input. "
"Returns breed prediction with confidence and metadata."
),
lifespan=lifespan,
docs_url="/docs",
redoc_url="/redoc",
)
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
app.include_router(health.router)
app.include_router(predict.router)
app.include_router(metadata.router)
# Serve Static frontend if it exists
static_dir = PROJECT_ROOT / "frontend" / "dist"
if static_dir.exists() and static_dir.is_dir():
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
# Mount assets
assets_dir = static_dir / "assets"
if assets_dir.exists():
app.mount("/assets", StaticFiles(directory=str(assets_dir)), name="assets")
@app.get("/", tags=["Root"])
async def root():
return FileResponse(str(static_dir / "index.html"))
# Catch-all for react router
@app.get("/{full_path:path}", tags=["Root"])
async def serve_spa(full_path: str):
# Exclude api requests
if full_path.startswith("api/") or full_path.startswith("docs") or full_path.startswith("redoc"):
return {"detail": "Not Found"}
return FileResponse(str(static_dir / "index.html"))
else:
@app.get("/", tags=["Root"])
async def root():
return {
"message": "Cattle Breed Classifier API",
"version": settings.app_version,
"docs": "/docs",
}
return app
app = create_app()
if __name__ == "__main__":
import uvicorn
settings = get_settings()
uvicorn.run(
"backend.app.main:app",
host=settings.host,
port=settings.port,
reload=settings.debug,
)
|