Naz786 commited on
Commit
dba0f1d
·
verified ·
1 Parent(s): 2d319b1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +385 -0
app.py ADDED
@@ -0,0 +1,385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from groq import Groq
3
+ import requests
4
+ import pandas as pd
5
+ from datetime import datetime, timedelta
6
+ import pycountry
7
+ from fpdf import FPDF
8
+ import io
9
+ import base64
10
+ from geopy.geocoders import Nominatim
11
+ from geopy.exc import GeocoderTimedOut
12
+ import plotly.express as px
13
+ import plotly.graph_objects as go
14
+ import unicodedata
15
+ from config import GROQ_API_KEY, AIRVISUAL_API_KEY, DEFAULT_MODEL
16
+ import os
17
+ from dotenv import load_dotenv
18
+
19
+ from utils.weather_utils import get_weather, get_historical_weather, get_air_quality
20
+ from utils.pdf_utils import generate_pdf
21
+ from utils.constants import SYSTEM_PROMPTS, EXAMPLE_QUERIES, CSS_STYLE
22
+
23
+ # Load environment variables
24
+ load_dotenv()
25
+
26
+ # Get API keys from environment variables
27
+ GROQ_API_KEY = os.getenv("GROQ_API_KEY")
28
+ AIRVISUAL_API_KEY = os.getenv("AIRVISUAL_API_KEY")
29
+ DEFAULT_MODEL = "llama3-70b-8192"
30
+
31
+ # === INIT Groq CLIENT ===
32
+ client = Groq(api_key=GROQ_API_KEY)
33
+
34
+ # === PAGE CONFIG ===
35
+ st.set_page_config(
36
+ page_title="🌱 AI Climate & Smart Farming Assistant",
37
+ page_icon="🌾",
38
+ layout="wide",
39
+ initial_sidebar_state="expanded"
40
+ )
41
+
42
+ # === CSS STYLING ===
43
+ st.markdown(CSS_STYLE, unsafe_allow_html=True)
44
+
45
+ # === HEADER ===
46
+ st.markdown("<h1 class='title'>🌾 AI Climate & Smart Farming Assistant</h1>", unsafe_allow_html=True)
47
+ st.markdown("<p class='subtitle'>Real-time AI insights + live weather data</p>", unsafe_allow_html=True)
48
+ st.markdown("---")
49
+
50
+ # === SIDEBAR ===
51
+ st.sidebar.header("🌟 Features")
52
+ page = st.sidebar.radio(
53
+ "Choose your tool:",
54
+ [
55
+ "AI Assistant Chat",
56
+ "Weather Data",
57
+ "Smart Farming CSV Analysis",
58
+ ]
59
+ )
60
+
61
+ # === MULTI-TURN CHAT ===
62
+ if page == "AI Assistant Chat":
63
+ st.subheader("🧠 AI Climate & Farming Chat Assistant")
64
+ option = st.selectbox(
65
+ "Choose a use case:",
66
+ list(SYSTEM_PROMPTS.keys())
67
+ )
68
+ st.markdown(f"💡 *Example*: {EXAMPLE_QUERIES[option]}")
69
+
70
+ user_input = st.text_area("Enter your question or describe your situation:")
71
+
72
+ if "chat_history" not in st.session_state:
73
+ st.session_state.chat_history = []
74
+
75
+ if st.button("Send to AI") and user_input.strip():
76
+ with st.spinner("Thinking..."):
77
+ messages = [
78
+ {"role": "system", "content": SYSTEM_PROMPTS[option]},
79
+ ]
80
+ # Append chat history for multi-turn
81
+ for chat in st.session_state.chat_history:
82
+ messages.append({"role": "user", "content": chat["user"]})
83
+ messages.append({"role": "assistant", "content": chat["ai"]})
84
+ # Add current user input
85
+ messages.append({"role": "user", "content": user_input})
86
+
87
+ response = client.chat.completions.create(
88
+ model=DEFAULT_MODEL,
89
+ messages=messages,
90
+ )
91
+ ai_response = response.choices[0].message.content
92
+
93
+ # Save chat
94
+ st.session_state.chat_history.append({"user": user_input, "ai": ai_response})
95
+
96
+ # Clear input box
97
+ st.rerun()
98
+
99
+ if st.session_state.chat_history:
100
+ st.markdown("### 🕘 Conversation History")
101
+ for chat in reversed(st.session_state.chat_history):
102
+ st.markdown(f"<div class='user-input'>You:</div><div>{chat['user']}</div>", unsafe_allow_html=True)
103
+ st.markdown(f"<div class='ai-response'>{chat['ai']}</div>", unsafe_allow_html=True)
104
+
105
+ # Add PDF download button
106
+ if st.button("Download Chat as PDF"):
107
+ pdf_bytes = generate_pdf(st.session_state.chat_history)
108
+ st.download_button(
109
+ label="Click to Download PDF",
110
+ data=pdf_bytes,
111
+ file_name="climate_advice.pdf",
112
+ mime="application/pdf"
113
+ )
114
+
115
+ if st.button("Clear Chat History"):
116
+ st.session_state.chat_history = []
117
+ st.rerun()
118
+
119
+ # === WEATHER DATA PAGE ===
120
+ elif page == "Weather Data":
121
+ st.subheader("🌍 Advanced Weather & Environmental Data")
122
+
123
+ location_method = st.radio(
124
+ "Choose location input method:",
125
+ ["Enter City", "Select Country"]
126
+ )
127
+
128
+ location = None
129
+ if location_method == "Enter City":
130
+ location = st.text_input("Enter a city or location (e.g., Los Angeles, Delhi):")
131
+ elif location_method == "Select Country":
132
+ country = st.selectbox("Select a country:", [country.name for country in pycountry.countries])
133
+ city = st.text_input("Enter city name:")
134
+ location = f"{city}, {country}" if city else None
135
+
136
+ if location:
137
+ tab1, tab2, tab3 = st.tabs(["Current Weather", "Historical Data", "Air Quality"])
138
+
139
+ with tab1:
140
+ if st.button("Get Current Weather"):
141
+ with st.spinner("Fetching data..."):
142
+ weather_data = get_weather(location)
143
+ if weather_data is None:
144
+ st.error("Failed to fetch weather data for this location.")
145
+ else:
146
+ col1, col2 = st.columns(2)
147
+
148
+ with col1:
149
+ st.markdown(f"### Current Weather in {weather_data['location']}:")
150
+ st.write(f"- Description: {weather_data['description']}")
151
+ st.write(f"- Temperature: {weather_data['temperature_C']} °C")
152
+ st.write(f"- Humidity: {weather_data['humidity_%']} %")
153
+ st.write(f"- Wind Speed: {weather_data['wind_speed_m/s']} m/s")
154
+
155
+ with col2:
156
+ fig = go.Figure()
157
+ fig.add_trace(go.Indicator(
158
+ mode="gauge+number",
159
+ value=weather_data['temperature_C'],
160
+ title={'text': "Temperature (°C)"},
161
+ gauge={'axis': {'range': [-20, 40]},
162
+ 'bar': {'color': "darkgreen"}}
163
+ ))
164
+ st.plotly_chart(fig)
165
+
166
+ with tab2:
167
+ days = st.slider("Select number of days for historical data:", 1, 30, 7)
168
+ if st.button("Get Historical Weather"):
169
+ with st.spinner("Fetching historical data..."):
170
+ hist_data = get_historical_weather(location, days)
171
+ if hist_data is None:
172
+ st.error("Failed to fetch historical weather data.")
173
+ else:
174
+ daily = hist_data['daily']
175
+ df = pd.DataFrame({
176
+ 'Date': pd.date_range(start=daily['time'][0], periods=len(daily['time'])),
177
+ 'Max Temp': daily['temperature_2m_max'],
178
+ 'Min Temp': daily['temperature_2m_min'],
179
+ 'Precipitation': daily['precipitation_sum'],
180
+ 'Wind Speed': daily['wind_speed_10m_max']
181
+ })
182
+
183
+ # Create temperature range plot
184
+ fig = go.Figure()
185
+ fig.add_trace(go.Scatter(
186
+ x=df['Date'],
187
+ y=df['Max Temp'],
188
+ name='Max Temperature',
189
+ line=dict(color='red')
190
+ ))
191
+ fig.add_trace(go.Scatter(
192
+ x=df['Date'],
193
+ y=df['Min Temp'],
194
+ name='Min Temperature',
195
+ line=dict(color='blue'),
196
+ fill='tonexty'
197
+ ))
198
+ fig.update_layout(
199
+ title='Temperature Range Over Time',
200
+ xaxis_title='Date',
201
+ yaxis_title='Temperature (°C)',
202
+ hovermode='x unified'
203
+ )
204
+ st.plotly_chart(fig)
205
+
206
+ # Create precipitation and wind speed plot
207
+ fig2 = go.Figure()
208
+ fig2.add_trace(go.Bar(
209
+ x=df['Date'],
210
+ y=df['Precipitation'],
211
+ name='Precipitation',
212
+ marker_color='lightblue'
213
+ ))
214
+ fig2.add_trace(go.Scatter(
215
+ x=df['Date'],
216
+ y=df['Wind Speed'],
217
+ name='Wind Speed',
218
+ line=dict(color='orange'),
219
+ yaxis='y2'
220
+ ))
221
+ fig2.update_layout(
222
+ title='Precipitation and Wind Speed',
223
+ xaxis_title='Date',
224
+ yaxis_title='Precipitation (mm)',
225
+ yaxis2=dict(
226
+ title='Wind Speed (m/s)',
227
+ overlaying='y',
228
+ side='right'
229
+ )
230
+ )
231
+ st.plotly_chart(fig2)
232
+
233
+ with tab3:
234
+ if st.button("Get Air Quality Data"):
235
+ with st.spinner("Fetching air quality data..."):
236
+ aq_data = get_air_quality(location, AIRVISUAL_API_KEY)
237
+ if aq_data is None:
238
+ st.error("Failed to fetch air quality data.")
239
+ else:
240
+ st.markdown(f"### Air Quality in {location}")
241
+ current = aq_data['current']
242
+
243
+ # Create air quality gauges
244
+ col1, col2, col3 = st.columns(3)
245
+
246
+ # Define parameters
247
+ params = {
248
+ 'pm10': {'name': 'PM10 (μg/m³)', 'range': [0, 100]},
249
+ 'pm2_5': {'name': 'PM2.5 (μg/m³)', 'range': [0, 50]},
250
+ 'ozone': {'name': 'Ozone (μg/m³)', 'range': [0, 100]},
251
+ 'nitrogen_dioxide': {'name': 'Nitrogen Dioxide (μg/m³)', 'range': [0, 100]},
252
+ 'sulphur_dioxide': {'name': 'Sulphur Dioxide (μg/m³)', 'range': [0, 100]}
253
+ }
254
+
255
+ # Display gauges for first 3 parameters
256
+ for i, param in enumerate(['pm2_5', 'pm10', 'ozone']):
257
+ if param in current and current[param] is not None:
258
+ with [col1, col2, col3][i]:
259
+ fig = go.Figure(go.Indicator(
260
+ mode="gauge+number",
261
+ value=current[param],
262
+ title={'text': params[param]['name']},
263
+ gauge={'axis': {'range': params[param]['range']},
264
+ 'bar': {'color': "darkgreen"}}
265
+ ))
266
+ st.plotly_chart(fig)
267
+
268
+ # Display other pollutants
269
+ st.markdown("### Other Pollutants")
270
+ col1, col2 = st.columns(2)
271
+ with col1:
272
+ if 'nitrogen_dioxide' in current and current['nitrogen_dioxide'] is not None:
273
+ st.write(f"- Nitrogen Dioxide: {current['nitrogen_dioxide']} μg/m³")
274
+ with col2:
275
+ if 'sulphur_dioxide' in current and current['sulphur_dioxide'] is not None:
276
+ st.write(f"- Sulphur Dioxide: {current['sulphur_dioxide']} μg/m³")
277
+
278
+ # === SMART FARMING CSV ANALYSIS PAGE ===
279
+ elif page == "Smart Farming CSV Analysis":
280
+ st.subheader("🌱 AI-Powered Farming Data Analysis")
281
+ uploaded_file = st.file_uploader("Upload your farming dataset (CSV)", type=["csv"])
282
+
283
+ if uploaded_file:
284
+ try:
285
+ df = pd.read_csv(uploaded_file)
286
+ st.success("✅ Data loaded successfully!")
287
+
288
+ # Create tabs for different analyses
289
+ tab1, tab2 = st.tabs(["Data Explorer", "AI Insights"])
290
+
291
+ with tab1:
292
+ st.markdown("### Dataset Preview")
293
+ st.dataframe(df.head(5))
294
+
295
+ if st.checkbox("Show Summary Statistics"):
296
+ st.markdown("### Summary Statistics")
297
+ st.write(df.describe().transpose())
298
+
299
+ # Interactive visualizations
300
+ numeric_cols = df.select_dtypes(include=["float64", "int64"]).columns.tolist()
301
+ if numeric_cols:
302
+ col1, col2 = st.columns(2)
303
+ with col1:
304
+ x_axis = st.selectbox("X-Axis", numeric_cols)
305
+ with col2:
306
+ y_axis = st.selectbox("Y-Axis", numeric_cols)
307
+
308
+ if x_axis and y_axis:
309
+ fig = px.scatter(
310
+ df,
311
+ x=x_axis,
312
+ y=y_axis,
313
+ title=f"{y_axis} vs {x_axis}",
314
+ trendline="ols",
315
+ color_discrete_sequence=["#2E7D32"]
316
+ )
317
+ st.plotly_chart(fig)
318
+
319
+ # Correlation heatmap
320
+ if len(numeric_cols) > 1:
321
+ st.markdown("### Correlation Matrix")
322
+ corr = df[numeric_cols].corr()
323
+ fig = px.imshow(corr,
324
+ text_auto=True,
325
+ aspect="auto",
326
+ color_continuous_scale="Greens")
327
+ st.plotly_chart(fig)
328
+
329
+ with tab2:
330
+ st.markdown("### AI-Powered Farming Insights")
331
+ st.info("Ask specific questions about your farming data to get actionable insights")
332
+
333
+ analysis_prompt = st.text_area(
334
+ "What insights would you like? (Examples below):",
335
+ "Analyze this farming data and provide key insights:",
336
+ height=100
337
+ )
338
+
339
+ st.caption("Examples: 'Suggest optimal crops for this region', 'Identify yield patterns', "
340
+ "'Recommend irrigation improvements', 'Predict harvest timing'")
341
+
342
+ if st.button("Generate AI Insights", type="primary"):
343
+ with st.spinner("🧠 Analyzing with AI..."):
344
+ # Prepare data context
345
+ context = f"Dataset has {len(df)} rows and columns: {', '.join(df.columns)}\n"
346
+ context += f"First 3 rows:\n{df.head(3).to_string(index=False)}"
347
+
348
+ # Get AI analysis
349
+ messages = [
350
+ {
351
+ "role": "system",
352
+ "content": (
353
+ "You are an expert agricultural data scientist. Analyze farming datasets and provide: "
354
+ "1. Actionable insights for improving crop yield "
355
+ "2. Recommendations based on climate patterns "
356
+ "3. Resource optimization strategies "
357
+ "4. Sustainable farming practices "
358
+ "Use bullet points and specific numbers when possible."
359
+ )
360
+ },
361
+ {
362
+ "role": "user",
363
+ "content": f"{analysis_prompt}\n\n{context}"
364
+ }
365
+ ]
366
+
367
+ response = client.chat.completions.create(
368
+ model=DEFAULT_MODEL,
369
+ messages=messages,
370
+ temperature=0.3
371
+ )
372
+ insights = response.choices[0].message.content
373
+ st.markdown(f"<div class='insight-box'>{insights}</div>", unsafe_allow_html=True)
374
+
375
+ except Exception as e:
376
+ st.error(f"❌ Error processing data: {str(e)}")
377
+ else:
378
+ st.info("👆 Upload a CSV file containing your farming data to get started")
379
+
380
+ # === FOOTER ===
381
+ st.markdown("---")
382
+ st.markdown(
383
+ "<small>🔋 Powered by <b>llama3-70b-8192</b> on Groq • Real-time data from Open-Meteo API</small>",
384
+ unsafe_allow_html=True
385
+ )