FREDML / src /main.py
Edwin Salguero
Enterprise: Transform to production-grade architecture with FastAPI, Docker, K8s, monitoring, and comprehensive tooling
832348e
#!/usr/bin/env python3
"""
FRED ML - Main Application Entry Point
Production-grade FastAPI application for economic data analysis
"""
import logging
import os
from contextlib import asynccontextmanager
import uvicorn
from fastapi import Depends, FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from config.settings import FRED_API_KEY
from src.analysis.advanced_analytics import AdvancedAnalytics
from src.core.fred_client import FREDDataCollectorV2
# Configure logging
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)
# Global variables for application state
collector = None
analytics = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan manager"""
# Startup
global collector, analytics
logger.info("Starting FRED ML application...")
if not FRED_API_KEY:
logger.error("FRED_API_KEY not configured")
raise ValueError("FRED_API_KEY environment variable is required")
collector = FREDDataCollectorV2(api_key=FRED_API_KEY)
logger.info("FRED Data Collector initialized")
yield
# Shutdown
logger.info("Shutting down FRED ML application...")
# Create FastAPI application
app = FastAPI(
title="FRED ML API",
description="Economic Data Analysis API using Federal Reserve Economic Data",
version="1.0.0",
lifespan=lifespan,
)
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def root():
"""Root endpoint"""
return {"message": "FRED ML API", "version": "1.0.0", "status": "running"}
@app.get("/health")
async def health_check():
"""Health check endpoint"""
return {"status": "healthy"}
@app.get("/ready")
async def readiness_check():
"""Readiness check endpoint"""
if collector is None:
raise HTTPException(status_code=503, detail="Service not ready")
return {"status": "ready"}
@app.get("/api/v1/indicators")
async def get_indicators():
"""Get available economic indicators"""
if collector is None:
raise HTTPException(status_code=503, detail="Service not ready")
return {
"indicators": list(collector.indicators.keys()),
"descriptions": collector.indicators,
}
@app.post("/api/v1/analyze")
async def analyze_data(
series_ids: list[str], start_date: str = None, end_date: str = None
):
"""Analyze economic data for specified series"""
if collector is None:
raise HTTPException(status_code=503, detail="Service not ready")
try:
df, summary = collector.run_analysis(
series_ids=series_ids, start_date=start_date, end_date=end_date
)
return {
"status": "success",
"data_shape": df.shape if df is not None else None,
"summary": summary.to_dict() if summary is not None else None,
}
except Exception as e:
logger.error(f"Analysis failed: {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.get("/api/v1/status")
async def get_status():
"""Get application status"""
return {
"api_key_configured": bool(FRED_API_KEY),
"collector_initialized": collector is not None,
"environment": os.getenv("ENVIRONMENT", "development"),
}
if __name__ == "__main__":
port = int(os.getenv("PORT", 8000))
uvicorn.run(
"src.main:app",
host="0.0.0.0",
port=port,
reload=os.getenv("ENVIRONMENT") == "development",
)