nakas commited on
Commit
5fcb9c7
Β·
verified Β·
1 Parent(s): 6e1cc9d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +275 -0
app.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+ import json
4
+ import pandas as pd
5
+ from datetime import datetime
6
+ import matplotlib.pyplot as plt
7
+ import io
8
+ import base64
9
+ from PIL import Image
10
+ import re
11
+
12
+ # NIWA Snow Monitoring Stations
13
+ SNOW_STATIONS = {
14
+ "Mahanga EWS": {
15
+ "name": "Mahanga Electronic Weather Station",
16
+ "location": "Mount Mahanga, Tasman",
17
+ "elevation": "1940m",
18
+ "image_url": "https://webstatic.niwa.co.nz/snow-plots/mahanga-ews-snow-depth-web.png"
19
+ },
20
+ "Mueller Hut": {
21
+ "name": "Mueller Hut",
22
+ "location": "Aoraki/Mount Cook National Park",
23
+ "elevation": "1800m",
24
+ "image_url": "https://webstatic.niwa.co.nz/snow-plots/mueller-hut-snow-depth-web.png"
25
+ },
26
+ "Rose Ridge": {
27
+ "name": "Rose Ridge",
28
+ "location": "Canterbury",
29
+ "elevation": "1580m",
30
+ "image_url": "https://webstatic.niwa.co.nz/snow-plots/rose-ridge-snow-depth-web.png"
31
+ }
32
+ }
33
+
34
+ def fetch_snow_depth_image(station_key):
35
+ """Fetch snow depth chart image from NIWA servers"""
36
+ try:
37
+ station = SNOW_STATIONS[station_key]
38
+ image_url = station["image_url"]
39
+
40
+ headers = {
41
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
42
+ }
43
+
44
+ response = requests.get(image_url, headers=headers, timeout=10)
45
+
46
+ if response.status_code == 200:
47
+ # Convert to PIL Image
48
+ image = Image.open(io.BytesIO(response.content))
49
+
50
+ info = f"""
51
+ **Station:** {station['name']}
52
+ **Location:** {station['location']}
53
+ **Elevation:** {station['elevation']}
54
+ **Last Updated:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} (Image fetch time)
55
+
56
+ *Note: This chart shows current snow depth relative to historical records. Data is updated weekly.*
57
+ """
58
+
59
+ return image, info, "βœ… Successfully fetched snow depth data"
60
+
61
+ else:
62
+ return None, f"❌ Failed to fetch data. HTTP {response.status_code}", f"Error fetching from {image_url}"
63
+
64
+ except Exception as e:
65
+ return None, f"❌ Error: {str(e)}", "Failed to connect to NIWA servers"
66
+
67
+ def try_fetch_json_data():
68
+ """Attempt to find JSON endpoints for snow data"""
69
+ potential_endpoints = [
70
+ "https://data.niwa.co.nz/api/snow/depth",
71
+ "https://api.niwa.co.nz/snow/depth",
72
+ "https://webstatic.niwa.co.nz/api/snow-data.json",
73
+ "https://niwa.co.nz/api/snow/stations"
74
+ ]
75
+
76
+ results = []
77
+ headers = {'User-Agent': 'Mozilla/5.0 (compatible; SnowDataFetcher/1.0)'}
78
+
79
+ for endpoint in potential_endpoints:
80
+ try:
81
+ response = requests.get(endpoint, headers=headers, timeout=5)
82
+ if response.status_code == 200:
83
+ try:
84
+ data = response.json()
85
+ results.append(f"βœ… {endpoint}: Found JSON data")
86
+ except:
87
+ results.append(f"πŸ” {endpoint}: Response received but not JSON")
88
+ else:
89
+ results.append(f"❌ {endpoint}: HTTP {response.status_code}")
90
+ except:
91
+ results.append(f"❌ {endpoint}: Connection failed")
92
+
93
+ return "\n".join(results)
94
+
95
+ def get_all_stations_data():
96
+ """Fetch data for all available stations"""
97
+ results = []
98
+ images = []
99
+
100
+ for station_key in SNOW_STATIONS.keys():
101
+ try:
102
+ image, info, status = fetch_snow_depth_image(station_key)
103
+ if image:
104
+ images.append((image, f"{SNOW_STATIONS[station_key]['name']} Snow Depth"))
105
+ results.append(f"βœ… {station_key}: {status}")
106
+ else:
107
+ results.append(f"❌ {station_key}: {status}")
108
+ except Exception as e:
109
+ results.append(f"❌ {station_key}: Error - {str(e)}")
110
+
111
+ return images, "\n".join(results)
112
+
113
+ def search_additional_endpoints():
114
+ """Search for additional NIWA data endpoints"""
115
+ # Try to find other potential data sources
116
+ search_urls = [
117
+ "https://niwa.co.nz/freshwater/snow-and-ice-network/",
118
+ "https://data.niwa.co.nz/",
119
+ "https://developer.niwa.co.nz/"
120
+ ]
121
+
122
+ findings = []
123
+ headers = {'User-Agent': 'Mozilla/5.0'}
124
+
125
+ for url in search_urls:
126
+ try:
127
+ response = requests.get(url, headers=headers, timeout=10)
128
+ if response.status_code == 200:
129
+ # Look for API references or data URLs in the content
130
+ content = response.text.lower()
131
+ if 'api' in content:
132
+ findings.append(f"βœ… {url}: Contains API references")
133
+ if 'json' in content:
134
+ findings.append(f"πŸ” {url}: Contains JSON references")
135
+ if 'data' in content:
136
+ findings.append(f"πŸ“Š {url}: Contains data references")
137
+ else:
138
+ findings.append(f"❌ {url}: HTTP {response.status_code}")
139
+ except:
140
+ findings.append(f"❌ {url}: Connection failed")
141
+
142
+ return "\n".join(findings) if findings else "No additional endpoints found"
143
+
144
+ # Create Gradio Interface
145
+ with gr.Blocks(title="NIWA Snow Depth Monitor", theme=gr.themes.Soft()) as app:
146
+ gr.Markdown("""
147
+ # πŸ”οΈ NIWA Snow Depth Data Fetcher
148
+
149
+ This app fetches real-time snow depth data from New Zealand's National Institute of Water and Atmospheric Research (NIWA) public servers.
150
+
151
+ **Data Sources:**
152
+ - Snow depth charts from NIWA's Electronic Weather Stations
153
+ - Updated weekly with quality-controlled data
154
+ - Covers key South Island alpine monitoring sites
155
+ """)
156
+
157
+ with gr.Tab("πŸ“Š Individual Station Data"):
158
+ with gr.Row():
159
+ station_dropdown = gr.Dropdown(
160
+ choices=list(SNOW_STATIONS.keys()),
161
+ value="Mahanga EWS",
162
+ label="Select Snow Monitoring Station",
163
+ info="Choose a NIWA snow monitoring station"
164
+ )
165
+ fetch_btn = gr.Button("πŸ”„ Fetch Snow Data", variant="primary")
166
+
167
+ with gr.Row():
168
+ with gr.Column(scale=2):
169
+ snow_image = gr.Image(label="Snow Depth Chart", height=400)
170
+ with gr.Column(scale=1):
171
+ station_info = gr.Markdown(label="Station Information")
172
+
173
+ fetch_status = gr.Textbox(label="Status", interactive=False)
174
+
175
+ with gr.Tab("πŸ—ΊοΈ All Stations Overview"):
176
+ with gr.Row():
177
+ fetch_all_btn = gr.Button("πŸ“‘ Fetch All Station Data", variant="primary")
178
+
179
+ all_stations_gallery = gr.Gallery(
180
+ label="All Snow Monitoring Stations",
181
+ columns=2,
182
+ height=400
183
+ )
184
+ all_stations_status = gr.Textbox(label="Fetch Results", interactive=False)
185
+
186
+ with gr.Tab("πŸ” API Discovery"):
187
+ gr.Markdown("""
188
+ ### API Endpoint Discovery
189
+ This section attempts to find additional JSON/API endpoints for accessing raw snow data.
190
+ """)
191
+
192
+ with gr.Row():
193
+ search_json_btn = gr.Button("πŸ” Search for JSON APIs", variant="secondary")
194
+ search_endpoints_btn = gr.Button("🌐 Search Additional Endpoints", variant="secondary")
195
+
196
+ json_results = gr.Textbox(label="JSON API Search Results", lines=8, interactive=False)
197
+ endpoint_results = gr.Textbox(label="Additional Endpoint Search", lines=6, interactive=False)
198
+
199
+ with gr.Tab("ℹ️ About"):
200
+ gr.Markdown("""
201
+ ### About This App
202
+
203
+ **Data Source:** New Zealand's National Institute of Water and Atmospheric Research (NIWA)
204
+
205
+ **Monitoring Stations:**
206
+ - **Mahanga EWS**: Mount Mahanga, Tasman (1940m elevation)
207
+ - **Mueller Hut**: Aoraki/Mount Cook National Park (1800m elevation)
208
+ - **Rose Ridge**: Canterbury (1580m elevation)
209
+
210
+ **Data Notes:**
211
+ - Charts show current snow depth relative to historical records
212
+ - Data is updated weekly from raw measurements
213
+ - Single monitoring point may not represent entire surrounding area
214
+ - Inherent uncertainty in snow depth measurements
215
+
216
+ **Technical Details:**
217
+ - Fetches PNG chart images from NIWA's public web servers
218
+ - Attempts to discover JSON API endpoints for raw data access
219
+ - No authentication required for public data
220
+
221
+ **Use Cases:**
222
+ - Alpine weather monitoring
223
+ - Skiing and mountaineering planning
224
+ - Climate research and analysis
225
+ - Avalanche risk assessment support
226
+
227
+ **Limitations:**
228
+ - Visual charts only (numerical data requires NIWA DataHub registration)
229
+ - Weekly update frequency
230
+ - Limited to available monitoring stations
231
+
232
+ For raw numerical data access, visit: https://data.niwa.co.nz/
233
+ """)
234
+
235
+ # Event handlers
236
+ fetch_btn.click(
237
+ fn=fetch_snow_depth_image,
238
+ inputs=[station_dropdown],
239
+ outputs=[snow_image, station_info, fetch_status]
240
+ )
241
+
242
+ fetch_all_btn.click(
243
+ fn=get_all_stations_data,
244
+ outputs=[all_stations_gallery, all_stations_status]
245
+ )
246
+
247
+ search_json_btn.click(
248
+ fn=try_fetch_json_data,
249
+ outputs=[json_results]
250
+ )
251
+
252
+ search_endpoints_btn.click(
253
+ fn=search_additional_endpoints,
254
+ outputs=[endpoint_results]
255
+ )
256
+
257
+ # Launch instructions for HuggingFace Spaces
258
+ if __name__ == "__main__":
259
+ app.launch()
260
+
261
+ # Requirements for HuggingFace Spaces (requirements.txt):
262
+ """
263
+ gradio>=4.0.0
264
+ requests>=2.25.0
265
+ pandas>=1.3.0
266
+ matplotlib>=3.5.0
267
+ Pillow>=8.0.0
268
+ """
269
+
270
+ # App file structure for HuggingFace Spaces:
271
+ """
272
+ app.py (this file)
273
+ requirements.txt (with the above dependencies)
274
+ README.md (with app description)
275
+ """