| | import uvicorn |
| | from fastapi import FastAPI, APIRouter, Request, Depends, HTTPException |
| | from fastapi.middleware.cors import CORSMiddleware |
| | from fastapi.staticfiles import StaticFiles |
| | import asyncio |
| | from concurrent.futures import ThreadPoolExecutor |
| | from fastapi.responses import JSONResponse |
| | import logging |
| | import time |
| | import os |
| | from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials |
| | import jwt |
| | from typing import Optional |
| |
|
| | from app.core.config import settings |
| | from app.api.routes.videos import router as videos_router |
| | from app.api.routes.auth import router as auth_router |
| | from app.api.routes.processing import router as processing_router |
| | from app.api.routes.users import router as users_router |
| | from app.api.routes.health import router as health_router |
| | from app.db.base import create_tables |
| |
|
| | |
| | create_tables() |
| |
|
| | |
| | logging.basicConfig(level=logging.INFO) |
| | logger = logging.getLogger(__name__) |
| |
|
| | |
| | security = HTTPBearer(auto_error=False) |
| |
|
| | |
| | async def verify_token(request: Request, credentials: Optional[HTTPAuthorizationCredentials] = Depends(security)): |
| | |
| | hf_token = request.query_params.get("__sign") |
| | if hf_token: |
| | try: |
| | |
| | jwt.decode(hf_token, options={"verify_signature": False}) |
| | return hf_token |
| | except jwt.InvalidTokenError: |
| | raise HTTPException(status_code=403, detail="Invalid HF Space token") |
| | |
| | |
| | if credentials: |
| | token = credentials.credentials |
| | if not token: |
| | raise HTTPException( |
| | status_code=401, |
| | detail="Invalid authentication credentials", |
| | headers={"WWW-Authenticate": "Bearer"}, |
| | ) |
| | return token |
| | |
| | |
| | raise HTTPException( |
| | status_code=401, |
| | detail="Authentication required", |
| | headers={"WWW-Authenticate": "Bearer"}, |
| | ) |
| |
|
| | |
| | app = FastAPI( |
| | title="Behavior Analytics API", |
| | description="API for behavior analytics processing", |
| | version="1.0.0", |
| | docs_url="/docs", |
| | redoc_url="/redoc", |
| | |
| | redirect_slashes=False |
| | ) |
| |
|
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=["*"], |
| | allow_credentials=True, |
| | allow_methods=["*"], |
| | allow_headers=["*"], |
| | ) |
| |
|
| | |
| | app.mount("/uploads", StaticFiles(directory=str(settings.UPLOAD_DIR)), name="uploads") |
| |
|
| | |
| | api_router = APIRouter() |
| |
|
| | |
| | api_router.include_router(videos_router) |
| | api_router.include_router(processing_router) |
| | api_router.include_router(users_router) |
| | api_router.include_router(auth_router) |
| |
|
| | |
| | app.include_router(api_router, prefix=settings.API_V1_STR) |
| |
|
| | |
| | app.include_router(health_router) |
| |
|
| | @app.middleware("http") |
| | async def log_requests(request: Request, call_next): |
| | """Log all requests and their processing time""" |
| | start_time = time.time() |
| | response = await call_next(request) |
| | process_time = time.time() - start_time |
| | logger.info(f"Path: {request.url.path} Method: {request.method} Time: {process_time:.2f}s Status: {response.status_code}") |
| | return response |
| |
|
| | @app.get("/") |
| | async def root(token: str = Depends(verify_token)): |
| | """Root endpoint that returns API status""" |
| | return { |
| | "status": "ok", |
| | "message": "Behavior Analytics API is running", |
| | "version": "1.0.0" |
| | } |
| |
|
| | @app.get("/health") |
| | async def health_check(): |
| | """Health check endpoint for Hugging Face Spaces""" |
| | return {"status": "ok"} |
| |
|
| | @app.on_event("shutdown") |
| | async def shutdown_event(): |
| | loop = asyncio.get_running_loop() |
| | with ThreadPoolExecutor() as pool: |
| | await loop.run_in_executor(pool, shutdown_tasks) |
| |
|
| | if __name__ == "__main__": |
| | uvicorn.run(app, host="0.0.0.0", port=7860, reload=True) |