Files changed (1) hide show
  1. app.py +567 -74
app.py CHANGED
@@ -1,64 +1,508 @@
1
  import os
2
- from flask import Flask, render_template, request, jsonify
3
  import requests
4
  import pandas as pd
5
  from datetime import datetime
 
 
 
 
 
 
 
 
 
 
 
6
  app = Flask(__name__)
7
 
8
- # Function to fetch data from the API
9
- def fetch_market_data(state=None, district=None, market=None, commodity=None):
10
- api_key = os.getenv("GOV_API_KEY")
11
- api_key = api_key
12
- base_url = "https://api.data.gov.in/resource/9ef84268-d588-465a-a308-a864a43d0070"
 
 
 
 
 
 
 
13
  params = {
14
  "api-key": api_key,
15
  "format": "json",
16
- "limit": 15000,
17
  }
 
 
 
 
 
 
 
 
 
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  if state:
20
- params["filters[state.keyword]"] = state
21
  if district:
22
- params["filters[district.keyword]"] = district
23
  if market:
24
- params["filters[market.keyword]"] = market
25
  if commodity:
26
- params["filters[commodity.keyword]"] = commodity
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- response = requests.get(base_url, params=params)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- if response.status_code == 200:
31
- data = response.json()
32
- records = data.get("records", [])
33
- df = pd.DataFrame(records)
34
- return df
35
- else:
36
- return pd.DataFrame()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
 
38
- # Fetch initial state data
39
- @app.route("/")
40
  def index():
41
- # Fetch distinct states for dropdown
42
- market_data = fetch_market_data()
43
- states = market_data['state'].dropna().unique().tolist()
44
- today = datetime.today().strftime('%Y-%m-%d')
45
- return render_template('index.html', states=states, today=today)
46
-
47
- # Handle AJAX requests to filter market data
48
- @app.route("/filter_data", methods=["POST"])
 
 
 
 
49
  def filter_data():
50
- state = request.form.get("state")
51
- district = request.form.get("district")
52
- market = request.form.get("market")
53
- commodity = request.form.get("commodity")
54
-
55
- # Fetch filtered data
56
- filtered_data = fetch_market_data(state, district, market, commodity)
57
-
58
- # Generate HTML for the filtered table
59
- table_html = ""
60
- for _, row in filtered_data.iterrows():
61
- table_html += f"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  <tr>
63
  <td>{row['state']}</td>
64
  <td>{row['district']}</td>
@@ -67,61 +511,110 @@ def filter_data():
67
  <td>{row['variety']}</td>
68
  <td>{row['grade']}</td>
69
  <td>{row['arrival_date']}</td>
70
- <td>{row['min_price']}</td>
71
- <td>{row['max_price']}</td>
72
- <td>{row['modal_price']}</td>
73
  </tr>
74
  """
 
75
 
76
- # Get top 5 cheapest crops by modal price
77
- cheapest_crops = filtered_data.sort_values("modal_price", ascending=True).head(5)
78
- cheapest_html = ""
 
 
 
 
 
 
 
 
 
 
 
79
  for _, row in cheapest_crops.iterrows():
80
- cheapest_html += f"""
81
  <tr>
82
  <td>{row['commodity']}</td>
83
- <td>{row['modal_price']}</td>
 
84
  </tr>
85
  """
 
86
 
87
- # Get top 5 costliest crops by modal price
88
- costliest_crops = filtered_data.sort_values("modal_price", ascending=False).head(5)
89
- costliest_html = ""
 
 
 
 
 
 
 
 
 
 
 
90
  for _, row in costliest_crops.iterrows():
91
- costliest_html += f"""
92
  <tr>
93
  <td>{row['commodity']}</td>
94
- <td>{row['modal_price']}</td>
 
95
  </tr>
96
  """
 
97
 
98
- return jsonify({
99
- "market_html": table_html,
100
- "cheapest_html": cheapest_html,
101
- "costliest_html": costliest_html
102
- })
 
103
 
104
- # Handle AJAX requests for dropdown filtering
105
- @app.route("/get_districts", methods=["POST"])
 
 
 
 
 
 
 
 
 
 
 
 
106
  def get_districts():
107
- state = request.form.get("state")
108
- market_data = fetch_market_data(state=state)
109
- districts = market_data["district"].dropna().unique().tolist()
110
  return jsonify(districts)
111
 
112
- @app.route("/get_markets", methods=["POST"])
113
  def get_markets():
114
- district = request.form.get("district")
115
- market_data = fetch_market_data(district=district)
116
- markets = market_data["market"].dropna().unique().tolist()
117
  return jsonify(markets)
118
 
119
- @app.route("/get_commodities", methods=["POST"])
120
  def get_commodities():
121
- market = request.form.get("market")
122
- market_data = fetch_market_data(market=market)
123
- commodities = market_data["commodity"].dropna().unique().tolist()
124
  return jsonify(commodities)
125
 
126
- if __name__ == "__main__":
127
- app.run(debug=True, host="0.0.0.0", port=7860)
 
 
 
 
 
 
 
 
 
 
1
  import os
2
+ from flask import Flask, render_template, request, jsonify, send_file
3
  import requests
4
  import pandas as pd
5
  from datetime import datetime
6
+ import plotly.express as px
7
+ import plotly.io as pio
8
+ import numpy as np
9
+ import dotenv
10
+ import json
11
+ import gtts
12
+ import uuid
13
+ from pathlib import Path
14
+
15
+ dotenv.load_dotenv()
16
+
17
  app = Flask(__name__)
18
 
19
+ # Create audio directory if it doesn't exist
20
+ AUDIO_DIR = Path("static/audio")
21
+ AUDIO_DIR.mkdir(parents=True, exist_ok=True)
22
+
23
+ def fetch_market_data(state=None, district=None, market=None, commodity=None):
24
+ """Fetch data from the agricultural market API.
25
+ If the API fails or returns empty data, fallback to the CSV file.
26
+ Filters (state, district, market, commodity) are applied manually on CSV data.
27
+ """
28
+ api_key = "579b464db66ec23bdd000001189bbb99e979428764bdbe8fdd44ebb7"
29
+ base_url = "https://api.data.gov.in/resource/9ef84268-d588-465a-a308-a864a43d007"
30
+
31
  params = {
32
  "api-key": api_key,
33
  "format": "json",
34
+ "limit": 1000,
35
  }
36
+
37
+ if state:
38
+ params["filters[state]"] = state
39
+ if district:
40
+ params["filters[district]"] = district
41
+ if market:
42
+ params["filters[market]"] = market
43
+ if commodity:
44
+ params["filters[commodity]"] = commodity
45
 
46
+ try:
47
+ response = requests.get(base_url, params=params)
48
+ if response.status_code == 200:
49
+ data = response.json()
50
+ records = data.get("records", [])
51
+ df = pd.DataFrame(records)
52
+ else:
53
+ print(f"API Error: {response.status_code}")
54
+ raise Exception(f"API Error: {response.status_code}")
55
+ except Exception as e:
56
+ print(f"Error fetching data from API: {str(e)}. Falling back to CSV file.")
57
+ df = pd.read_csv("final_price_data.csv")
58
+ if 'min_price' not in df.columns:
59
+ rename_mapping = {
60
+ 'State': 'state',
61
+ 'District': 'district',
62
+ 'Market': 'market',
63
+ 'Commodity': 'commodity',
64
+ 'Variety': 'variety',
65
+ 'Grade': 'grade',
66
+ 'Arrival_Date': 'arrival_date',
67
+ 'Min_x0020_Price': 'min_price',
68
+ 'Max_x0020_Price': 'max_price',
69
+ 'Modal_x0020_Price': 'modal_price'
70
+ }
71
+ df.rename(columns=rename_mapping, inplace=True)
72
+
73
+ if df.empty:
74
+ print("API returned empty data. Falling back to CSV file.")
75
+ df = pd.read_csv("final_price_data.csv")
76
+ if 'min_price' not in df.columns:
77
+ rename_mapping = {
78
+ 'State': 'state',
79
+ 'District': 'district',
80
+ 'Market': 'market',
81
+ 'Commodity': 'commodity',
82
+ 'Variety': 'variety',
83
+ 'Grade': 'grade',
84
+ 'Arrival_Date': 'arrival_date',
85
+ 'Min_x0020_Price': 'min_price',
86
+ 'Max_x0020_Price': 'max_price',
87
+ 'Modal_x0020_Price': 'modal_price'
88
+ }
89
+ df.rename(columns=rename_mapping, inplace=True)
90
+
91
  if state:
92
+ df = df[df['state'] == state]
93
  if district:
94
+ df = df[df['district'] == district]
95
  if market:
96
+ df = df[df['market'] == market]
97
  if commodity:
98
+ df = df[df['commodity'] == commodity]
99
+
100
+ return df
101
+
102
+ def get_ai_insights(market_data, state, district, market=None, commodity=None, language="English"):
103
+ """Get enhanced insights from Gemini API with focus on profitable suggestions for farmers.
104
+ Supports multiple languages through the prompt.
105
+ Returns dynamic insights only. If something goes wrong, returns an empty string.
106
+ """
107
+ if not state or not district or market_data.empty:
108
+ return ""
109
+
110
+ try:
111
+ # Filter data based on provided parameters
112
+ district_data = market_data[market_data['district'] == district]
113
+ if district_data.empty:
114
+ return ""
115
+
116
+ # Apply market filter if provided
117
+ if market and not market_data[market_data['market'] == market].empty:
118
+ market_specific = True
119
+ district_data = district_data[district_data['market'] == market]
120
+ else:
121
+ market_specific = False
122
+
123
+ # Apply commodity filter if provided
124
+ if commodity and not market_data[market_data['commodity'] == commodity].empty:
125
+ commodity_specific = True
126
+ district_data = district_data[district_data['commodity'] == commodity]
127
+ else:
128
+ commodity_specific = False
129
+
130
+ # Calculate price trends
131
+ price_trends = district_data.groupby('commodity').agg({
132
+ 'modal_price': ['mean', 'min', 'max', 'std']
133
+ }).round(2)
134
+
135
+ # Using environment variable for Gemini API key
136
+ api_key = "AIzaSyBtXV2xJbrWVV57B5RWy_meKXOA59HFMeY"
137
+ if not api_key:
138
+ print("Warning: Gemini API key not set")
139
+ return ""
140
+
141
+ price_trends['price_stability'] = (price_trends['modal_price']['std'] /
142
+ price_trends['modal_price']['mean']).round(2)
143
+
144
+ district_data['arrival_date'] = pd.to_datetime(district_data['arrival_date'])
145
+ district_data['month'] = district_data['arrival_date'].dt.month
146
+ monthly_trends = district_data.groupby(['commodity', 'month'])['modal_price'].mean().round(2)
147
+
148
+ market_competition = len(district_data['market'].unique())
149
+ top_commodities = district_data.groupby('commodity')['modal_price'].mean().nlargest(5).index.tolist()
150
+
151
+ # Get min and max prices for key commodities
152
+ price_range_info = {}
153
+ for commodity in top_commodities[:3]:
154
+ comm_data = district_data[district_data['commodity'] == commodity]
155
+ if not comm_data.empty:
156
+ price_range_info[commodity] = {
157
+ 'min': comm_data['modal_price'].min(),
158
+ 'max': comm_data['modal_price'].max(),
159
+ 'avg': comm_data['modal_price'].mean()
160
+ }
161
+
162
+ # Calculate market-specific metrics if market is selected
163
+ market_details = ""
164
+ if market_specific:
165
+ market_details = f"""
166
+ Market-specific information for {market}:
167
+ - Number of commodities: {len(district_data['commodity'].unique())}
168
+ - Most expensive commodity: {district_data.groupby('commodity')['modal_price'].mean().idxmax()}
169
+ - Cheapest commodity: {district_data.groupby('commodity')['modal_price'].mean().idxmin()}
170
+ """
171
+
172
+ # Commodity-specific details if commodity is selected
173
+ commodity_details = ""
174
+ if commodity_specific:
175
+ commodity_data = district_data[district_data['commodity'] == commodity]
176
+ best_market = commodity_data.loc[commodity_data['modal_price'].idxmin()]['market']
177
+ worst_market = commodity_data.loc[commodity_data['modal_price'].idxmax()]['market']
178
+
179
+ commodity_details = f"""
180
+ Commodity-specific information for {commodity}:
181
+ - Best market to buy (lowest price): {best_market}
182
+ - Highest priced market: {worst_market}
183
+ - Price variance across markets: {commodity_data['modal_price'].std().round(2)}
184
+ """
185
+
186
+ # Improved prompt for better structured output with language support
187
+ prompt = f"""
188
+ Analyze the following agricultural market data for {district}, {state} and provide insights in {language} language.
189
+
190
+ Market data:
191
+ - Active markets: {market_competition}
192
+ - Top crops: {', '.join(top_commodities[:5])}
193
+ - Data from {len(price_trends.index)} crops and {len(monthly_trends)} monthly entries.
194
+
195
+ Price information:
196
+ {json.dumps(price_range_info, indent=2)}
197
+
198
+ {market_details}
199
+ {commodity_details}
200
+
201
+ Analyze this data and provide insights about crop market trends and profitability.
202
+ Include specific numbers from the data about prices.
203
+
204
+ Provide structured insights with clear sections. Use this exact format with bullet points:
205
+
206
+ Crop Profitability Analysis:
207
+ * [First insight about profitable crops with specific prices mentioned]
208
+ * [Second insight]
209
+
210
+ Market Price Analysis:
211
+ * [First insight about markets with specific price ranges]
212
+ * [Second insight]
213
+
214
+ Recommendations for Farmers:
215
+ * [Action item 1]
216
+ * [Action item 2]
217
+ """
218
+
219
+ api_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent"
220
+ headers = {"Content-Type": "application/json"}
221
+
222
+ payload = {
223
+ "contents": [
224
+ {
225
+ "parts": [
226
+ {"text": prompt}
227
+ ]
228
+ }
229
+ ],
230
+ "generationConfig": {
231
+ "temperature": 0.4,
232
+ "maxOutputTokens": 1024
233
+ }
234
+ }
235
+
236
+ response = requests.post(
237
+ f"{api_url}?key={api_key}",
238
+ headers=headers,
239
+ json=payload,
240
+ timeout=20
241
+ )
242
+
243
+ if response.status_code == 200:
244
+ response_data = response.json()
245
+ if 'candidates' in response_data and len(response_data['candidates']) > 0:
246
+ content = response_data['candidates'][0]['content']
247
+ if 'parts' in content and len(content['parts']) > 0:
248
+ insights = content['parts'][0]['text']
249
+ return format_ai_insights(insights, language)
250
+ print(f"API Response issue: {response.text[:100]}")
251
+ else:
252
+ print(f"Gemini API Error: {response.status_code} - {response.text[:100]}")
253
+
254
+ return ""
255
+
256
+ except Exception as e:
257
+ print(f"Error generating insights: {str(e)}")
258
+ return ""
259
+
260
+ def extract_text_from_insights(insights_html):
261
+ """Extract pure text content from HTML insights for text-to-speech conversion."""
262
+ # Simple HTML tag removal - for production, consider using BeautifulSoup for better parsing
263
+ import re
264
+ text = re.sub(r'<.*?>', ' ', insights_html)
265
+ text = re.sub(r'\s+', ' ', text) # Remove extra whitespace
266
+ return text.strip()
267
+
268
+ def create_audio_from_text(text, language_code="en"):
269
+ """Generate audio file from text using gTTS."""
270
+ if not text:
271
+ return None
272
+
273
+ # Map UI language selection to gTTS language codes
274
+ language_map = {
275
+ "English": "en",
276
+ "Hindi": "hi",
277
+ "Tamil": "ta",
278
+ "Telugu": "te",
279
+ "Marathi": "mr",
280
+ "Bengali": "bn",
281
+ "Gujarati": "gu",
282
+ "Kannada": "kn",
283
+ "Malayalam": "ml",
284
+ "Punjabi": "pa"
285
+ }
286
+
287
+ tts_lang = language_map.get(language_code, "en")
288
+
289
+ # Generate unique filename
290
+ filename = f"{uuid.uuid4()}.mp3"
291
+ filepath = AUDIO_DIR / filename
292
+
293
+ try:
294
+ tts = gtts.gTTS(text, lang=tts_lang, slow=False)
295
+ tts.save(str(filepath))
296
+ return f"/static/audio/{filename}"
297
+ except Exception as e:
298
+ print(f"Error creating audio: {str(e)}")
299
+ return None
300
+
301
+ def create_audio_local_fallback(text, language_code="en"):
302
+ """Local fallback for TTS when network is unavailable."""
303
+ try:
304
+ # This requires pyttsx3 to be installed
305
+ import pyttsx3
306
+ engine = pyttsx3.init()
307
+
308
+ # Generate unique filename
309
+ filename = f"{uuid.uuid4()}.mp3"
310
+ filepath = AUDIO_DIR / filename
311
+
312
+ engine.save_to_file(text, str(filepath))
313
+ engine.runAndWait()
314
+
315
+ return f"/static/audio/{filename}"
316
+ except Exception as e:
317
+ print(f"Local TTS fallback failed: {str(e)}")
318
+ return None
319
 
320
+ def format_ai_insights(insights_data, language="English"):
321
+ """Format AI insights into structured HTML.
322
+ Returns an empty string if no valid insights are provided.
323
+ """
324
+ if not insights_data or not insights_data.strip():
325
+ return ""
326
+
327
+ # Process the insights text - each bullet point becomes a formatted item
328
+ formatted_content = ""
329
+
330
+ # Split by bullet points
331
+ bullet_points = insights_data.split('*')
332
+
333
+ # Filter out empty items and process each bullet point
334
+ bullet_points = [point.strip() for point in bullet_points if point.strip()]
335
+
336
+ # Check if any section headers exist in the content
337
+ sections = {}
338
+ current_section = "Recommendations"
339
+
340
+ for point in bullet_points:
341
+ if ":" in point and len(point.split(":")[0]) < 30: # Likely a section header
342
+ current_section = point.split(":")[0].strip()
343
+ # Start a new section
344
+ if current_section not in sections:
345
+ sections[current_section] = []
346
+ else:
347
+ # Add to current section
348
+ if current_section not in sections:
349
+ sections[current_section] = []
350
+ sections[current_section].append(point)
351
+
352
+ # Now build the HTML with proper sections
353
+ for section, points in sections.items():
354
+ formatted_content += f'<div class="insight-card"><h5>{section}</h5><ul class="insight-list">'
355
+ for point in points:
356
+ # Highlight prices with special styling
357
+ if "₹" in point:
358
+ # Replace price mentions with highlighted spans
359
+ parts = point.split("₹")
360
+ styled_point = parts[0]
361
+ for i in range(1, len(parts)):
362
+ # Extract the price value
363
+ price_text = parts[i].split()[0]
364
+ # Add the highlighted price and the rest of the text
365
+ styled_point += f'<span class="price-highlight">₹{price_text}</span>' + parts[i][len(price_text):]
366
+ formatted_content += f'<li>{styled_point}</li>'
367
+ else:
368
+ formatted_content += f'<li>{point}</li>'
369
+ formatted_content += '</ul></div>'
370
+
371
+ # Create the plain text version for audio generation
372
+ plain_text = f"Market Insights for {language}.\n\n"
373
+ for section, points in sections.items():
374
+ plain_text += f"{section}:\n"
375
+ for point in points:
376
+ # Clean up for speech
377
+ clean_point = point.replace("₹", " rupees ")
378
+ plain_text += f"• {clean_point}\n"
379
+ plain_text += "\n"
380
+
381
+ # Generate audio file
382
+ audio_path = create_audio_from_text(plain_text, language)
383
+ if audio_path is None:
384
+ audio_path = create_audio_local_fallback(plain_text)
385
+
386
+ # Add a wrapper for the insights with audio player
387
+ audio_player = ""
388
+ if audio_path:
389
+ audio_player = f"""
390
+ <div class="audio-player-container">
391
+ <h4>Listen to Insights</h4>
392
+ <audio id="insightsAudio" controls>
393
+ <source src="{audio_path}" type="audio/mpeg">
394
+ Your browser does not support the audio element.
395
+ </audio>
396
+ <button class="btn btn-sm btn-custom mt-2" id="playAudioBtn">
397
+ <i class="fa fa-play"></i> Play Audio
398
+ </button>
399
+ </div>
400
+ """
401
+
402
+ html = f"""
403
+ <div class="insights-header">
404
+ <h3>AI Market Insights</h3>
405
+ {audio_player}
406
+ </div>
407
+ <div class="insight-section">
408
+ {formatted_content}
409
+ </div>
410
+ """
411
+
412
+ return html
413
 
414
+ def generate_plots(df):
415
+ """Generate all plots in English"""
416
+ if df.empty:
417
+ return {}, "No data available"
418
+
419
+ price_cols = ['min_price', 'max_price', 'modal_price']
420
+ for col in price_cols:
421
+ df[col] = pd.to_numeric(df[col], errors='coerce')
422
+
423
+ colors = ["#4CAF50", "#8BC34A", "#CDDC39", "#FFC107", "#FF5722"]
424
+
425
+ df_bar = df.groupby('commodity')['modal_price'].mean().reset_index()
426
+ fig_bar = px.bar(df_bar,
427
+ x='commodity',
428
+ y='modal_price',
429
+ title="Average Price by Commodity",
430
+ color_discrete_sequence=colors)
431
+
432
+ fig_line = None
433
+ if 'commodity' in df.columns and len(df['commodity'].unique()) == 1:
434
+ df['arrival_date'] = pd.to_datetime(df['arrival_date'])
435
+ df_line = df.sort_values('arrival_date')
436
+ fig_line = px.line(df_line,
437
+ x='arrival_date',
438
+ y='modal_price',
439
+ title="Price Trend",
440
+ color_discrete_sequence=colors)
441
+
442
+ fig_box = px.box(df,
443
+ x='commodity',
444
+ y='modal_price',
445
+ title="Price Distribution",
446
+ color='commodity',
447
+ color_discrete_sequence=colors)
448
+
449
+ plots = {
450
+ 'bar': pio.to_html(fig_bar, full_html=False),
451
+ 'box': pio.to_html(fig_box, full_html=False)
452
+ }
453
+ if fig_line:
454
+ plots['line'] = pio.to_html(fig_line, full_html=False)
455
+
456
+ return plots
457
 
458
+ @app.route('/')
 
459
  def index():
460
+ try:
461
+ initial_data = fetch_market_data()
462
+ states = sorted(initial_data['state'].dropna().unique()) if not initial_data.empty else []
463
+ except Exception as e:
464
+ print(f"Error fetching initial data: {str(e)}")
465
+ states = []
466
+
467
+ return render_template('index.html',
468
+ states=states,
469
+ today=datetime.today().strftime('%Y-%m-%d'))
470
+
471
+ @app.route('/filter_data', methods=['POST'])
472
  def filter_data():
473
+ state = request.form.get('state')
474
+ district = request.form.get('district')
475
+ market = request.form.get('market')
476
+ commodity = request.form.get('commodity')
477
+ language = request.form.get('language', 'English') # Default to English
478
+
479
+ df = fetch_market_data(state, district, market, commodity)
480
+ plots = generate_plots(df)
481
+ # Pass market and commodity to get_ai_insights
482
+ insights = get_ai_insights(df, state, district, market, commodity, language) if state and district and not df.empty else ""
483
+
484
+ market_table_html = """
485
+ <div class="table-responsive">
486
+ <table class="table table-striped table-bordered">
487
+ <thead>
488
+ <tr>
489
+ <th>State</th>
490
+ <th>District</th>
491
+ <th>Market</th>
492
+ <th>Commodity</th>
493
+ <th>Variety</th>
494
+ <th>Grade</th>
495
+ <th>Arrival Date</th>
496
+ <th>Min Price</th>
497
+ <th>Max Price</th>
498
+ <th>Modal Price</th>
499
+ </tr>
500
+ </thead>
501
+ <tbody>
502
+ """
503
+
504
+ for _, row in df.iterrows():
505
+ market_table_html += f"""
506
  <tr>
507
  <td>{row['state']}</td>
508
  <td>{row['district']}</td>
 
511
  <td>{row['variety']}</td>
512
  <td>{row['grade']}</td>
513
  <td>{row['arrival_date']}</td>
514
+ <td>₹{row['min_price']}</td>
515
+ <td>₹{row['max_price']}</td>
516
+ <td>₹{row['modal_price']}</td>
517
  </tr>
518
  """
519
+ market_table_html += "</tbody></table></div>"
520
 
521
+ cheapest_crops = df.sort_values('modal_price', ascending=True).head(5)
522
+ cheapest_table_html = """
523
+ <div class="table-responsive">
524
+ <table class="table table-sm table-bordered">
525
+ <thead>
526
+ <tr>
527
+ <th>Commodity</th>
528
+ <th>Market</th>
529
+ <th>Modal Price</th>
530
+ </tr>
531
+ </thead>
532
+ <tbody>
533
+ """
534
+
535
  for _, row in cheapest_crops.iterrows():
536
+ cheapest_table_html += f"""
537
  <tr>
538
  <td>{row['commodity']}</td>
539
+ <td>{row['market']}</td>
540
+ <td>₹{row['modal_price']}</td>
541
  </tr>
542
  """
543
+ cheapest_table_html += "</tbody></table></div>"
544
 
545
+ costliest_crops = df.sort_values('modal_price', ascending=False).head(5)
546
+ costliest_table_html = """
547
+ <div class="table-responsive">
548
+ <table class="table table-sm table-bordered">
549
+ <thead>
550
+ <tr>
551
+ <th>Commodity</th>
552
+ <th>Market</th>
553
+ <th>Modal Price</th>
554
+ </tr>
555
+ </thead>
556
+ <tbody>
557
+ """
558
+
559
  for _, row in costliest_crops.iterrows():
560
+ costliest_table_html += f"""
561
  <tr>
562
  <td>{row['commodity']}</td>
563
+ <td>{row['market']}</td>
564
+ <td>₹{row['modal_price']}</td>
565
  </tr>
566
  """
567
+ costliest_table_html += "</tbody></table></div>"
568
 
569
+ market_stats = {
570
+ 'total_commodities': len(df['commodity'].unique()),
571
+ 'avg_modal_price': f"₹{df['modal_price'].mean():.2f}",
572
+ 'price_range': f"₹{df['modal_price'].min():.2f} - ₹{df['modal_price'].max():.2f}",
573
+ 'total_markets': len(df['market'].unique())
574
+ }
575
 
576
+ response = {
577
+ 'plots': plots,
578
+ 'insights': insights,
579
+ 'success': not df.empty,
580
+ 'hasStateDistrict': bool(state and district),
581
+ 'market_html': market_table_html,
582
+ 'cheapest_html': cheapest_table_html,
583
+ 'costliest_html': costliest_table_html,
584
+ 'market_stats': market_stats
585
+ }
586
+
587
+ return jsonify(response)
588
+
589
+ @app.route('/get_districts', methods=['POST'])
590
  def get_districts():
591
+ state = request.form.get('state')
592
+ df = fetch_market_data(state=state)
593
+ districts = sorted(df['district'].dropna().unique())
594
  return jsonify(districts)
595
 
596
+ @app.route('/get_markets', methods=['POST'])
597
  def get_markets():
598
+ district = request.form.get('district')
599
+ df = fetch_market_data(district=district)
600
+ markets = sorted(df['market'].dropna().unique())
601
  return jsonify(markets)
602
 
603
+ @app.route('/get_commodities', methods=['POST'])
604
  def get_commodities():
605
+ market = request.form.get('market')
606
+ df = fetch_market_data(market=market)
607
+ commodities = sorted(df['commodity'].dropna().unique())
608
  return jsonify(commodities)
609
 
610
+ @app.route('/static/audio/<filename>')
611
+ def serve_audio(filename):
612
+ try:
613
+ return send_file(f"static/audio/{filename}", mimetype="audio/mpeg")
614
+ except Exception as e:
615
+ print(f"Error serving audio file: {str(e)}")
616
+ return "Audio file not found", 404
617
+
618
+ if __name__ == '__main__':
619
+ pio.templates.default = "plotly_white"
620
+ app.run(debug=True, host='0.0.0.0', port=7860)