Spaces:
Running
Running
| from fastapi import FastAPI, HTTPException, Query | |
| from starlette.responses import JSONResponse | |
| from obspy.clients.fdsn import Client | |
| from obspy.core.utcdatetime import UTCDateTime | |
| import logging | |
| from datetime import date | |
| # Configure logging | |
| logging.basicConfig(level=logging.INFO) | |
| # Initialize the FastAPI app | |
| app = FastAPI( | |
| title="Dynamic Earthquake Catalog API", | |
| description="A robust API to fetch earthquake data from the IRIS FDSN web service using URL parameters.", | |
| version="2.1.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}") | |
| def greet_json(): | |
| """ | |
| A simple 'Hello World' endpoint. | |
| """ | |
| return {"Hello": "World!", "message": "Go to /docs to try the dynamic earthquake endpoint. cwadayi \n https://cwadayi-python-app.hf.space/earthquakes?start_date=2024-07-01&end_date=2024-07-07&min_magnitude=5.0"} | |
| async def get_earthquake_catalog( | |
| start_date: date = Query(default="2024-01-01", description="Start date in YYYY-MM-DD format"), | |
| end_date: date = Query(default="2024-01-07", description="End date in YYYY-MM-DD format"), | |
| min_magnitude: float = Query(default=4.5, description="Minimum earthquake magnitude (e.g., 5.5)", gt=0, le=10) | |
| ): | |
| """ | |
| Fetches earthquake data based on date and magnitude parameters provided in the URL. | |
| """ | |
| if not client: | |
| raise HTTPException(status_code=503, detail="The IRIS FDSN client is not available.") | |
| if start_date > end_date: | |
| raise HTTPException(status_code=400, detail="The start_date cannot be after the end_date.") | |
| try: | |
| starttime = UTCDateTime(start_date) | |
| endtime = UTCDateTime(end_date) | |
| 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 = [] | |
| for event in catalog: | |
| try: | |
| origin = event.preferred_origin() | |
| magnitude = event.preferred_magnitude() | |
| if not origin or not magnitude: | |
| continue | |
| # --- Key Change Start --- | |
| # Safely get the description using getattr. This avoids errors if the 'descriptions' | |
| # attribute doesn't exist, by providing a default empty list []. | |
| place = "N/A" | |
| descriptions = getattr(event, 'descriptions', []) | |
| if descriptions: | |
| place = descriptions[0].text | |
| # --- Key Change End --- | |
| 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: | |
| logging.warning(f"Skipping event due to unexpected processing error: {e}") | |
| continue | |
| 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, detail=f"An internal error occurred: {e}") |