Files
bantaycam/backend/app/main.py
Nemo 7c43e4580d feat: initial BantayCam scaffold
- FastAPI backend with async SQLAlchemy
- Camera RTSP management (add, start, stop)
- Vehicle detection (YOLO + fast-alpr)
  - Type: car, motorcycle, truck, jeepney
  - Color detection (HSV)
  - License plate OCR
  - Motorcycle person count
- Face detection + InsightFace ArcFace embedding
- pgvector identity grouping (auto-cluster same face)
- Vehicle + person movement trail APIs
- Docker Compose with pgvector/pg16
- Models: Camera, VehicleIdentity, VehicleEvent, PersonIdentity, FaceEvent
2026-03-12 12:11:02 +08:00

92 lines
2.4 KiB
Python

"""
BantayCam — Integrated License Plate & Face Recognition for Philippine CCTV
FastAPI Application Entry Point
"""
from contextlib import asynccontextmanager
import logging
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pathlib import Path
from app.core.config import settings
from app.core.database import init_db
from app.services.vehicle_detector import vehicle_detector
from app.services.face_service import face_service
from app.services.stream_manager import StreamManager
from app.api import cameras, vehicles, persons
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s"
)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown events."""
logger.info("🚀 BantayCam starting up...")
# Init database
await init_db()
logger.info("✅ Database initialized")
# Load AI models
logger.info("Loading AI models (this may take a moment)...")
vehicle_detector.load()
face_service.load()
logger.info("✅ AI models loaded")
# Ensure snapshot storage exists
Path(settings.STORAGE_PATH).mkdir(parents=True, exist_ok=True)
yield
# Shutdown
logger.info("Shutting down streams...")
await StreamManager.get().stop_all()
logger.info("👋 BantayCam shut down")
app = FastAPI(
title="BantayCam",
description="Integrated License Plate & Face Recognition for Philippine CCTV Infrastructure",
version=settings.APP_VERSION,
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Tighten in production
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# API routes
app.include_router(cameras.router, prefix="/api/v1")
app.include_router(vehicles.router, prefix="/api/v1")
app.include_router(persons.router, prefix="/api/v1")
# Serve snapshots as static files
snapshot_dir = Path(settings.STORAGE_PATH)
snapshot_dir.mkdir(parents=True, exist_ok=True)
app.mount("/snapshots", StaticFiles(directory=str(snapshot_dir)), name="snapshots")
@app.get("/")
async def root():
return {
"app": settings.APP_NAME,
"version": settings.APP_VERSION,
"status": "running",
"docs": "/docs",
}
@app.get("/health")
async def health():
return {"status": "ok"}