nakas commited on
Commit
fe49e63
·
verified ·
1 Parent(s): dc2c705

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +89 -135
app.py CHANGED
@@ -45,132 +45,84 @@ def get_snow_forecast(lat, lon):
45
  return f"Error getting forecast: {str(e)}"
46
 
47
  def get_forecast_images():
48
- """Get forecast images and combine them into an animation."""
49
  try:
50
- frames = []
51
  current_time = datetime.utcnow()
52
 
53
- # List of forecast product URLs
54
- forecast_urls = [
55
- # National Forecast Products
56
- f"https://graphical.weather.gov/images/conus/MaxT1_conus.png",
57
- f"https://graphical.weather.gov/images/conus/MinT1_conus.png",
58
- f"https://graphical.weather.gov/images/conus/Wx1_conus.png",
59
-
60
- # Winter Weather Probability
61
- "https://www.wpc.ncep.noaa.gov/pwpf/24hr_pwpf_fill.gif",
62
- "https://www.wpc.ncep.noaa.gov/pwpf/48hr_pwpf_fill.gif",
63
- "https://www.wpc.ncep.noaa.gov/pwpf/72hr_pwpf_fill.gif",
64
-
65
- # Winter Weather Maps
66
- "https://www.wpc.ncep.noaa.gov/wwd/24wp_d1_psnow.gif",
67
- "https://www.wpc.ncep.noaa.gov/wwd/48wp_d2_psnow.gif",
68
- "https://www.wpc.ncep.noaa.gov/wwd/72wp_d3_psnow.gif",
69
-
70
- # Precipitation Probability
71
- f"https://graphical.weather.gov/images/conus/PoP1_conus.png",
72
- f"https://graphical.weather.gov/images/conus/PoP2_conus.png",
73
-
74
- # Snow Amount Forecasts
75
- f"https://graphical.weather.gov/images/conus/Snow1_conus.png",
76
- f"https://graphical.weather.gov/images/conus/Snow2_conus.png"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  ]
78
 
79
- # Try to get each forecast image
80
- for i, url in enumerate(forecast_urls):
81
  try:
82
- response = requests.get(url, timeout=10)
83
  if response.status_code == 200:
84
- img = Image.open(io.BytesIO(response.content))
85
-
86
- # Convert to RGB if needed
87
- if img.mode != 'RGB':
88
- img = img.convert('RGB')
89
-
90
- # Resize to consistent dimensions
91
- img = img.resize((800, 600), Image.Resampling.LANCZOS)
92
-
93
- # Add descriptive text
94
- draw = ImageDraw.Draw(img)
95
- try:
96
- font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
97
- except:
98
- font = ImageFont.load_default()
99
-
100
- # Determine image type
101
- if "MaxT" in url:
102
- text = "Maximum Temperature Forecast"
103
- elif "MinT" in url:
104
- text = "Minimum Temperature Forecast"
105
- elif "Wx" in url:
106
- text = "Weather Type Forecast"
107
- elif "pwpf" in url:
108
- hours = url.split('/')[-1].split('hr')[0]
109
- text = f"{hours}-hour Winter Precipitation Forecast"
110
- elif "psnow" in url:
111
- if "24wp" in url:
112
- text = "24-hour Snowfall Probability"
113
- elif "48wp" in url:
114
- text = "48-hour Snowfall Probability"
115
- else:
116
- text = "72-hour Snowfall Probability"
117
- elif "PoP" in url:
118
- text = "Precipitation Probability Forecast"
119
- elif "Snow" in url:
120
- text = "Snowfall Amount Forecast"
121
- else:
122
- text = f"Weather Forecast Product {i+1}"
123
-
124
- timestamp = f"Valid: {current_time.strftime('%Y-%m-%d %H:%M UTC')}"
125
-
126
- # Draw text with outline for visibility
127
- x, y = 10, 10
128
- for dx, dy in [(-1,-1), (-1,1), (1,-1), (1,1)]:
129
- draw.text((x+dx, y+dy), text, fill='black', font=font)
130
- draw.text((x+dx, y+dy+25), timestamp, fill='black', font=font)
131
- draw.text((x, y), text, fill='white', font=font)
132
- draw.text((x, y+25), timestamp, fill='white', font=font)
133
-
134
- frames.append(img)
135
- print(f"Successfully added frame from {url}")
136
  except Exception as e:
137
- print(f"Error processing forecast image from {url}: {str(e)}")
138
  continue
139
-
140
- if not frames:
141
- raise Exception("No forecast images could be loaded")
142
-
143
- # Create animated GIF
144
- with tempfile.NamedTemporaryFile(suffix='.gif', delete=False) as tmp_file:
145
- frames[0].save(
146
- tmp_file.name,
147
- save_all=True,
148
- append_images=frames[1:],
149
- duration=3000, # 3 seconds per frame
150
- loop=0
151
- )
152
- return tmp_file.name
153
 
154
- except Exception as e:
155
- print(f"Error creating forecast display: {str(e)}")
156
- # Create error message image
157
- img = Image.new('RGB', (800, 600), color='black')
158
- draw = ImageDraw.Draw(img)
159
- message = (
160
- "Weather forecast images temporarily unavailable\n"
161
- f"{str(e)}\n"
162
- "Please check weather.gov for current conditions\n"
163
- f"Last attempt: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
164
- )
165
- try:
166
- font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 20)
167
- draw.text((400, 300), message, fill='white', anchor="mm", align="center", font=font)
168
- except:
169
- draw.text((400, 300), message, fill='white', anchor="mm", align="center")
170
 
171
- with tempfile.NamedTemporaryFile(suffix='.gif', delete=False) as tmp_file:
172
- img.save(tmp_file.name, format='GIF')
173
- return tmp_file.name
174
 
175
  def get_map(lat, lon):
176
  """Create a map centered on the given coordinates with markers."""
@@ -205,21 +157,21 @@ def update_weather(lat, lon):
205
  lat = float(lat)
206
  lon = float(lon)
207
  if not (-90 <= lat <= 90 and -180 <= lon <= 180):
208
- return "Invalid coordinates", None, get_map(45.5, -111.0)
209
 
210
  # Get text forecast
211
  forecast_text = get_snow_forecast(lat, lon)
212
 
213
- # Get forecast images animation
214
- forecast_animation = get_forecast_images()
215
 
216
  # Get map
217
  map_html = get_map(lat, lon)
218
 
219
- return forecast_text, forecast_animation, map_html
220
 
221
  except Exception as e:
222
- return f"Error: {str(e)}", None, get_map(45.5, -111.0)
223
 
224
  # Create Gradio interface
225
  with gr.Blocks(title="Montana Mountain Weather") as demo:
@@ -252,17 +204,20 @@ with gr.Blocks(title="Montana Mountain Weather") as demo:
252
  map_display = gr.HTML(get_map(45.5, -111.0))
253
 
254
  with gr.Row():
255
- with gr.Column():
256
  forecast_output = gr.Textbox(
257
- label="Forecast",
258
  lines=12,
259
  placeholder="Select a location to see the forecast..."
260
  )
261
- forecast_gallery = gr.Gallery(
 
262
  label="Weather Forecast Products",
263
  show_label=True,
264
  columns=2,
265
- height=400
 
 
266
  )
267
 
268
  # Handle submit button click
@@ -271,7 +226,7 @@ with gr.Blocks(title="Montana Mountain Weather") as demo:
271
  inputs=[lat_input, lon_input],
272
  outputs=[
273
  forecast_output,
274
- forecast_gallery,
275
  map_display
276
  ]
277
  )
@@ -287,7 +242,7 @@ with gr.Blocks(title="Montana Mountain Weather") as demo:
287
  inputs=[lat_input, lon_input],
288
  outputs=[
289
  forecast_output,
290
- forecast_gallery,
291
  map_display
292
  ]
293
  )
@@ -303,17 +258,16 @@ with gr.Blocks(title="Montana Mountain Weather") as demo:
303
  - Sacajawea Peak: 45°53′45″N 110°58′7″W
304
  - Pioneer Mountain: 45°13′55″N 111°27′2″W
305
 
306
- **Forecast Products Include:**
307
- - Temperature forecasts (max/min)
308
- - Precipitation probability
309
- - Snow amount predictions
310
- - Winter weather probability
311
- - 24/48/72-hour snowfall forecasts
312
-
313
- Each forecast image will be shown for 3 seconds in the animation.
314
 
315
  **Note**: This app uses the NOAA Weather API and may have occasional delays or service interruptions.
316
  Mountain weather can change rapidly - always check multiple sources for safety.
317
  """)
318
 
319
- demo.queue().launch()
 
45
  return f"Error getting forecast: {str(e)}"
46
 
47
  def get_forecast_images():
48
+ """Get forecast images."""
49
  try:
50
+ gallery_images = []
51
  current_time = datetime.utcnow()
52
 
53
+ # List of forecast product URLs with descriptions
54
+ forecast_products = [
55
+ {
56
+ "url": "https://graphical.weather.gov/images/conus/MaxT1_conus.png",
57
+ "title": "Maximum Temperature Forecast"
58
+ },
59
+ {
60
+ "url": "https://graphical.weather.gov/images/conus/MinT1_conus.png",
61
+ "title": "Minimum Temperature Forecast"
62
+ },
63
+ {
64
+ "url": "https://graphical.weather.gov/images/conus/Wx1_conus.png",
65
+ "title": "Weather Type Forecast"
66
+ },
67
+ {
68
+ "url": "https://graphical.weather.gov/images/conus/PoP1_conus.png",
69
+ "title": "Precipitation Probability (Day 1)"
70
+ },
71
+ {
72
+ "url": "https://graphical.weather.gov/images/conus/PoP2_conus.png",
73
+ "title": "Precipitation Probability (Day 2)"
74
+ },
75
+ {
76
+ "url": "https://graphical.weather.gov/images/conus/Snow1_conus.png",
77
+ "title": "Snowfall Amount (Day 1)"
78
+ },
79
+ {
80
+ "url": "https://graphical.weather.gov/images/conus/Snow2_conus.png",
81
+ "title": "Snowfall Amount (Day 2)"
82
+ },
83
+ {
84
+ "url": "https://www.wpc.ncep.noaa.gov/pwpf/24hr_pwpf_fill.gif",
85
+ "title": "24-hour Winter Precipitation Probability"
86
+ },
87
+ {
88
+ "url": "https://www.wpc.ncep.noaa.gov/pwpf/48hr_pwpf_fill.gif",
89
+ "title": "48-hour Winter Precipitation Probability"
90
+ },
91
+ {
92
+ "url": "https://www.wpc.ncep.noaa.gov/pwpf/72hr_pwpf_fill.gif",
93
+ "title": "72-hour Winter Precipitation Probability"
94
+ },
95
+ {
96
+ "url": "https://www.wpc.ncep.noaa.gov/wwd/24wp_d1_psnow.gif",
97
+ "title": "24-hour Snowfall Probability"
98
+ },
99
+ {
100
+ "url": "https://www.wpc.ncep.noaa.gov/wwd/48wp_d2_psnow.gif",
101
+ "title": "48-hour Snowfall Probability"
102
+ },
103
+ {
104
+ "url": "https://www.wpc.ncep.noaa.gov/wwd/72wp_d3_psnow.gif",
105
+ "title": "72-hour Snowfall Probability"
106
+ }
107
  ]
108
 
109
+ for product in forecast_products:
 
110
  try:
111
+ response = requests.get(product["url"], timeout=10)
112
  if response.status_code == 200:
113
+ img_data = response.content
114
+ caption = f"{product['title']} (Valid: {current_time.strftime('%Y-%m-%d %H:%M UTC')})"
115
+ gallery_images.append((img_data, caption))
116
+ print(f"Successfully added {product['title']}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  except Exception as e:
118
+ print(f"Error processing {product['title']}: {str(e)}")
119
  continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
+ return gallery_images
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
+ except Exception as e:
124
+ print(f"Error getting forecast images: {str(e)}")
125
+ return []
126
 
127
  def get_map(lat, lon):
128
  """Create a map centered on the given coordinates with markers."""
 
157
  lat = float(lat)
158
  lon = float(lon)
159
  if not (-90 <= lat <= 90 and -180 <= lon <= 180):
160
+ return "Invalid coordinates", [], get_map(45.5, -111.0)
161
 
162
  # Get text forecast
163
  forecast_text = get_snow_forecast(lat, lon)
164
 
165
+ # Get forecast images
166
+ gallery_images = get_forecast_images()
167
 
168
  # Get map
169
  map_html = get_map(lat, lon)
170
 
171
+ return forecast_text, gallery_images, map_html
172
 
173
  except Exception as e:
174
+ return f"Error: {str(e)}", [], get_map(45.5, -111.0)
175
 
176
  # Create Gradio interface
177
  with gr.Blocks(title="Montana Mountain Weather") as demo:
 
204
  map_display = gr.HTML(get_map(45.5, -111.0))
205
 
206
  with gr.Row():
207
+ with gr.Column(scale=1):
208
  forecast_output = gr.Textbox(
209
+ label="Weather Forecast",
210
  lines=12,
211
  placeholder="Select a location to see the forecast..."
212
  )
213
+ with gr.Column(scale=2):
214
+ forecast_images = gr.Gallery(
215
  label="Weather Forecast Products",
216
  show_label=True,
217
  columns=2,
218
+ rows=2,
219
+ height="auto",
220
+ object_fit="contain"
221
  )
222
 
223
  # Handle submit button click
 
226
  inputs=[lat_input, lon_input],
227
  outputs=[
228
  forecast_output,
229
+ forecast_images,
230
  map_display
231
  ]
232
  )
 
242
  inputs=[lat_input, lon_input],
243
  outputs=[
244
  forecast_output,
245
+ forecast_images,
246
  map_display
247
  ]
248
  )
 
258
  - Sacajawea Peak: 45°53′45″N 110°58′7″W
259
  - Pioneer Mountain: 45°13′55″N 111°27′2″W
260
 
261
+ **Available Forecast Products:**
262
+ - Temperature Forecasts (Max/Min)
263
+ - Weather Type Forecast
264
+ - Precipitation Probability (Days 1-2)
265
+ - Snowfall Amount Forecasts (Days 1-2)
266
+ - Winter Precipitation Probability (24/48/72-hour)
267
+ - Snowfall Probability (24/48/72-hour)
 
268
 
269
  **Note**: This app uses the NOAA Weather API and may have occasional delays or service interruptions.
270
  Mountain weather can change rapidly - always check multiple sources for safety.
271
  """)
272
 
273
+ demo.queue().launch()