neotwin-api / app.py
1qwsd's picture
ci: auto-deploy from GitHub Actions
213617b verified
Raw
History Blame Contribute Delete
2.81 kB
"""
NeoTwin β€” Main FastAPI Application
Production-ready backend for 3D Digital Twin Platform
"""
from fastapi import FastAPI, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware
from contextlib import asynccontextmanager
import os
from dotenv import load_dotenv
load_dotenv()
# Force early PyTorch import to ensure transformers pipelines register it correctly
import torch
# CORS: read comma-separated origins from env ("*" for open access)
_raw_origins = os.getenv("ALLOWED_ORIGINS", "*")
ALLOWED_ORIGINS = [o.strip() for o in _raw_origins.split(",")]
from api.routes_search import router as search_router
from api.routes_identify import router as identify_router
from api.routes_narrate import router as narrate_router
from api.routes_pipeline import router as pipeline_router
from api.routes_health import router as health_router
from core.config import settings
from core.monitoring import setup_monitoring
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application startup and shutdown"""
print("πŸš€ NeoTwin Backend Starting...")
print(f"πŸ“Š Monitoring: {settings.ENABLE_MONITORING}")
print(f"πŸ€– AI Provider: Gemini 2.0 Flash")
yield
print("πŸ‘‹ NeoTwin Backend Shutting Down...")
app = FastAPI(
title="NeoTwin API",
description="Production-ready 3D Digital Twin Backend",
version="1.0.0",
lifespan=lifespan
)
# CORS β€” driven by ALLOWED_ORIGINS env var
app.add_middleware(
CORSMiddleware,
allow_origins=ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Security headers
app.add_middleware(
TrustedHostMiddleware,
allowed_hosts=["*"] # Restrict in production
)
# Setup monitoring
if settings.ENABLE_MONITORING:
setup_monitoring(app)
from fastapi.staticfiles import StaticFiles
# Ensure data directory exists and mount it statically to serve reconstruction outputs
os.makedirs("data", exist_ok=True)
app.mount("/data", StaticFiles(directory="data"), name="data")
# Include routers
app.include_router(health_router, prefix="/api/v1", tags=["health"])
app.include_router(search_router, prefix="/api/v1", tags=["search"])
app.include_router(identify_router, prefix="/api/v1", tags=["identify"])
app.include_router(narrate_router, prefix="/api/v1", tags=["narrate"])
app.include_router(pipeline_router, prefix="/api/v1", tags=["pipeline"])
@app.get("/")
async def root():
return {
"name": "NeoTwin API",
"version": "1.0.0",
"status": "running",
"docs": "/docs"
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app:app",
host="0.0.0.0",
port=int(os.getenv("PORT", 7860)),
reload=True
)