Adedoyinjames commited on
Commit
ce23ae7
·
verified ·
1 Parent(s): 4245e09

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -242
app.py CHANGED
@@ -1,259 +1,136 @@
 
1
  import os
2
  import requests
3
- import pandas as pd
4
- import plotly.express as px
5
- from geopy.geocoders import Nominatim
6
  import gradio as gr
7
- import feedparser
 
 
8
 
9
- API_URL = "https://router.huggingface.co/v1/chat/completions"
10
- headers = {
11
- "Authorization": f"Bearer {os.environ.get('HF_TOKEN')}",
12
- }
13
 
14
- def query(payload):
15
- response = requests.post(API_URL, headers=headers, json=payload)
16
- return response.json()
17
-
18
- def fetch_data(api_name):
19
- url = f"https://global-warming.org/api/{api_name}-api"
20
- try:
21
- resp = requests.get(url).json()
22
- if 'result' in resp:
23
- return pd.DataFrame(resp['result'])
24
- elif api_name == 'co2':
25
- return pd.DataFrame(resp['co2'])
26
- elif api_name == 'methane':
27
- return pd.DataFrame(resp['methane'])
28
- elif api_name == 'nitrous-oxide':
29
- return pd.DataFrame(resp['nitrous'])
30
- elif api_name == 'arctic':
31
- return pd.DataFrame(resp['arctic'])
32
- elif api_name == 'ocean-warming':
33
- return pd.DataFrame(resp['ocean_heat'])
34
- else:
35
- return pd.DataFrame()
36
- except Exception as e:
37
- return pd.DataFrame()
38
-
39
- def clean_df(df, x_col, y_cols):
40
- for col in [x_col] + y_cols:
41
- if col in df.columns:
42
- df[col] = pd.to_numeric(df[col], errors='coerce')
43
- return df.dropna(subset=y_cols)
44
-
45
- def get_temp_fig():
46
- df = fetch_data('temperature')
47
- df = clean_df(df, 'time', ['station', 'land'])
48
- fig = px.line(df, x='time', y=['station', 'land'], title='Global Temperature Anomaly (°C)')
49
- return fig
50
-
51
- def get_co2_fig():
52
- df = fetch_data('co2')
53
- df['date'] = pd.to_datetime(df[['year', 'month', 'day']].astype(str).agg('-'.join, axis=1), format='%Y-%m-%d')
54
- df = clean_df(df, 'date', ['trend'])
55
- fig = px.line(df, x='date', y='trend', title='Atmospheric CO₂ Levels (ppm)')
56
- return fig
57
-
58
- def get_methane_fig():
59
- df = fetch_data('methane')
60
- if 'date' in df.columns:
61
- df['date'] = pd.to_numeric(df['date'], errors='coerce')
62
- elif 'year' in df.columns and 'month' in df.columns:
63
- df['date'] = pd.to_datetime(df[['year', 'month']].astype(str).agg('-'.join, axis=1) + '-01')
64
- else:
65
- return px.line(title='Data unavailable')
66
- df = clean_df(df, 'date', ['average'])
67
- fig = px.line(df, x='date', y='average', title='Atmospheric Methane Levels (ppb)')
68
- return fig
69
-
70
- def get_nitrous_fig():
71
- df = fetch_data('nitrous-oxide')
72
- if 'date' not in df.columns:
73
- return px.line(title='Data unavailable or unexpected format')
74
- df['date'] = pd.to_numeric(df['date'], errors='coerce') # Decimal year, e.g., 2024.5
75
- df = clean_df(df, 'date', ['average'])
76
- fig = px.line(df, x='date', y='average', title='Atmospheric Nitrous Oxide Levels (ppb)')
77
- return fig
78
-
79
- def get_arctic_fig():
80
- df = fetch_data('arctic')
81
- df['date'] = pd.to_datetime(df[['year', 'month']].astype(str).agg('-'.join, axis=1) + '-01')
82
- df = clean_df(df, 'date', ['extent'])
83
- fig = px.line(df, x='date', y='extent', title='Arctic Sea Ice Extent (million km²)')
84
- return fig
85
-
86
- def get_ocean_fig():
87
- df = fetch_data('ocean-warming')
88
- df = clean_df(df, 'Year', ['Result'])
89
- fig = px.line(df, x='Year', y='Result', title='Ocean Heat Content Anomaly (10^22 Joules)')
90
- return fig
91
-
92
- def get_sea_level_fig():
93
- url = "https://sealevel.colorado.edu/files/current/sl_ns_global.txt"
94
  try:
95
- resp = requests.get(url)
96
- lines = [line for line in resp.text.splitlines() if not line.startswith('#') and line.strip()]
97
- data = [line.split() for line in lines]
98
- df = pd.DataFrame(data, columns=['year_fraction', 'altimeter_type', 'merged_file_cycle', 'year_decimal', 'num_observations', 'num_weighted_observations', 'GMSL_no_GIA', 'std_dev_no_GIA', 'smoothed_no_GIA', 'GMSL_GIA', 'std_dev_GIA', 'smoothed_GIA'])
99
- df['year'] = pd.to_numeric(df['year_fraction'])
100
- df['GMSL'] = pd.to_numeric(df['GMSL_GIA'])
101
- df = df.dropna(subset=['GMSL'])
102
- fig = px.line(df, x='year', y='GMSL', title='Global Mean Sea Level Rise (mm)')
103
- return fig
104
- except Exception as e:
105
- return px.line(title=f'Error fetching data: {str(e)}')
106
 
107
- def get_temp_zonal_fig():
108
- url = "https://data.giss.nasa.gov/gistemp/tabledata_v4/Zonal.Ts+dSST.txt"
109
  try:
110
- df = pd.read_table(url, skiprows=7, sep='\s+', index_col='Year', na_values=['****'])
111
- latest_year = df.index[-1]
112
- latest = df.loc[latest_year].dropna()
113
- zones = latest.index
114
- anomalies = latest.values
115
- zonal_df = pd.DataFrame({'zone': zones, 'anomaly': anomalies})
116
- fig = px.bar(zonal_df, x='zone', y='anomaly', title=f'Zonal Temperature Anomalies (°C) for {latest_year}')
117
- fig.update_layout(xaxis_title='Latitude Zone', yaxis_title='Anomaly (°C)')
118
- return fig
119
- except Exception as e:
120
- return px.bar(title=f'Error fetching data: {str(e)}')
121
 
122
- def get_local_climate(city):
123
- if not city:
124
- return None, None, "Please enter a city name."
125
-
126
- geolocator = Nominatim(user_agent="climate_dashboard")
127
  try:
128
- location = geolocator.geocode(city)
129
- if not location:
130
- return None, None, "City not found."
131
-
132
- lat, lon = location.latitude, location.longitude
133
- url = f"https://climate-api.open-meteo.com/v1/climate?latitude={lat}&longitude={lon}&start_date=1950-01-01&end_date=2050-12-31&models=CMCC_CM2_VHR4&daily=temperature_2m_mean"
134
- resp = requests.get(url).json()
135
-
136
- if 'daily' not in resp:
137
- return None, None, "No data available."
138
-
139
- times = resp['daily']['time']
140
- temps = resp['daily']['temperature_2m_mean']
141
- df = pd.DataFrame({'date': times, 'temperature_mean': temps})
142
- df['date'] = pd.to_datetime(df['date'])
143
- fig = px.line(df, x='date', y='temperature_mean', title=f'Projected Mean Temperature for {city} (°C)')
144
-
145
- # Simple heatwave estimation: days with mean temp > 25°C (adjust threshold as needed)
146
- df['year'] = df['date'].dt.year
147
- heatwave_days = df[df['temperature_mean'] > 25].groupby('year').size().reset_index(name='heatwave_days')
148
- heat_fig = px.line(heatwave_days, x='year', y='heatwave_days', title=f'Projected Heatwave Days per Year for {city}')
149
-
150
- return fig, heat_fig, ""
151
- except Exception as e:
152
- return None, None, f"Error: {str(e)}"
153
 
154
- def get_news():
155
- feed_url = "https://feeds.bbci.co.uk/news/science_and_environment/rss.xml"
156
- feed = feedparser.parse(feed_url)
157
- if not feed.entries:
158
- return "No news available."
159
- news_list = [f"- [{entry.title}]({entry.link})" for entry in feed.entries[:10]]
160
- return "## Recent Climate News\n" + "\n".join(news_list)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
 
162
- def chat_response(message, history):
163
- messages = [
164
- {"role": "system", "content": "You are a helpful climate change expert. Use data and facts to explain concepts, impacts, and solutions. Be engaging and educational."}
165
- ]
166
- for user_msg, assistant_msg in history:
167
- messages.append({"role": "user", "content": user_msg})
168
- messages.append({"role": "assistant", "content": assistant_msg})
169
- messages.append({"role": "user", "content": message})
170
-
171
  payload = {
172
- "messages": messages,
173
- "model": "deepseek-ai/DeepSeek-V3.2:novita",
174
- "max_tokens": 512,
175
  "temperature": 0.7,
 
176
  }
 
177
  try:
178
- resp = query(payload)
179
- return resp["choices"][0]["message"]["content"]
 
 
 
 
 
 
 
 
 
 
 
 
 
180
  except Exception as e:
181
- return f"Error: {str(e)}"
182
-
183
- css = """
184
- .gradio-container {
185
- background: ur[](https://www.nasa.gov/wp-content/uploads/2023/03/earth-from-space.jpg) no-repeat center center fixed !important;
186
- background-size: cover !important;
187
- }
188
- """
189
-
190
- with gr.Blocks() as demo: # css moved to launch()
191
- gr.Markdown("# Interactive Climate Dashboard")
192
- gr.Markdown("Explore global climate indicators, personalized local projections, and chat with an AI expert.")
193
-
194
- with gr.Tab("Live Key Indicators"):
195
- with gr.Row():
196
- with gr.Column():
197
- temp_plot = gr.Plot(value=get_temp_fig())
198
- with gr.Column():
199
- co2_plot = gr.Plot(value=get_co2_fig())
200
- with gr.Column():
201
- methane_plot = gr.Plot(value=get_methane_fig())
202
- with gr.Row():
203
- with gr.Column():
204
- nitrous_plot = gr.Plot(value=get_nitrous_fig())
205
- with gr.Column():
206
- arctic_plot = gr.Plot(value=get_arctic_fig())
207
- with gr.Column():
208
- ocean_plot = gr.Plot(value=get_ocean_fig())
209
- with gr.Row():
210
- with gr.Column():
211
- sea_level_plot = gr.Plot(value=get_sea_level_fig())
212
- refresh_btn = gr.Button("Refresh Data")
213
- refresh_btn.click(fn=lambda: (get_temp_fig(), get_co2_fig(), get_methane_fig(), get_nitrous_fig(), get_arctic_fig(), get_ocean_fig(), get_sea_level_fig()),
214
- outputs=[temp_plot, co2_plot, methane_plot, nitrous_plot, arctic_plot, ocean_plot, sea_level_plot])
215
-
216
- with gr.Tab("Interactive Maps & Graphs"):
217
- gr.Markdown("Global temperature anomaly by latitude zones (inspired by Berkeley Earth and NASA GISS)")
218
- zonal_plot = gr.Plot(value=get_temp_zonal_fig())
219
- refresh_map_btn = gr.Button("Refresh Map Data")
220
- refresh_map_btn.click(fn=get_temp_zonal_fig, outputs=zonal_plot)
221
-
222
- with gr.Tab("Location-Based Personalization"):
223
- city_input = gr.Textbox(label="Enter your city (e.g., New York, USA)")
224
- submit_btn = gr.Button("Get Local Projections")
225
- temp_output = gr.Plot()
226
- heat_output = gr.Plot()
227
- message = gr.Markdown()
228
- submit_btn.click(get_local_climate, inputs=city_input, outputs=[temp_output, heat_output, message])
229
- gr.Markdown("Note: Projections based on CMCC_CM2_VHR4 model. Heatwave days defined as mean temp > 25°C.")
230
-
231
- with gr.Tab("AI Chat Assistant"):
232
- gr.ChatInterface(chat_response)
233
-
234
- with gr.Tab("Climate News"):
235
- news_md = gr.Markdown(value=get_news())
236
- news_refresh = gr.Button("Refresh News")
237
- news_refresh.click(get_news, outputs=news_md)
238
-
239
- with gr.Tab("What Can I Do?"):
240
- gr.Markdown("""
241
- ### Individual Actions
242
- - Reduce energy use: Switch to LED bulbs, unplug devices.
243
- - Sustainable transport: Walk, bike, or use public transit.
244
- - Eat sustainably: Reduce meat consumption, avoid food waste.
245
- - Support renewables: Choose green energy providers.
246
-
247
- ### Community Actions
248
- - Advocate for policies: Support climate-friendly laws.
249
- - Plant trees: Join local reforestation efforts.
250
- - Educate others: Share knowledge and facts.
251
-
252
- Share this dashboard on social media!
253
- """)
254
- gr.HTML("""
255
- <a href="https://twitter.com/intent/tweet?text=Check%20out%20this%20interactive%20climate%20dashboard!&url=https://example.com" target="_blank" style="margin-right:10px;">Share on X</a>
256
- <a href="https://www.facebook.com/sharer/sharer.php?u=https://example.com" target="_blank">Share on Facebook</a>
257
- """) # Replace https://example.com with actual URL if known
258
-
259
- demo.launch(share=True, css=css, theme=gr.themes.Soft())
 
1
+ # app.py
2
  import os
3
  import requests
 
 
 
4
  import gradio as gr
5
+ import folium
6
+ import leafmap.foliumap as leafmap
7
+ from datetime import datetime
8
 
9
+ # Global climate APIs (all data is global, not per-location)
10
+ TEMP_API = "https://global-warming.org/api/temperature-api"
11
+ CO2_API = "https://global-warming.org/api/co2-api"
12
+ OCEAN_API = "https://global-warming.org/api/ocean-warming-api"
13
 
14
+ # Fetch and cache data
15
+ def fetch_data():
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  try:
17
+ temp = requests.get(TEMP_API).json()["result"][-12:] # Last 12 months for recent view
18
+ latest_temp = temp[-1]
19
+ temp_info = f"Latest Global Temperature Anomaly: {latest_temp['station']} °C (Land+Ocean, {latest_temp['time']})"
20
+ except:
21
+ temp_info = "Temperature data unavailable"
 
 
 
 
 
 
22
 
 
 
23
  try:
24
+ co2 = requests.get(CO2_API).json()["co2"][-1]
25
+ co2_info = f"Latest CO₂: {co2['trend']} ppm (Trend, {co2['year']}-{co2['month']}-{co2['day']})"
26
+ except:
27
+ co2_info = "CO₂ data unavailable"
 
 
 
 
 
 
 
28
 
 
 
 
 
 
29
  try:
30
+ ocean_data = requests.get(OCEAN_API).json()["result"]
31
+ latest_year = max(ocean_data.keys())
32
+ ocean_anomaly = ocean_data[latest_year]["anomaly"]
33
+ ocean_info = f"Ocean Warming Anomaly (Latest {latest_year}): {ocean_anomaly} (relative to baseline)"
34
+ except:
35
+ ocean_info = "Ocean data unavailable"
36
+
37
+ summary = f"## Live Global Climate Indicators\n\n{temp_info}\n\n{co2_info}\n\n{ocean_info}"
38
+ return summary
39
+
40
+ # Create a beautiful animated world map with climate theme (using Folium + plugins for animation effect)
41
+ def create_map():
42
+ # Center on world view
43
+ m = leafmap.Map(location=[20, 0], zoom_start=2, tiles="Stamen Terrain")
44
+
45
+ # Add a heat-like color overlay for visual "warming" effect (static but beautiful)
46
+ # Simple markers for key locations with climate popups
47
+ locations = [
48
+ ("Mauna Loa, Hawaii (CO₂ Observatory)", 19.536, -155.576, "Primary CO₂ measurement site"),
49
+ ("Arctic (Rapid Warming Region)", 80, -40, "Fastest warming region on Earth"),
50
+ ("Antarctica", -90, 0, "Ice sheet monitoring"),
51
+ ("Amazon Rainforest", -3, -60, "Carbon sink & deforestation impact"),
52
+ ("Great Barrier Reef", -18.28, 147.7, "Coral bleaching due to ocean warming"),
53
+ ]
 
54
 
55
+ for name, lat, lon, desc in locations:
56
+ folium.Marker(
57
+ [lat, lon],
58
+ popup=f"<b>{name}</b><br>{desc}",
59
+ icon=folium.Icon(color="red", icon="fire", prefix="fa")
60
+ ).add_to(m)
61
+
62
+ # Add a time-based "pulse" animation effect using Circle markers
63
+ for lat, lon in [(lat, lon) for _, lat, lon, _ in locations]:
64
+ folium.Circle(
65
+ location=[lat, lon],
66
+ radius=500000,
67
+ color="crimson",
68
+ fill=True,
69
+ fill_color="red",
70
+ fill_opacity=0.2,
71
+ weight=2
72
+ ).add_to(m)
73
+
74
+ # Make it interactive and beautiful
75
+ m.add_child(folium.LatLngPopup())
76
+ return m.to_gradio(height=600)
77
+
78
+ # DeepSeek chatbot function (using Hugging Face Inference API)
79
+ def deepseek_chat(message, history):
80
+ hf_token = os.getenv("HF_TOKEN")
81
+ if not hf_token:
82
+ yield "Error: Please set your Hugging Face token as the environment variable HF_TOKEN in your Space secrets."
83
+ return
84
 
 
 
 
 
 
 
 
 
 
85
  payload = {
86
+ "model": "deepseek-ai/DeepSeek-V3",
87
+ "messages": history + [{"role": "user", "content": message}],
88
+ "max_tokens": 1024,
89
  "temperature": 0.7,
90
+ "stream": True
91
  }
92
+
93
  try:
94
+ with requests.post(
95
+ "https://api.huggingface.co/v1/chat/completions",
96
+ headers={"Authorization": f"Bearer {hf_token}"},
97
+ json=payload,
98
+ stream=True
99
+ ) as response:
100
+ response.raise_for_status()
101
+ buffer = ""
102
+ for chunk in response.iter_lines():
103
+ if chunk:
104
+ data = requests.utils.json.loads(chunk.decode("utf-8"))
105
+ if "choices" in data and data["choices"]:
106
+ content = data["choices"][0]["delta"].get("content", "")
107
+ buffer += content
108
+ yield buffer
109
  except Exception as e:
110
+ yield f"Error: {str(e)}"
111
+
112
+ # Build the Gradio interface
113
+ with gr.Blocks(title="Global Climate Change Monitor", theme=gr.themes.Soft()) as demo:
114
+ gr.Markdown("# 🌍 Global Climate Change Monitor")
115
+ gr.Markdown("Real-time global climate indicators + interactive world map + AI chatbot powered by DeepSeek")
116
+
117
+ with gr.Row():
118
+ with gr.Column(scale=2):
119
+ map_output = gr.HTML()
120
+ demo.load(create_map, outputs=map_output)
121
+
122
+ gr.Markdown("### Live Global Data (refreshes on load)")
123
+ data_text = gr.Markdown()
124
+ demo.load(fetch_data, outputs=data_text)
125
+
126
+ with gr.Column(scale=1):
127
+ gr.Markdown("### Ask about Climate Change")
128
+ gr.Markdown("Chat with DeepSeek AI model (requires HF_TOKEN in Space secrets)")
129
+ chat = gr.ChatInterface(
130
+ fn=deepseek_chat,
131
+ chatbot=gr.Chatbot(height=500),
132
+ textbox=gr.Textbox(placeholder="e.g., What are the effects of rising CO₂?", label="Your question"),
133
+ title=None
134
+ )
135
+
136
+ demo.launch()