Spaces:
Sleeping
Sleeping
| import os | |
| from pathlib import Path | |
| from dotenv import load_dotenv | |
| load_dotenv(Path(__file__).resolve().parent.parent / ".env") | |
| from contextlib import asynccontextmanager | |
| from fastapi import FastAPI, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import FileResponse | |
| from fastapi.staticfiles import StaticFiles | |
| from app.db.session import engine, Base | |
| from app.db.asyncpg_pool import close_asyncpg_pool, init_asyncpg_pool | |
| # Intel routers (SQLAlchemy) | |
| from app.routers import admin, query, results, upload | |
| # Shop routers (asyncpg) | |
| from app.routers import analytics, auth, orders, products, admin_orders, intel_live | |
| async def lifespan(app: FastAPI): | |
| try: | |
| from app.db import models | |
| Base.metadata.create_all(bind=engine) | |
| print("SQLAlchemy tables ready: jobs, customer_profiles, insights.") | |
| except Exception as e: | |
| print(f"SQLAlchemy startup error: {e}") | |
| try: | |
| await init_asyncpg_pool() | |
| except Exception as e: | |
| print(f"asyncpg startup error: {e}") | |
| raise | |
| try: | |
| yield | |
| finally: | |
| try: | |
| await close_asyncpg_pool() | |
| print("asyncpg pool closed") | |
| except Exception as e: | |
| print(f"Warning: error closing pool: {e}") | |
| app = FastAPI( | |
| title="ThreadHouse + Customer Intelligence Engine", | |
| version="1.0.0", | |
| lifespan=lifespan, | |
| docs_url="/docs", | |
| redoc_url="/redoc", | |
| ) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origin_regex=r"http://(localhost|127\.0\.0\.1):\d+", | |
| allow_credentials=False, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # Intel / CIE routers - match what frontend/src/services/api.js expects. | |
| app.include_router(upload.router, prefix="/api", tags=["Upload"]) | |
| app.include_router(results.router, prefix="/api", tags=["Results"]) | |
| app.include_router(query.router, prefix="/api", tags=["Query"]) | |
| app.include_router(admin.router, prefix="/api", tags=["Admin"]) | |
| # Shop routers - match what Login.jsx, ShopContext.jsx, useAnalytics.js expect. | |
| app.include_router(auth.router, prefix="/api/auth", tags=["Auth"]) | |
| app.include_router(orders.router, prefix="/api/orders", tags=["Orders"]) | |
| app.include_router(analytics.router, prefix="/api/analytics", tags=["Analytics"]) | |
| # Legacy alias for admin/Login.jsx (POST /api/user/admin) | |
| app.include_router(auth.admin_alias_router, prefix="/api/user", tags=["Auth (legacy alias)"]) | |
| # Admin panel singular-path endpoints. | |
| app.include_router(products.router, prefix="/api/product", tags=["Products (admin)"]) | |
| app.include_router(admin_orders.router, prefix="/api/order", tags=["Orders (admin)"]) | |
| app.include_router(intel_live.router, prefix="/api/intel", tags=["Intel (live)"]) | |
| # Static files (product images uploaded via the admin panel). | |
| import os as _os | |
| _STATIC_DIR = _os.path.join(_os.path.dirname(__file__), "..", "static") | |
| _os.makedirs(_os.path.join(_STATIC_DIR, "images"), exist_ok=True) | |
| app.mount("/static", StaticFiles(directory=_STATIC_DIR), name="static") | |
| def health(): | |
| return {"status": "healthy"} | |
| # Optional: if the frontend has been built into ../frontend/dist, serve it. | |
| FRONTEND_DIST = os.path.join(os.path.dirname(__file__), "..", "..", "frontend", "dist") | |
| if os.path.exists(FRONTEND_DIST): | |
| app.mount( | |
| "/assets", | |
| StaticFiles(directory=os.path.join(FRONTEND_DIST, "assets")), | |
| name="assets", | |
| ) | |
| async def serve_react(full_path: str): | |
| if full_path.startswith("api/"): | |
| raise HTTPException(status_code=404, detail="API route not found") | |
| index_file = os.path.join(FRONTEND_DIST, "index.html") | |
| if os.path.exists(index_file): | |
| return FileResponse(index_file) | |
| return {"error": "Frontend not built yet."} | |
| else: | |
| def root(): | |
| return { | |
| "message": "ThreadHouse + Customer Intelligence Engine API", | |
| "note": "Frontend not built. Run: cd frontend && npm run build", | |
| "docs": "/docs", | |
| } | |