GeoQuery / backend /main.py
GerardCB's picture
Deploy to Spaces (Final Clean)
4851501
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from pathlib import Path
import os
from backend.core.database import init_db
from backend.api.api import api_router
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
try:
await init_db()
except Exception as e:
print(f"WARNING: Database initialization failed. Running in MOCK mode. Error: {e}")
yield
# Shutdown
app = FastAPI(
title="GeoQuery API",
description="Geospatial Analysis Agent API",
version="0.1.0",
lifespan=lifespan
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # Allow all for dev
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(api_router, prefix="/api/v1")
# Serve static files (Frontend)
static_dir = Path(__file__).parent / "static"
if static_dir.exists():
app.mount("/_next", StaticFiles(directory=static_dir / "_next"), name="next")
# app.mount("/assets", StaticFiles(directory=static_dir / "assets"), name="assets") # Standard Next.js Output might not use this top-level
@app.get("/{full_path:path}")
async def serve_frontend(full_path: str):
# API requests are already handled by include_router above (because specific routes take precedence? No, order matters).
# Wait, explicit routes define earlier take precedence.
# But include_router adds routes.
# A catch-all route /{full_path:path} will capture everything NOT matched by previous routes.
# Since api_router is included first (implicitly? No, verify order).
# FastAPI router priority: First declared wins.
# So app.include_router MUST be before this catch-all. It is.
file_path = static_dir / full_path
if file_path.exists() and file_path.is_file():
return FileResponse(file_path)
# Fallback to index.html for SPA routing
index_path = static_dir / "index.html"
if index_path.exists():
return FileResponse(index_path)
return {"error": "Frontend not found"}
else:
@app.get("/")
def read_root():
return {"message": "GeoQuery API is running (Frontend not built)"}