python_app / app.py
cwadayi's picture
Update app.py
7c69a57 verified
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}")
@app.get("/")
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"}
@app.get("/earthquakes")
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}")