File size: 5,132 Bytes
ab07cb1 dac021d ab07cb1 973d6a7 ab07cb1 973d6a7 2627f59 973d6a7 ab07cb1 973d6a7 ab07cb1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | """
Eurus Web Application
======================
FastAPI application factory and main entry point.
"""
import os
import sys
import logging
from pathlib import Path
from contextlib import asynccontextmanager
from dotenv import load_dotenv
load_dotenv() # Load .env EARLY so /api/keys-status sees the keys
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
# Add parent and src directory to path for eurus package
PROJECT_ROOT = Path(__file__).parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
sys.path.insert(0, str(PROJECT_ROOT / "src"))
# IMPORT FROM EURUS PACKAGE
from eurus.config import CONFIG, PLOTS_DIR
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s | %(levelname)s | %(name)s | %(message)s',
datefmt='%H:%M:%S'
)
logger = logging.getLogger(__name__)
# Paths
WEB_DIR = Path(__file__).parent
TEMPLATES_DIR = WEB_DIR / "templates"
STATIC_DIR = WEB_DIR / "static"
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Application lifespan handler for startup/shutdown."""
# Startup
logger.info("Starting Eurus Web Interface...")
logger.info(f"Templates: {TEMPLATES_DIR}")
logger.info(f"Static files: {STATIC_DIR}")
logger.info(f"Plots directory: {PLOTS_DIR}")
# Sessions are created per-connection in websocket.py
logger.info("Ready to accept connections")
yield
# Shutdown
logger.info("Shutting down Eurus Web Interface...")
from web.agent_wrapper import shutdown_agent_session
shutdown_agent_session()
def create_app() -> FastAPI:
"""Create and configure the FastAPI application."""
app = FastAPI(
title="Eurus Climate Agent",
description="Interactive web interface for ERA5 climate data analysis",
version="1.0.0",
lifespan=lifespan,
)
# CORS β allow React dev server
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=False,
allow_methods=["*"],
allow_headers=["*"],
)
# Mount static files
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
# Mount plots directory for serving generated plots
PLOTS_DIR.mkdir(parents=True, exist_ok=True)
app.mount("/plots", StaticFiles(directory=str(PLOTS_DIR)), name="plots")
# Include routers
from web.routes import api_router, websocket_router, pages_router
app.include_router(api_router, prefix="/api", tags=["api"])
app.include_router(websocket_router, tags=["websocket"])
app.include_router(pages_router, tags=["pages"])
return app
# Create the app instance
app = create_app()
def main():
"""Main entry point for running the web server."""
import uvicorn
host = getattr(CONFIG, 'web_host', '127.0.0.1')
port = getattr(CONFIG, 'web_port', 8000)
print(f"""
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β
β βββββββββββ ββββββββββ βββ βββββββββββ β
β βββββββββββ ββββββββββββββ βββββββββββ β
β ββββββ βββ ββββββββββββββ βββββββββββ β
β ββββββ βββ ββββββββββββββ βββββββββββ β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β ββββββββ βββββββ βββ βββ βββββββ ββββββββ β
β β
β Eurus Web Interface v1.0 β
β βββββββββββββββββββββββββββββββββββββ β
β β
β Starting server at: http://{host}:{port} β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
""")
uvicorn.run(
"web.app:app",
host=host,
port=port,
reload=False,
log_level="info",
)
if __name__ == "__main__":
main()
|