11import logging
2+ from contextlib import asynccontextmanager
23from pathlib import Path
34
45from anthropic import Anthropic
56from anthropic import __version__ as anthropic_version
6- from fastapi import FastAPI
7+ from fastapi import FastAPI , Request
78from fastapi .middleware .cors import CORSMiddleware
89from mangum import Mangum
910
2021from app .metrics import get_metrics_provider
2122from app .prompt import Prompt
2223
23- # Configure logging based on settings
24- settings = get_settings ()
25- log_level = getattr (logging , settings .log_level .upper (), logging .INFO )
26- logging .basicConfig (level = log_level )
27- logger = logging .getLogger ()
28- logger .setLevel (log_level )
2924
30- app = FastAPI (root_path = get_settings ().root_path )
25+ def configure_logging (log_level : str ) -> None :
26+ """Configure logging with the specified level."""
27+ level = getattr (logging , log_level .upper (), logging .INFO )
28+ logging .basicConfig (
29+ level = level ,
30+ format = "%(asctime)s [%(levelname)s] %(name)s: %(message)s" ,
31+ force = True , # Reconfigure if already configured
32+ )
33+
34+
35+ @asynccontextmanager
36+ async def lifespan (app : FastAPI ):
37+ """Configure app on startup, cleanup on shutdown."""
38+ # Startup
39+ settings = get_settings ()
40+ configure_logging (settings .log_level )
41+ logger = logging .getLogger (__name__ )
42+
43+ # Store shared resources in app.state
44+ app .state .settings = settings
45+ app .state .anthropic_client = Anthropic (api_key = settings .anthropic_api_key )
46+
47+ # Load the prompt configuration
48+ prompt_config_path = Path (__file__ ).parent / "prompt.yaml"
49+ app .state .prompt = Prompt (prompt_config_path )
50+
51+ logger .info (f"Application started with log level: { settings .log_level } " )
52+ logger .info (f"Anthropic SDK version: { anthropic_version } " )
53+ logger .info (f"Loaded prompt configuration from { prompt_config_path } " )
54+
55+ yield
56+
57+ # Shutdown
58+ logger .info ("Application shutting down" )
59+
60+
61+ # Get settings once for app-level configuration
62+ # This is acceptable since these settings don't change during runtime
63+ _app_settings = get_settings ()
64+ app = FastAPI (root_path = _app_settings .root_path , lifespan = lifespan )
3165
3266# Configure CORS - allows all origins for public API
3367app .add_middleware (
4074)
4175handler = Mangum (app )
4276
43- anthropic_client = Anthropic (api_key = get_settings ().anthropic_api_key )
44- logger .info (f"Anthropic SDK version: { anthropic_version } " )
45-
46- # Load the prompt configuration
47- prompt_config_path = Path (__file__ ).parent / "prompt.yaml"
48- prompt = Prompt (prompt_config_path )
49- logger .info (f"Loaded prompt configuration from { prompt_config_path } " )
5077
51-
52- def get_cache_provider ():
78+ def get_cache_provider (settings ) -> NoOpCacheProvider | S3CacheProvider :
5379 """Get the configured cache provider."""
54- settings = get_settings ( )
80+ logger = logging . getLogger ( __name__ )
5581
5682 if not settings .cache_enabled :
5783 logger .info ("Caching disabled by configuration" )
@@ -73,8 +99,9 @@ def get_cache_provider():
7399
74100
75101@app .get ("/" , response_model = AvailableOptions )
76- async def get_options () -> AvailableOptions :
102+ async def get_options (request : Request ) -> AvailableOptions :
77103 """Get available options for the explain API."""
104+ prompt = request .app .state .prompt
78105 async with get_metrics_provider () as metrics_provider :
79106 metrics_provider .put_metric ("ClaudeExplainOptionsRequest" , 1 )
80107 return AvailableOptions (
@@ -96,8 +123,14 @@ async def get_options() -> AvailableOptions:
96123
97124
98125@app .post ("/" )
99- async def explain (request : ExplainRequest ) -> ExplainResponse :
126+ async def explain (explain_request : ExplainRequest , request : Request ) -> ExplainResponse :
100127 """Explain a Compiler Explorer compilation from its source and output assembly."""
101128 async with get_metrics_provider () as metrics_provider :
102- cache_provider = get_cache_provider ()
103- return await process_request (request , anthropic_client , prompt , metrics_provider , cache_provider )
129+ cache_provider = get_cache_provider (request .app .state .settings )
130+ return await process_request (
131+ explain_request ,
132+ request .app .state .anthropic_client ,
133+ request .app .state .prompt ,
134+ metrics_provider ,
135+ cache_provider ,
136+ )
0 commit comments