|
from fastapi import FastAPI, HTTPException |
|
from fastapi.middleware.cors import CORSMiddleware |
|
from fastapi.responses import JSONResponse, HTMLResponse |
|
import uvicorn |
|
import logging |
|
import sys |
|
from src.api.routes.health import health_status |
|
from src.api.routes.isrunning import is_running |
|
|
|
|
|
logging.basicConfig( |
|
level=logging.INFO, |
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', |
|
handlers=[ |
|
logging.StreamHandler(sys.stdout) |
|
] |
|
) |
|
|
|
logger = logging.getLogger(__name__) |
|
|
|
app = FastAPI( |
|
title="AdvisorAI Data API", |
|
description="API for AdvisorAI data pipeline and health monitoring", |
|
version="1.0.0" |
|
) |
|
|
|
|
|
app.add_middleware( |
|
CORSMiddleware, |
|
allow_origins=["*"], |
|
allow_credentials=True, |
|
allow_methods=["*"], |
|
allow_headers=["*"], |
|
) |
|
|
|
@app.exception_handler(Exception) |
|
async def global_exception_handler(request, exc): |
|
logger.error(f"Global exception handler caught: {exc}", exc_info=True) |
|
return JSONResponse( |
|
status_code=500, |
|
content={"detail": "Internal server error", "error": str(exc)} |
|
) |
|
|
|
@app.get('/health') |
|
def health(): |
|
"""Enhanced health check endpoint""" |
|
try: |
|
return health_status() |
|
except Exception as e: |
|
logger.error(f"Health check failed: {e}", exc_info=True) |
|
raise HTTPException(status_code=500, detail=f"Health check failed: {str(e)}") |
|
|
|
|
|
@app.get('/status') |
|
def status(): |
|
"""Check if the data pipeline is running and has recent data""" |
|
try: |
|
return is_running() |
|
except Exception as e: |
|
logger.error(f"Status check failed: {e}", exc_info=True) |
|
raise HTTPException(status_code=500, detail=f"Status check failed: {str(e)}") |
|
|
|
@app.get('/', response_class=HTMLResponse) |
|
def root(): |
|
"""Root endpoint returns simple HTML so HF Spaces iframe can render it.""" |
|
html = """ |
|
<!doctype html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="utf-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|
<title>AdvisorAI Data API</title> |
|
<style> |
|
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; padding: 24px; } |
|
code { background: #f5f5f5; padding: 2px 4px; border-radius: 4px; } |
|
.links a { margin-right: 12px; } |
|
</style> |
|
</head> |
|
<body> |
|
<h1>AdvisorAI Data API</h1> |
|
<p>Service is running.</p> |
|
<div class="links"> |
|
<a href="/health">/health</a> |
|
<a href="/status">/status</a> |
|
<a href="/api">/api (JSON)</a> |
|
</div> |
|
</body> |
|
</html> |
|
""" |
|
return HTMLResponse(content=html, status_code=200) |
|
|
|
@app.get('/api') |
|
def api_root(): |
|
"""JSON root for programmatic clients.""" |
|
return { |
|
"message": "AdvisorAI Data API", |
|
"version": "1.0.0", |
|
"endpoints": { |
|
"/health": "Health check with system metrics", |
|
"/status": "Data pipeline status", |
|
"/api": "This JSON endpoint", |
|
"/": "HTML landing page for Spaces" |
|
} |
|
} |
|
|
|
if __name__ == "__main__": |
|
uvicorn.run( |
|
"src.api.main:app", |
|
host="0.0.0.0", |
|
port=10000, |
|
workers=1, |
|
timeout_keep_alive=30, |
|
access_log=True |
|
) |