cwadayi commited on
Commit
d2a98c6
·
verified ·
1 Parent(s): c472fc7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -81
app.py CHANGED
@@ -1,96 +1,147 @@
1
- from fastapi import FastAPI, HTTPException, Query
2
- from starlette.responses import JSONResponse
3
- from obspy.clients.fdsn import Client
4
- from obspy.core.utcdatetime import UTCDateTime
5
- import logging
6
- from datetime import date
7
 
8
- # Configure logging
9
- logging.basicConfig(level=logging.INFO)
10
 
11
- # Initialize the FastAPI app
12
- app = FastAPI(
13
- title="Dynamic Earthquake Catalog API",
14
- description="A robust API to fetch earthquake data from the IRIS FDSN web service using URL parameters.",
15
- version="2.1.0",
16
- )
17
 
18
- # Initialize the IRIS FDSN client
19
- try:
20
- client = Client("IRIS")
21
- logging.info("Successfully initialized IRIS FDSN client.")
22
- except Exception as e:
23
- client = None
24
- logging.error(f"Could not initialize IRIS FDSN client on startup: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
  @app.get("/")
27
- def greet_json():
28
- """
29
- A simple 'Hello World' endpoint.
30
- """
31
- 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"}
32
 
33
- @app.get("/earthquakes")
34
- async def get_earthquake_catalog(
35
- start_date: date = Query(default="2024-01-01", description="Start date in YYYY-MM-DD format"),
36
- end_date: date = Query(default="2024-01-07", description="End date in YYYY-MM-DD format"),
37
- min_magnitude: float = Query(default=4.5, description="Minimum earthquake magnitude (e.g., 5.5)", gt=0, le=10)
38
- ):
39
- """
40
- Fetches earthquake data based on date and magnitude parameters provided in the URL.
41
- """
42
- if not client:
43
- raise HTTPException(status_code=503, detail="The IRIS FDSN client is not available.")
44
-
45
- if start_date > end_date:
46
- raise HTTPException(status_code=400, detail="The start_date cannot be after the end_date.")
 
47
 
 
 
 
 
48
  try:
49
- starttime = UTCDateTime(start_date)
50
- endtime = UTCDateTime(end_date)
 
 
 
 
 
 
 
51
 
52
- logging.info(f"Fetching events from {starttime} to {endtime} with min magnitude {min_magnitude}.")
53
- catalog = client.get_events(
54
- starttime=starttime,
55
- endtime=endtime,
56
- minmagnitude=min_magnitude,
57
- )
58
- logging.info(f"Found {len(catalog)} events. Now processing.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
- earthquake_list = []
61
- for event in catalog:
62
- try:
63
- origin = event.preferred_origin()
64
- magnitude = event.preferred_magnitude()
65
 
66
- if not origin or not magnitude:
67
- continue
68
 
69
- # --- Key Change Start ---
70
- # Safely get the description using getattr. This avoids errors if the 'descriptions'
71
- # attribute doesn't exist, by providing a default empty list [].
72
- place = "N/A"
73
- descriptions = getattr(event, 'descriptions', [])
74
- if descriptions:
75
- place = descriptions[0].text
76
- # --- Key Change End ---
77
 
78
- earthquake_list.append({
79
- "time": origin.time.isoformat(),
80
- "latitude": origin.latitude,
81
- "longitude": origin.longitude,
82
- "depth_km": origin.depth / 1000.0 if origin.depth is not None else None,
83
- "magnitude": magnitude.mag,
84
- "magnitude_type": magnitude.magnitude_type,
85
- "place": place,
86
- })
87
- except Exception as e:
88
- logging.warning(f"Skipping event due to unexpected processing error: {e}")
89
- continue
90
-
91
- logging.info(f"Successfully processed {len(earthquake_list)} events.")
92
- return JSONResponse(content={"earthquakes": earthquake_list})
93
 
 
 
 
 
 
 
 
 
 
 
94
  except Exception as e:
95
- logging.error(f"A major error occurred during the request: {e}")
96
- raise HTTPException(status_code=500, detail=f"An internal error occurred: {e}")
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ import sqlite3
3
+ import os
 
 
 
4
 
5
+ app = FastAPI()
 
6
 
7
+ # Define the path for your SQLite database file
8
+ # This will be created in the /app directory of your Hugging Face Space.
9
+ # Files in /app are generally persisted across restarts within a Space.
10
+ DATABASE_FILE = os.path.join(os.getcwd(), "data.db")
 
 
11
 
12
+ def get_db_connection():
13
+ try:
14
+ conn = sqlite3.connect(DATABASE_FILE)
15
+ # Configure connection to return rows as dictionaries for easier access
16
+ conn.row_factory = sqlite3.Row
17
+ return conn
18
+ except sqlite3.Error as err:
19
+ print(f"Error connecting to database: {err}")
20
+ raise HTTPException(status_code=500, detail="Database connection error")
21
+
22
+ @app.on_event("startup")
23
+ async def startup_event():
24
+ # Create tables if they don't exist
25
+ conn = None # Initialize conn to None
26
+ try:
27
+ conn = get_db_connection()
28
+ cursor = conn.cursor()
29
+ cursor.execute("""
30
+ CREATE TABLE IF NOT EXISTS items (
31
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
32
+ name TEXT NOT NULL,
33
+ description TEXT
34
+ )
35
+ """)
36
+ conn.commit()
37
+ print(f"Database table 'items' checked/created successfully at {DATABASE_FILE}.")
38
+ except Exception as e:
39
+ print(f"Error during database startup: {e}")
40
+ # In a real app, you might want to handle this more gracefully,
41
+ # e.g., log the error and potentially shut down if essential tables can't be created.
42
+ finally:
43
+ if conn:
44
+ conn.close()
45
 
46
  @app.get("/")
47
+ async def root():
48
+ return {"message": "Welcome to the API!"}
 
 
 
49
 
50
+ @app.post("/items/")
51
+ async def create_item(name: str, description: str = None):
52
+ conn = get_db_connection()
53
+ cursor = conn.cursor()
54
+ try:
55
+ query = "INSERT INTO items (name, description) VALUES (?, ?)"
56
+ cursor.execute(query, (name, description))
57
+ conn.commit()
58
+ return {"message": "Item created successfully", "id": cursor.lastrowid}
59
+ except Exception as e:
60
+ conn.rollback()
61
+ raise HTTPException(status_code=500, detail=f"Error creating item: {e}")
62
+ finally:
63
+ cursor.close()
64
+ conn.close()
65
 
66
+ @app.get("/items/")
67
+ async def read_items():
68
+ conn = get_db_connection()
69
+ cursor = conn.cursor()
70
  try:
71
+ cursor.execute("SELECT * FROM items")
72
+ items = cursor.fetchall()
73
+ # Convert sqlite3.Row objects to dictionaries for JSON serialization
74
+ return {"items": [dict(item) for item in items]}
75
+ except Exception as e:
76
+ raise HTTPException(status_code=500, detail=f"Error reading items: {e}")
77
+ finally:
78
+ cursor.close()
79
+ conn.close()
80
 
81
+ @app.get("/items/{item_id}")
82
+ async def read_item(item_id: int):
83
+ conn = get_db_connection()
84
+ cursor = conn.cursor()
85
+ try:
86
+ cursor.execute("SELECT * FROM items WHERE id = ?", (item_id,))
87
+ item = cursor.fetchone()
88
+ if item is None:
89
+ raise HTTPException(status_code=404, detail="Item not found")
90
+ return dict(item)
91
+ except Exception as e:
92
+ raise HTTPException(status_code=500, detail=f"Error reading item: {e}")
93
+ finally:
94
+ cursor.close()
95
+ conn.close()
96
+
97
+ @app.put("/items/{item_id}")
98
+ async def update_item(item_id: int, name: str = None, description: str = None):
99
+ conn = get_db_connection()
100
+ cursor = conn.cursor()
101
+ try:
102
+ updates = []
103
+ params = []
104
+ if name is not None:
105
+ updates.append("name = ?")
106
+ params.append(name)
107
+ if description is not None:
108
+ updates.append("description = ?")
109
+ params.append(description)
110
 
111
+ if not updates:
112
+ raise HTTPException(status_code=400, detail="No fields to update provided")
 
 
 
113
 
114
+ query = f"UPDATE items SET {', '.join(updates)} WHERE id = ?"
115
+ params.append(item_id)
116
 
117
+ cursor.execute(query, tuple(params))
118
+ conn.commit()
 
 
 
 
 
 
119
 
120
+ if cursor.rowcount == 0:
121
+ raise HTTPException(status_code=404, detail="Item not found")
122
+ return {"message": "Item updated successfully"}
123
+ except HTTPException: # Re-raise if it's already an HTTPException
124
+ raise
125
+ except Exception as e:
126
+ conn.rollback()
127
+ raise HTTPException(status_code=500, detail=f"Error updating item: {e}")
128
+ finally:
129
+ cursor.close()
130
+ conn.close()
 
 
 
 
131
 
132
+ @app.delete("/items/{item_id}")
133
+ async def delete_item(item_id: int):
134
+ conn = get_db_connection()
135
+ cursor = conn.cursor()
136
+ try:
137
+ cursor.execute("DELETE FROM items WHERE id = ?", (item_id,))
138
+ conn.commit()
139
+ if cursor.rowcount == 0:
140
+ raise HTTPException(status_code=404, detail="Item not found")
141
+ return {"message": "Item deleted successfully"}
142
  except Exception as e:
143
+ conn.rollback()
144
+ raise HTTPException(status_code=500, detail=f"Error deleting item: {e}")
145
+ finally:
146
+ cursor.close()
147
+ conn.close()