File size: 5,751 Bytes
f4202e1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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()