from fastapi import FastAPI, HTTPException from starlette.responses import JSONResponse from obspy.clients.fdsn import Client from obspy.core.utcdatetime import UTCDateTime import logging # Configure logging logging.basicConfig(level=logging.INFO) # Initialize the FastAPI app app = FastAPI( title="Earthquake Catalog API", description="An API to fetch earthquake data from the IRIS FDSN web service, ready for Hugging Face.", version="1.0.0", ) # Initialize the IRIS FDSN client try: client = Client("IRIS") logging.info("Successfully initialized IRIS FDSN client.") except Exception as e: client = None logging.error(f"Could not initialize IRIS FDSN client on startup: {e}") @app.get("/") def greet_json(): """ A simple 'Hello World' endpoint. """ return {"Hello": "World!", "message": "Go to /earthquakes to fetch data, or /docs for the API documentation. Dayi"} @app.get("/earthquakes") async def get_earthquake_catalog(): """ Fetches earthquake data with a magnitude larger than 5.0 from 2015-01-05 to 2016-03-05. """ if not client: raise HTTPException( status_code=503, # Service Unavailable detail="The IRIS FDSN client is not available or failed to initialize.", ) try: starttime = UTCDateTime("2015-01-05") endtime = UTCDateTime("2016-03-05") min_magnitude = 5.0 logging.info(f"Fetching events from {starttime} to {endtime} with min magnitude {min_magnitude}.") catalog = client.get_events( starttime=starttime, endtime=endtime, minmagnitude=min_magnitude, ) logging.info(f"Found {len(catalog)} events. Now processing.") earthquake_list = [] # --- Key Change Start --- # Loop through each event and process it individually to prevent one bad event from crashing the app. for event in catalog: try: # Ensure the event has a preferred origin and magnitude if not event.preferred_origin() or not event.preferred_magnitude(): continue # Skip to the next event if essential data is missing origin = event.preferred_origin() magnitude = event.preferred_magnitude() # Safely extract the place description place = "N/A" if event.descriptions: # Check if the descriptions list exists and is not empty place = event.descriptions[0].text earthquake_list.append({ "time": origin.time.isoformat(), "latitude": origin.latitude, "longitude": origin.longitude, "depth_km": origin.depth / 1000.0 if origin.depth is not None else None, "magnitude": magnitude.mag, "magnitude_type": magnitude.magnitude_type, "place": place, }) except Exception as e: # If a single event fails, log it and continue with the others. logging.warning(f"Skipping one event due to a processing error: {e}") continue # --- Key Change End --- logging.info(f"Successfully processed {len(earthquake_list)} events.") return JSONResponse(content={"earthquakes": earthquake_list}) except Exception as e: logging.error(f"A major error occurred during the request: {e}") raise HTTPException( status_code=500, # Internal Server Error detail=f"An internal error occurred: {e}", )