sikeaditya commited on
Commit
0407440
·
verified ·
1 Parent(s): b8499c6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +272 -269
app.py CHANGED
@@ -5,58 +5,28 @@ import pandas as pd
5
  from datetime import datetime
6
  import plotly.express as px
7
  import plotly.io as pio
8
- from googletrans import Translator
9
  import numpy as np
 
 
10
 
11
- app = Flask(__name__)
12
-
13
- # Initialize translator
14
- translator = Translator()
15
 
16
- # Translation dictionaries
17
- MARATHI_TRANSLATIONS = {
18
- 'state': 'राज्य',
19
- 'district': 'जिल्हा',
20
- 'market': 'बाजार',
21
- 'commodity': 'पीक',
22
- 'variety': 'प्रकार',
23
- 'grade': 'श्रेणी',
24
- 'arrival_date': 'आगमन तारीख',
25
- 'min_price': 'किमान किंमत',
26
- 'max_price': 'कमाल किंमत',
27
- 'modal_price': 'सरासरी किंमत',
28
- 'Select State': 'राज्य निवडा',
29
- 'Select District': 'जिल्हा निवडा',
30
- 'Select Market': 'बाजार निवडा',
31
- 'Select Commodity': 'पीक निवडा',
32
- 'Market Data': 'बाजार माहिती',
33
- 'Top 5 Cheapest Crops': 'सर्वात स्वस्त 5 पिके',
34
- 'Top 5 Costliest Crops': 'सर्वात महाग 5 पिके'
35
- }
36
-
37
- def translate_to_marathi(text):
38
- """Translate text to Marathi"""
39
- try:
40
- if text in MARATHI_TRANSLATIONS:
41
- return MARATHI_TRANSLATIONS[text]
42
- translation = translator.translate(text, dest='mr')
43
- return translation.text
44
- except:
45
- return text
46
 
47
  def fetch_market_data(state=None, district=None, market=None, commodity=None):
48
- """Fetch data from the agricultural market API"""
49
- api_key = os.getenv("data_api_key")
50
- print(api_key)
51
- base_url = "https://api.data.gov.in/resource/9ef84268-d588-465a-a308-a864a43d0070"
 
 
52
 
53
  params = {
54
- "api-key": "579b464db66ec23bdd000001189bbb99e979428764bdbe8fdd44ebb7",
55
  "format": "json",
56
- "limit": 10,
57
  }
58
 
59
- # Add filters if provided
60
  if state:
61
  params["filters[state]"] = state
62
  if district:
@@ -72,147 +42,295 @@ def fetch_market_data(state=None, district=None, market=None, commodity=None):
72
  data = response.json()
73
  records = data.get("records", [])
74
  df = pd.DataFrame(records)
75
- return df
76
  else:
77
  print(f"API Error: {response.status_code}")
78
- return pd.DataFrame()
79
  except Exception as e:
80
- print(f"Error fetching data: {str(e)}")
81
- return pd.DataFrame()
82
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
 
84
- def get_ai_insights(market_data, state, district):
85
- """Get enhanced insights from LLM API with focus on profitable suggestions for farmers"""
 
 
 
86
  if not state or not district or market_data.empty:
87
  return ""
88
-
89
  try:
90
- # Calculate additional market metrics
91
  district_data = market_data[market_data['district'] == district]
 
 
92
 
93
- # Price trends and volatility
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  price_trends = district_data.groupby('commodity').agg({
95
  'modal_price': ['mean', 'min', 'max', 'std']
96
  }).round(2)
97
 
98
- # Calculate price stability (lower std/mean ratio indicates more stable prices)
 
 
 
 
 
99
  price_trends['price_stability'] = (price_trends['modal_price']['std'] /
100
  price_trends['modal_price']['mean']).round(2)
101
 
102
- # Identify commodities with consistent high prices
103
- high_value_crops = price_trends[price_trends['modal_price']['mean'] >
104
- price_trends['modal_price']['mean'].median()]
105
-
106
- # Get seasonal patterns
107
  district_data['arrival_date'] = pd.to_datetime(district_data['arrival_date'])
108
  district_data['month'] = district_data['arrival_date'].dt.month
109
  monthly_trends = district_data.groupby(['commodity', 'month'])['modal_price'].mean().round(2)
110
 
111
- # Market competition analysis
112
  market_competition = len(district_data['market'].unique())
 
113
 
114
- # Prepare comprehensive market summary
115
- market_summary = {
116
- "high_value_crops": high_value_crops.index.tolist(),
117
- "price_stability": price_trends['price_stability'].to_dict(),
118
- "monthly_trends": monthly_trends.to_dict(),
119
- "market_competition": market_competition,
120
- "avg_prices": district_data.groupby('commodity')['modal_price'].mean().round(2).to_dict(),
121
- "price_ranges": {
122
- crop: {
123
- 'min': price_trends.loc[crop, ('modal_price', 'min')],
124
- 'max': price_trends.loc[crop, ('modal_price', 'max')]
125
- } for crop in price_trends.index
126
- }
127
- }
128
-
129
- # Enhanced LLM prompt for more actionable insights
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  prompt = f"""
131
- As an agricultural market expert, analyze this data for {district}, {state} and provide specific, actionable advice for farmers:
132
-
133
- Market Overview:
134
- - Number of active markets: {market_competition}
135
- - High-value crops: {', '.join(market_summary['high_value_crops'][:5])}
136
- - Price stability data available for {len(market_summary['price_stability'])} crops
137
- - Monthly price trends tracked across {len(market_summary['monthly_trends'])} entries
138
-
139
- Based on this comprehensive data, provide:
140
-
141
- 1. Immediate Market Opportunities (Next 2-4 weeks):
142
- - Which crops currently show the best profit potential?
143
- - Which markets are offering the best prices?
144
- - Any immediate selling or holding recommendations?
145
-
146
- 2. Strategic Planning (Next 3-6 months):
147
- - Which crops show consistent high returns?
148
- - What are the optimal planting times based on price patterns?
149
- - Which crop combinations could maximize profit throughout the year?
150
-
151
- 3. Risk Management:
152
- - Which crops have shown the most stable prices?
153
- - How can farmers diversify their crops to minimize risk?
154
- - What are the warning signs to watch for in the market?
155
-
156
- 4. Market Engagement Strategy:
157
- - Which markets consistently offer better prices?
158
- - What quality grades are fetching premium prices?
159
- - How can farmers negotiate better based on current market dynamics?
160
-
161
- 5. Storage and Timing Recommendations:
162
- - Which crops are worth storing for better prices?
163
- - What are the best times to sell each major crop?
164
- - How can farmers use price trends to time their sales?
165
-
166
- Provide practical, actionable advice that farmers can implement immediately. Include specific numbers and percentages where relevant.
167
- Break the response into clear sections and keep it concise but informative.
168
  """
169
- api_url = "https://api-inference.huggingface.co/models/meta-llama/Llama-3.2-1B-Instruct/v1/chat/completions"
170
- headers = {"Authorization": f"Bearer {os.getenv('HUGGINGFACE_API_KEY')}"}
 
 
171
  payload = {
172
- "inputs": prompt
 
 
 
 
 
 
 
 
 
 
173
  }
174
 
175
- response = requests.post(api_url,headers=headers, json=payload)
 
 
 
 
 
 
176
  if response.status_code == 200:
177
  response_data = response.json()
178
- if (response_data and
179
- 'choices' in response_data and
180
- len(response_data['choices']) > 0 and
181
- 'message' in response_data['choices'][0] and
182
- 'content' in response_data['choices'][0]['message']):
183
-
184
- insights = response_data['choices'][0]['message']['content']
185
- formatted_insights = format_ai_insights(insights)
186
- return formatted_insights
187
-
188
- return "AI insights temporarily unavailable"
189
-
190
  except Exception as e:
191
  print(f"Error generating insights: {str(e)}")
192
- return f"Could not generate insights: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
- def generate_plots(df, lang='en'):
195
- """Generate all plots with language support"""
196
  if df.empty:
197
  return {}, "No data available"
198
 
199
- # Convert price columns to numeric
200
  price_cols = ['min_price', 'max_price', 'modal_price']
201
  for col in price_cols:
202
  df[col] = pd.to_numeric(df[col], errors='coerce')
203
 
204
- # Color scheme
205
  colors = ["#4CAF50", "#8BC34A", "#CDDC39", "#FFC107", "#FF5722"]
206
 
207
- # 1. Bar Chart
208
  df_bar = df.groupby('commodity')['modal_price'].mean().reset_index()
209
  fig_bar = px.bar(df_bar,
210
  x='commodity',
211
  y='modal_price',
212
- title=translate_to_marathi("Average Price by Commodity") if lang == 'mr' else "Average Price by Commodity",
213
  color_discrete_sequence=colors)
214
 
215
- # 2. Line Chart (if commodity selected)
216
  fig_line = None
217
  if 'commodity' in df.columns and len(df['commodity'].unique()) == 1:
218
  df['arrival_date'] = pd.to_datetime(df['arrival_date'])
@@ -220,18 +338,16 @@ def generate_plots(df, lang='en'):
220
  fig_line = px.line(df_line,
221
  x='arrival_date',
222
  y='modal_price',
223
- title=translate_to_marathi("Price Trend") if lang == 'mr' else "Price Trend",
224
  color_discrete_sequence=colors)
225
 
226
- # 3. Box Plot
227
  fig_box = px.box(df,
228
  x='commodity',
229
  y='modal_price',
230
- title=translate_to_marathi("Price Distribution") if lang == 'mr' else "Price Distribution",
231
  color='commodity',
232
  color_discrete_sequence=colors)
233
 
234
- # Convert to HTML
235
  plots = {
236
  'bar': pio.to_html(fig_bar, full_html=False),
237
  'box': pio.to_html(fig_box, full_html=False)
@@ -243,27 +359,30 @@ def generate_plots(df, lang='en'):
243
 
244
  @app.route('/')
245
  def index():
246
- """Render main page"""
247
- initial_data = fetch_market_data()
248
- states = sorted(initial_data['state'].dropna().unique())
 
 
 
 
249
  return render_template('index.html',
250
- states=states,
251
- today=datetime.today().strftime('%Y-%m-%d'))
252
 
253
  @app.route('/filter_data', methods=['POST'])
254
  def filter_data():
255
- """Handle data filtering, chart generation, and table generation"""
256
  state = request.form.get('state')
257
  district = request.form.get('district')
258
  market = request.form.get('market')
259
  commodity = request.form.get('commodity')
260
- lang = request.form.get('language', 'en')
261
 
262
  df = fetch_market_data(state, district, market, commodity)
263
- plots = generate_plots(df, lang)
264
- insights = get_ai_insights(df, state, district) if state and district and not df.empty else ""
 
265
 
266
- # Generate market data table HTML
267
  market_table_html = """
268
  <div class="table-responsive">
269
  <table class="table table-striped table-bordered">
@@ -301,7 +420,6 @@ def filter_data():
301
  """
302
  market_table_html += "</tbody></table></div>"
303
 
304
- # Generate top 5 cheapest crops table
305
  cheapest_crops = df.sort_values('modal_price', ascending=True).head(5)
306
  cheapest_table_html = """
307
  <div class="table-responsive">
@@ -326,7 +444,6 @@ def filter_data():
326
  """
327
  cheapest_table_html += "</tbody></table></div>"
328
 
329
- # Generate top 5 costliest crops table
330
  costliest_crops = df.sort_values('modal_price', ascending=False).head(5)
331
  costliest_table_html = """
332
  <div class="table-responsive">
@@ -351,7 +468,6 @@ def filter_data():
351
  """
352
  costliest_table_html += "</tbody></table></div>"
353
 
354
- # Calculate market statistics
355
  market_stats = {
356
  'total_commodities': len(df['commodity'].unique()),
357
  'avg_modal_price': f"₹{df['modal_price'].mean():.2f}",
@@ -362,7 +478,6 @@ def filter_data():
362
  response = {
363
  'plots': plots,
364
  'insights': insights,
365
- 'translations': MARATHI_TRANSLATIONS if lang == 'mr' else {},
366
  'success': not df.empty,
367
  'hasStateDistrict': bool(state and district),
368
  'market_html': market_table_html,
@@ -373,121 +488,8 @@ def filter_data():
373
 
374
  return jsonify(response)
375
 
376
- def format_ai_insights(insights_data, lang='en'):
377
- """Format AI insights into structured HTML with language support"""
378
- # Translation dictionary for section headers and labels
379
- translations = {
380
- 'AI Market Insights': 'एआय बाजार विश्लेषण',
381
- 'Immediate Market Opportunities': 'तात्काळ बाजार संधी',
382
- 'Best Profit Potential': 'सर्वोत्तम नफा क्षमता',
383
- 'Current Market Status': 'सध्याची बाजार स्थिती',
384
- 'Strategic Planning': 'धोरणात्मक नियोजन',
385
- 'High Return Crops': 'उच्च परतावा पिके',
386
- 'Recommended Crop Combinations': 'शिफारस केलेली पीक संयोजने',
387
- 'Risk Management & Market Strategy': 'जोखीम व्यवस्थापन आणि बाजार धोरण',
388
- 'Recommended Actions': 'शिफारस केलेल्या कृती',
389
- 'increase': 'वाढ',
390
- 'per kg': 'प्रति किलो',
391
- 'Most stable prices': 'सर्वात स्थिर किंमती',
392
- 'Best storage life': 'सर्वोत्तम साठवण कालावधी',
393
- 'Peak selling time': 'उच्चतम विक्री काळ',
394
- 'Plant mix of': 'पिकांचे मिश्रण लावा',
395
- 'Focus on': 'लक्ष केंद्रित करा',
396
- 'Store': 'साठवण करा',
397
- 'Aim for': 'लक्ष्य ठेवा',
398
- 'months': 'महिने'
399
- }
400
-
401
- def translate_text(text):
402
- """Translate text based on language selection"""
403
- if lang == 'mr':
404
- # Try to find direct translation from dictionary
405
- for eng, mar in translations.items():
406
- text = text.replace(eng, mar)
407
- return text
408
- return text
409
-
410
- def format_price(price_text):
411
- """Format price with proper currency symbol and translation"""
412
- if lang == 'mr':
413
- return price_text.replace('₹', '₹').replace('per kg', 'प्रति किलो')
414
- return price_text
415
-
416
- """Format AI insights into structured HTML"""
417
- html = f"""
418
- <div class="insights-header">
419
- <h3 class="en">AI Market Insights</h3>
420
- <h3 class="mr" style="display:none;">एआय बाजार विश्लेषण</h3>
421
- </div>
422
-
423
- <div class="insight-section">
424
- <h4>Immediate Market Opportunities</h4>
425
- <div class="insight-card">
426
- <h5>Best Profit Potential</h5>
427
- <ul class="insight-list">
428
- <li>Beetroot and Bitter gourd showing <span class="percentage-up">15% increase</span> from base year</li>
429
- <li>Bottle gourd premium quality fetching <span class="price-highlight">₹150 per kg</span></li>
430
- </ul>
431
- </div>
432
-
433
- <div class="insight-card">
434
- <h5>Current Market Status</h5>
435
- <ul class="insight-list">
436
- <li>Brinjal in high demand with stable price of <span class="price-highlight">₹80 per kg</span></li>
437
- <li>Premium quality bottle gourd commanding <span class="price-highlight">₹200 per kg</span></li>
438
- </ul>
439
- </div>
440
- </div>
441
-
442
- <div class="insight-section">
443
- <h4>Strategic Planning</h4>
444
- <div class="insight-card">
445
- <h5>High Return Crops</h5>
446
- <ul class="insight-list">
447
- <li>Cauliflower showing <span class="percentage-up">20% increase</span> from base year</li>
448
- <li>Best planting time: Spring season for cauliflower and bottle gourd</li>
449
- </ul>
450
- </div>
451
-
452
- <div class="insight-card">
453
- <h5>Recommended Crop Combinations</h5>
454
- <ul class="insight-list">
455
- <li>Brinjal + Bottle gourd + Cauliflower (similar demand patterns)</li>
456
- </ul>
457
- </div>
458
- </div>
459
-
460
- <div class="insight-section">
461
- <h4>Risk Management & Market Strategy</h4>
462
- <div class="insight-card">
463
- <ul class="insight-list">
464
- <li>Most stable prices: Brinjal, Bottle gourd, Cauliflower</li>
465
- <li>Best storage life: 6-9 months for Cauliflower, Brinjal, and Bottle gourd</li>
466
- <li>Peak selling time for Cauliflower: March-April</li>
467
- </ul>
468
- </div>
469
- </div>
470
-
471
- <div class="action-box">
472
- <h5>Recommended Actions</h5>
473
- <ul class="action-list">
474
- <li>Plant mix of beetroot, bitter gourd, bottle gourd, brinjal, and cauliflower</li>
475
- <li>Focus on stable price markets for cauliflower and bottle gourd</li>
476
- <li>Store cauliflower for March-April peak prices</li>
477
- <li>Aim for premium quality grades to maximize profits</li>
478
- </ul>
479
- </div>
480
- """
481
- if lang == 'mr':
482
- html = translate_text(html)
483
- # print(html
484
- return html
485
-
486
- return html
487
-
488
  @app.route('/get_districts', methods=['POST'])
489
  def get_districts():
490
- """Get districts for selected state"""
491
  state = request.form.get('state')
492
  df = fetch_market_data(state=state)
493
  districts = sorted(df['district'].dropna().unique())
@@ -495,7 +497,6 @@ def get_districts():
495
 
496
  @app.route('/get_markets', methods=['POST'])
497
  def get_markets():
498
- """Get markets for selected district"""
499
  district = request.form.get('district')
500
  df = fetch_market_data(district=district)
501
  markets = sorted(df['market'].dropna().unique())
@@ -503,9 +504,11 @@ def get_markets():
503
 
504
  @app.route('/get_commodities', methods=['POST'])
505
  def get_commodities():
506
- """Get commodities for selected market"""
507
  market = request.form.get('market')
508
  df = fetch_market_data(market=market)
509
  commodities = sorted(df['commodity'].dropna().unique())
510
  return jsonify(commodities)
511
 
 
 
 
 
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
 
12
+ dotenv.load_dotenv()
 
 
 
13
 
14
+ app = Flask(__name__)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  def fetch_market_data(state=None, district=None, market=None, commodity=None):
17
+ """Fetch data from the agricultural market API.
18
+ If the API fails or returns empty data, fallback to the CSV file.
19
+ Filters (state, district, market, commodity) are applied manually on CSV data.
20
+ """
21
+ api_key = "579b464db66ec23bdd000001189bbb99e979428764bdbe8fdd44ebb7"
22
+ base_url = "https://api.data.gov.in/resource/9ef84268-d588-465a-a308-a864a43d007"
23
 
24
  params = {
25
+ "api-key": api_key,
26
  "format": "json",
27
+ "limit": 1000,
28
  }
29
 
 
30
  if state:
31
  params["filters[state]"] = state
32
  if district:
 
42
  data = response.json()
43
  records = data.get("records", [])
44
  df = pd.DataFrame(records)
 
45
  else:
46
  print(f"API Error: {response.status_code}")
47
+ raise Exception(f"API Error: {response.status_code}")
48
  except Exception as e:
49
+ print(f"Error fetching data from API: {str(e)}. Falling back to CSV file.")
50
+ df = pd.read_csv("final_price_data.csv")
51
+ if 'min_price' not in df.columns:
52
+ rename_mapping = {
53
+ 'State': 'state',
54
+ 'District': 'district',
55
+ 'Market': 'market',
56
+ 'Commodity': 'commodity',
57
+ 'Variety': 'variety',
58
+ 'Grade': 'grade',
59
+ 'Arrival_Date': 'arrival_date',
60
+ 'Min_x0020_Price': 'min_price',
61
+ 'Max_x0020_Price': 'max_price',
62
+ 'Modal_x0020_Price': 'modal_price'
63
+ }
64
+ df.rename(columns=rename_mapping, inplace=True)
65
+
66
+ if df.empty:
67
+ print("API returned empty data. Falling back to CSV file.")
68
+ df = pd.read_csv("final_price_data.csv")
69
+ if 'min_price' not in df.columns:
70
+ rename_mapping = {
71
+ 'State': 'state',
72
+ 'District': 'district',
73
+ 'Market': 'market',
74
+ 'Commodity': 'commodity',
75
+ 'Variety': 'variety',
76
+ 'Grade': 'grade',
77
+ 'Arrival_Date': 'arrival_date',
78
+ 'Min_x0020_Price': 'min_price',
79
+ 'Max_x0020_Price': 'max_price',
80
+ 'Modal_x0020_Price': 'modal_price'
81
+ }
82
+ df.rename(columns=rename_mapping, inplace=True)
83
+
84
+ if state:
85
+ df = df[df['state'] == state]
86
+ if district:
87
+ df = df[df['district'] == district]
88
+ if market:
89
+ df = df[df['market'] == market]
90
+ if commodity:
91
+ df = df[df['commodity'] == commodity]
92
+
93
+ return df
94
 
95
+ def get_ai_insights(market_data, state, district, market=None, commodity=None, language="English"):
96
+ """Get enhanced insights from Gemini API with focus on profitable suggestions for farmers.
97
+ Supports multiple languages through the prompt.
98
+ Returns dynamic insights only. If something goes wrong, returns an empty string.
99
+ """
100
  if not state or not district or market_data.empty:
101
  return ""
102
+
103
  try:
104
+ # Filter data based on provided parameters
105
  district_data = market_data[market_data['district'] == district]
106
+ if district_data.empty:
107
+ return ""
108
 
109
+ # Apply market filter if provided
110
+ if market and not market_data[market_data['market'] == market].empty:
111
+ market_specific = True
112
+ district_data = district_data[district_data['market'] == market]
113
+ else:
114
+ market_specific = False
115
+
116
+ # Apply commodity filter if provided
117
+ if commodity and not market_data[market_data['commodity'] == commodity].empty:
118
+ commodity_specific = True
119
+ district_data = district_data[district_data['commodity'] == commodity]
120
+ else:
121
+ commodity_specific = False
122
+
123
+ # Calculate price trends
124
  price_trends = district_data.groupby('commodity').agg({
125
  'modal_price': ['mean', 'min', 'max', 'std']
126
  }).round(2)
127
 
128
+ # Using environment variable for Gemini API key
129
+ api_key = os.environ.get('GEMINI_API_KEY')
130
+ if not api_key:
131
+ print("Warning: Gemini API key not set")
132
+ return ""
133
+
134
  price_trends['price_stability'] = (price_trends['modal_price']['std'] /
135
  price_trends['modal_price']['mean']).round(2)
136
 
 
 
 
 
 
137
  district_data['arrival_date'] = pd.to_datetime(district_data['arrival_date'])
138
  district_data['month'] = district_data['arrival_date'].dt.month
139
  monthly_trends = district_data.groupby(['commodity', 'month'])['modal_price'].mean().round(2)
140
 
 
141
  market_competition = len(district_data['market'].unique())
142
+ top_commodities = district_data.groupby('commodity')['modal_price'].mean().nlargest(5).index.tolist()
143
 
144
+ # Get min and max prices for key commodities
145
+ price_range_info = {}
146
+ for commodity in top_commodities[:3]:
147
+ comm_data = district_data[district_data['commodity'] == commodity]
148
+ if not comm_data.empty:
149
+ price_range_info[commodity] = {
150
+ 'min': comm_data['modal_price'].min(),
151
+ 'max': comm_data['modal_price'].max(),
152
+ 'avg': comm_data['modal_price'].mean()
153
+ }
154
+
155
+ # Calculate market-specific metrics if market is selected
156
+ market_details = ""
157
+ if market_specific:
158
+ market_details = f"""
159
+ Market-specific information for {market}:
160
+ - Number of commodities: {len(district_data['commodity'].unique())}
161
+ - Most expensive commodity: {district_data.groupby('commodity')['modal_price'].mean().idxmax()}
162
+ - Cheapest commodity: {district_data.groupby('commodity')['modal_price'].mean().idxmin()}
163
+ """
164
+
165
+ # Commodity-specific details if commodity is selected
166
+ commodity_details = ""
167
+ if commodity_specific:
168
+ commodity_data = district_data[district_data['commodity'] == commodity]
169
+ best_market = commodity_data.loc[commodity_data['modal_price'].idxmin()]['market']
170
+ worst_market = commodity_data.loc[commodity_data['modal_price'].idxmax()]['market']
171
+
172
+ commodity_details = f"""
173
+ Commodity-specific information for {commodity}:
174
+ - Best market to buy (lowest price): {best_market}
175
+ - Highest priced market: {worst_market}
176
+ - Price variance across markets: {commodity_data['modal_price'].std().round(2)}
177
+ """
178
+
179
+ # Improved prompt for better structured output with language support
180
  prompt = f"""
181
+ Analyze the following agricultural market data for {district}, {state} and provide insights in {language} language.
182
+
183
+ Market data:
184
+ - Active markets: {market_competition}
185
+ - Top crops: {', '.join(top_commodities[:5])}
186
+ - Data from {len(price_trends.index)} crops and {len(monthly_trends)} monthly entries.
187
+
188
+ Price information:
189
+ {json.dumps(price_range_info, indent=2)}
190
+
191
+ {market_details}
192
+ {commodity_details}
193
+
194
+ Analyze this data and provide insights about crop market trends and profitability.
195
+ Include specific numbers from the data about prices.
196
+
197
+ Provide structured insights with clear sections. Use this exact format with bullet points:
198
+
199
+ Crop Profitability Analysis:
200
+ * [First insight about profitable crops with specific prices mentioned]
201
+ * [Second insight]
202
+
203
+ Market Price Analysis:
204
+ * [First insight about markets with specific price ranges]
205
+ * [Second insight]
206
+
207
+ Recommendations for Farmers:
208
+ * [Action item 1]
209
+ * [Action item 2]
 
 
 
 
 
 
 
 
210
  """
211
+
212
+ api_url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent"
213
+ headers = {"Content-Type": "application/json"}
214
+
215
  payload = {
216
+ "contents": [
217
+ {
218
+ "parts": [
219
+ {"text": prompt}
220
+ ]
221
+ }
222
+ ],
223
+ "generationConfig": {
224
+ "temperature": 0.4,
225
+ "maxOutputTokens": 1024
226
+ }
227
  }
228
 
229
+ response = requests.post(
230
+ f"{api_url}?key={api_key}",
231
+ headers=headers,
232
+ json=payload,
233
+ timeout=20
234
+ )
235
+
236
  if response.status_code == 200:
237
  response_data = response.json()
238
+ if 'candidates' in response_data and len(response_data['candidates']) > 0:
239
+ content = response_data['candidates'][0]['content']
240
+ if 'parts' in content and len(content['parts']) > 0:
241
+ insights = content['parts'][0]['text']
242
+ return format_ai_insights(insights)
243
+ print(f"API Response issue: {response.text[:100]}")
244
+ else:
245
+ print(f"Gemini API Error: {response.status_code} - {response.text[:100]}")
246
+
247
+ return ""
248
+
 
249
  except Exception as e:
250
  print(f"Error generating insights: {str(e)}")
251
+ return ""
252
+
253
+ def format_ai_insights(insights_data):
254
+ """Format AI insights into structured HTML.
255
+ Returns an empty string if no valid insights are provided.
256
+ """
257
+ if not insights_data or not insights_data.strip():
258
+ return ""
259
+
260
+ # Process the insights text - each bullet point becomes a formatted item
261
+ formatted_content = ""
262
+
263
+ # Split by bullet points
264
+ bullet_points = insights_data.split('*')
265
+
266
+ # Filter out empty items and process each bullet point
267
+ bullet_points = [point.strip() for point in bullet_points if point.strip()]
268
+
269
+ # Check if any section headers exist in the content
270
+ sections = {}
271
+ current_section = "Recommendations"
272
+
273
+ for point in bullet_points:
274
+ if ":" in point and len(point.split(":")[0]) < 30: # Likely a section header
275
+ current_section = point.split(":")[0].strip()
276
+ # Start a new section
277
+ if current_section not in sections:
278
+ sections[current_section] = []
279
+ else:
280
+ # Add to current section
281
+ if current_section not in sections:
282
+ sections[current_section] = []
283
+ sections[current_section].append(point)
284
+
285
+ # Now build the HTML with proper sections
286
+ for section, points in sections.items():
287
+ formatted_content += f'<div class="insight-card"><h5>{section}</h5><ul class="insight-list">'
288
+ for point in points:
289
+ # Highlight prices with special styling
290
+ if "₹" in point:
291
+ # Replace price mentions with highlighted spans
292
+ parts = point.split("₹")
293
+ styled_point = parts[0]
294
+ for i in range(1, len(parts)):
295
+ # Extract the price value
296
+ price_text = parts[i].split()[0]
297
+ # Add the highlighted price and the rest of the text
298
+ styled_point += f'<span class="price-highlight">₹{price_text}</span>' + parts[i][len(price_text):]
299
+ formatted_content += f'<li>{styled_point}</li>'
300
+ else:
301
+ formatted_content += f'<li>{point}</li>'
302
+ formatted_content += '</ul></div>'
303
+
304
+ # Add a wrapper for the insights
305
+ html = f"""
306
+ <div class="insights-header">
307
+ <h3>AI Market Insights</h3>
308
+ </div>
309
+ <div class="insight-section">
310
+ {formatted_content}
311
+ </div>
312
+ """
313
+
314
+ return html
315
 
316
+ def generate_plots(df):
317
+ """Generate all plots in English"""
318
  if df.empty:
319
  return {}, "No data available"
320
 
 
321
  price_cols = ['min_price', 'max_price', 'modal_price']
322
  for col in price_cols:
323
  df[col] = pd.to_numeric(df[col], errors='coerce')
324
 
 
325
  colors = ["#4CAF50", "#8BC34A", "#CDDC39", "#FFC107", "#FF5722"]
326
 
 
327
  df_bar = df.groupby('commodity')['modal_price'].mean().reset_index()
328
  fig_bar = px.bar(df_bar,
329
  x='commodity',
330
  y='modal_price',
331
+ title="Average Price by Commodity",
332
  color_discrete_sequence=colors)
333
 
 
334
  fig_line = None
335
  if 'commodity' in df.columns and len(df['commodity'].unique()) == 1:
336
  df['arrival_date'] = pd.to_datetime(df['arrival_date'])
 
338
  fig_line = px.line(df_line,
339
  x='arrival_date',
340
  y='modal_price',
341
+ title="Price Trend",
342
  color_discrete_sequence=colors)
343
 
 
344
  fig_box = px.box(df,
345
  x='commodity',
346
  y='modal_price',
347
+ title="Price Distribution",
348
  color='commodity',
349
  color_discrete_sequence=colors)
350
 
 
351
  plots = {
352
  'bar': pio.to_html(fig_bar, full_html=False),
353
  'box': pio.to_html(fig_box, full_html=False)
 
359
 
360
  @app.route('/')
361
  def index():
362
+ try:
363
+ initial_data = fetch_market_data()
364
+ states = sorted(initial_data['state'].dropna().unique()) if not initial_data.empty else []
365
+ except Exception as e:
366
+ print(f"Error fetching initial data: {str(e)}")
367
+ states = []
368
+
369
  return render_template('index.html',
370
+ states=states,
371
+ today=datetime.today().strftime('%Y-%m-%d'))
372
 
373
  @app.route('/filter_data', methods=['POST'])
374
  def filter_data():
 
375
  state = request.form.get('state')
376
  district = request.form.get('district')
377
  market = request.form.get('market')
378
  commodity = request.form.get('commodity')
379
+ language = request.form.get('language', 'English') # Default to English
380
 
381
  df = fetch_market_data(state, district, market, commodity)
382
+ plots = generate_plots(df)
383
+ # Pass market and commodity to get_ai_insights
384
+ insights = get_ai_insights(df, state, district, market, commodity, language) if state and district and not df.empty else ""
385
 
 
386
  market_table_html = """
387
  <div class="table-responsive">
388
  <table class="table table-striped table-bordered">
 
420
  """
421
  market_table_html += "</tbody></table></div>"
422
 
 
423
  cheapest_crops = df.sort_values('modal_price', ascending=True).head(5)
424
  cheapest_table_html = """
425
  <div class="table-responsive">
 
444
  """
445
  cheapest_table_html += "</tbody></table></div>"
446
 
 
447
  costliest_crops = df.sort_values('modal_price', ascending=False).head(5)
448
  costliest_table_html = """
449
  <div class="table-responsive">
 
468
  """
469
  costliest_table_html += "</tbody></table></div>"
470
 
 
471
  market_stats = {
472
  'total_commodities': len(df['commodity'].unique()),
473
  'avg_modal_price': f"₹{df['modal_price'].mean():.2f}",
 
478
  response = {
479
  'plots': plots,
480
  'insights': insights,
 
481
  'success': not df.empty,
482
  'hasStateDistrict': bool(state and district),
483
  'market_html': market_table_html,
 
488
 
489
  return jsonify(response)
490
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  @app.route('/get_districts', methods=['POST'])
492
  def get_districts():
 
493
  state = request.form.get('state')
494
  df = fetch_market_data(state=state)
495
  districts = sorted(df['district'].dropna().unique())
 
497
 
498
  @app.route('/get_markets', methods=['POST'])
499
  def get_markets():
 
500
  district = request.form.get('district')
501
  df = fetch_market_data(district=district)
502
  markets = sorted(df['market'].dropna().unique())
 
504
 
505
  @app.route('/get_commodities', methods=['POST'])
506
  def get_commodities():
 
507
  market = request.form.get('market')
508
  df = fetch_market_data(market=market)
509
  commodities = sorted(df['commodity'].dropna().unique())
510
  return jsonify(commodities)
511
 
512
+ if __name__ == '__main__':
513
+ app.run(debug=True, host='0.0.0.0', port=7860)
514
+ pio.templates.default = "plotly_white"