Spaces:
Sleeping
Sleeping
| import requests | |
| import gradio as gr | |
| from datetime import datetime, timedelta | |
| # USGS API 的基礎 URL | |
| USGS_API_BASE_URL = "https://earthquake.usgs.gov/fdsnws/event/1/query" | |
| def format_earthquake_info_markdown(data): | |
| """ | |
| 將從 API 獲取的地震資料格式化為 Markdown 字串。 | |
| """ | |
| if not data or 'features' not in data or not data['features']: | |
| return "在指定的條件下,找不到任何地震資料。" | |
| count = data['metadata']['count'] | |
| title = data['metadata']['title'] | |
| # 建立 Markdown 表格的標頭 | |
| md_output = f"## {title}\n\n" | |
| md_output += f"**查詢成功,共找到 {count} 筆地震資料。**\n\n" | |
| md_output += "| 時間 (UTC) | 地點 | 芮氏規模 | 深度 (公里) | 經緯度 |\n" | |
| md_output += "|---|---|---|---|---|\n" | |
| # 填入每一筆地震資料 | |
| for feature in data['features']: | |
| properties = feature['properties'] | |
| geometry = feature['geometry'] | |
| event_time_utc = datetime.fromtimestamp(properties['time'] / 1000) | |
| time_str = event_time_utc.strftime('%Y-%m-%d %H:%M:%S') | |
| magnitude = properties['mag'] | |
| place = properties['place'].replace('|', '\|') # 避免 Markdown 表格語法衝突 | |
| longitude, latitude, depth = geometry['coordinates'] | |
| md_output += f"| {time_str} | {place} | {magnitude:.2f} | {depth:.2f} | ({latitude:.4f}, {longitude:.4f}) |\n" | |
| return md_output | |
| def query_earthquakes( | |
| starttime_str: str, | |
| endtime_str: str, | |
| min_magnitude: float, | |
| use_geo: bool, | |
| min_lat: float, max_lat: float, | |
| min_lon: float, max_lon: float | |
| ): | |
| """ | |
| 接收來自 Gradio UI 的輸入,查詢並回傳格式化的地震資料。 | |
| """ | |
| params = { | |
| "format": "geojson", | |
| "starttime": starttime_str, | |
| "endtime": endtime_str, | |
| "minmagnitude": min_magnitude, | |
| "limit": 500, # 限制回傳數量,避免 UI 過於壅塞 | |
| "orderby": "time" | |
| } | |
| # 如果使用者勾選了 "指定地理範圍" | |
| if use_geo: | |
| # 簡單的驗證 | |
| if not all([min_lat, max_lat, min_lon, max_lon]): | |
| return "錯誤:若要指定地理範圍,則經緯度四個欄位皆須填寫。" | |
| if min_lat >= max_lat or min_lon >= max_lon: | |
| return "錯誤:最小經緯度必須小於最大經緯度。" | |
| params.update({ | |
| "minlatitude": min_lat, | |
| "maxlatitude": max_lat, | |
| "minlongitude": min_lon, | |
| "maxlongitude": max_lon | |
| }) | |
| try: | |
| response = requests.get(USGS_API_BASE_URL, params=params, timeout=20) | |
| response.raise_for_status() | |
| data = response.json() | |
| return format_earthquake_info_markdown(data) | |
| except requests.exceptions.RequestException as e: | |
| return f"錯誤:網路請求失敗: {e}" | |
| except Exception as e: | |
| return f"發生未知錯誤: {e}" | |
| # --- Gradio 介面設計 --- | |
| with gr.Blocks(theme=gr.themes.Soft()) as demo: | |
| gr.Markdown("# 🌎 USGS 地震資料查詢工具") | |
| gr.Markdown("透過此工具,您可以查詢美國地質調查局 (USGS) 的全球地震紀錄。") | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| gr.Markdown("### 1. 設定查詢條件") | |
| # 預設查詢時間為過去 7 天 | |
| today = datetime.now() | |
| seven_days_ago = today - timedelta(days=7) | |
| starttime_input = gr.Textbox(label="查詢開始日期", value=seven_days_ago.strftime('%Y-%m-%d')) | |
| endtime_input = gr.Textbox(label="查詢結束日期", value=today.strftime('%Y-%m-%d')) | |
| magnitude_slider = gr.Slider( | |
| minimum=0, maximum=10, step=0.1, | |
| label="最小芮氏規模", | |
| value=4.5 | |
| ) | |
| gr.Markdown("### 2. (可選) 指定地理範圍") | |
| use_geo_checkbox = gr.Checkbox(label="啟用地理範圍篩選", value=False) | |
| with gr.Row(): | |
| min_lat_input = gr.Number(label="最小緯度 (南)", value=21.5) | |
| max_lat_input = gr.Number(label="最大緯度 (北)", value=25.5) | |
| with gr.Row(): | |
| min_lon_input = gr.Number(label="最小經度 (西)", value=120.0) | |
| max_lon_input = gr.Number(label="最大經度 (東)", value=122.5) | |
| submit_btn = gr.Button("開始查詢", variant="primary") | |
| with gr.Column(scale=3): | |
| gr.Markdown("### 查詢結果") | |
| output_markdown = gr.Markdown("點擊「開始查詢」後,結果將會顯示於此。") | |
| # 綁定按鈕點擊事件 | |
| submit_btn.click( | |
| fn=query_earthquakes, | |
| inputs=[ | |
| starttime_input, | |
| endtime_input, | |
| magnitude_slider, | |
| use_geo_checkbox, | |
| min_lat_input, max_lat_input, | |
| min_lon_input, max_lon_input | |
| ], | |
| outputs=output_markdown | |
| ) | |
| gr.Examples( | |
| examples=[ | |
| [seven_days_ago.strftime('%Y-%m-%d'), today.strftime('%Y-%m-%d'), 6.0, False, 0, 0, 0, 0], | |
| ["2024-04-02", "2024-04-04", 5.5, True, 23.0, 25.0, 121.0, 122.5], | |
| ["2024-01-01", "2024-01-02", 7.0, True, 35.0, 38.0, 136.0, 140.0], | |
| ], | |
| inputs=[ | |
| starttime_input, | |
| endtime_input, | |
| magnitude_slider, | |
| use_geo_checkbox, | |
| min_lat_input, max_lat_input, | |
| min_lon_input, max_lon_input | |
| ], | |
| outputs=output_markdown, | |
| fn=query_earthquakes, | |
| cache_examples=True # 讓範例結果快取,加速載入 | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch() | |