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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +488 -411
app.py CHANGED
@@ -1,434 +1,511 @@
1
- # app.py
2
  import os
3
- from flask import Flask, render_template, request, jsonify, redirect, url_for, flash, session
4
  import requests
5
- from werkzeug.utils import secure_filename
6
- import google.generativeai as genai
7
- import base64
8
- import json
9
- from datetime import datetime, timedelta
10
- import threading
11
- import time
12
- from gtts import gTTS # <-- New import for audio generation
13
-
14
-
15
-
16
- # Configure the Gemini API
17
- GEMINI_API_KEY = "AIzaSyBtXV2xJbrWVV57B5RWy_meKXOA59HFMeY"
18
- if not GEMINI_API_KEY:
19
- raise ValueError("Google API Key not found. Set it as GEMINI_API_KEY in the Space settings.")
20
-
21
- genai.configure(api_key=GEMINI_API_KEY)
22
-
23
- # Setup the Gemini model
24
- model = genai.GenerativeModel('gemini-1.5-flash')
25
 
26
  app = Flask(__name__)
27
- app.secret_key = os.getenv("SECRET_KEY", "your-default-secret-key-for-flash-messages")
28
-
29
- # Configure upload folder
30
- UPLOAD_FOLDER = 'static/uploads'
31
- ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
32
-
33
- if not os.path.exists(UPLOAD_FOLDER):
34
- os.makedirs(UPLOAD_FOLDER)
35
-
36
- # Configure audio folder (new)
37
- AUDIO_FOLDER = 'static/audio'
38
- if not os.path.exists(AUDIO_FOLDER):
39
- os.makedirs(AUDIO_FOLDER)
40
 
41
- app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
42
-
43
-
44
- def allowed_file(filename):
45
- return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
46
-
47
-
48
- def encode_image(image_path):
49
- with open(image_path, "rb") as image_file:
50
- return base64.b64encode(image_file.read()).decode('utf-8')
51
-
52
-
53
- def get_web_pesticide_info(disease, plant_type="Unknown"):
54
- """Fetch pesticide information from web sources for a specific disease and plant type"""
55
- query = f"site:agrowon.esakal.com {disease} in {plant_type}"
56
- url = "https://www.googleapis.com/customsearch/v1"
57
- params = {
58
- "key": os.getenv("GOOGLE_API_KEY"),
59
- "cx": os.getenv("GOOGLE_CX"),
60
- "q": query,
61
- "num": 3
62
- }
 
 
 
 
63
  try:
64
- response = requests.get(url, params=params)
65
- response.raise_for_status()
66
- data = response.json()
67
- if "items" in data and len(data["items"]) > 0:
68
- item = data["items"][0]
69
- return {
70
- "title": item.get("title", "No title available"),
71
- "link": item.get("link", "#"),
72
- "snippet": item.get("snippet", "No snippet available"),
73
- "summary": item.get("snippet", "No snippet available")
74
- }
75
- except Exception as e:
76
- print(f"Error retrieving web pesticide info: {str(e)}")
77
- return None
78
-
79
-
80
- def get_more_web_info(query):
81
- """Get more general web information based on a search query"""
82
- url = "https://www.googleapis.com/customsearch/v1"
83
  params = {
84
- "key": os.getenv("GOOGLE_API_KEY"),
85
- "cx": os.getenv("GOOGLE_CX"),
86
- "q": query,
87
- "num": 3
88
  }
89
- try:
90
- response = requests.get(url, params=params)
91
- response.raise_for_status()
92
- data = response.json()
93
- results = []
94
- if "items" in data:
95
- for item in data["items"]:
96
- results.append({
97
- "title": item.get("title", "No title available"),
98
- "link": item.get("link", "#"),
99
- "snippet": item.get("snippet", "No snippet available")
100
- })
101
- return results
102
- except Exception as e:
103
- print(f"Error retrieving additional articles: {str(e)}")
104
- return []
105
 
106
-
107
- def get_commercial_product_info(recommendation, disease_name):
108
- """Fetch commercial product information related to a pesticide recommendation.
109
- If no relevant products are found from web sources, return default products based on issue type:
110
- bacterial, fungicide (disease), or insecticide.
111
- """
112
- indiamart_query = f"site:indiamart.com pesticide '{disease_name}' '{recommendation}'"
113
- krishi_query = f"site:krishisevakendra.in/products pesticide '{disease_name}' '{recommendation}'"
114
-
115
- indiamart_results = get_more_web_info(indiamart_query)
116
- krishi_results = get_more_web_info(krishi_query)
117
-
118
- results = indiamart_results + krishi_results
119
-
120
- if not results:
121
- lower_disease = disease_name.lower()
122
- lower_recommendation = recommendation.lower()
123
-
124
- if ("bacteria" in lower_disease or "bacterial" in lower_disease or
125
- "bacteria" in lower_recommendation or "bacterial" in lower_recommendation):
126
- results = [
127
- {
128
- "title": "UPL SAAF Carbendazin Mancozeb Bactericide",
129
- "link": "https://www.amazon.in/UPL-SAAF-Carbendazinm12-Mancozeb63-Action/dp/B0DJLQRL44",
130
- "snippet": "Bactericide for controlling bacterial infections."
131
- },
132
- {
133
- "title": "Tropical Tagmycin Bactericide",
134
- "link": "https://krushidukan.bharatagri.com/en/products/tropical-tagmycin-bactericide",
135
- "snippet": "Bactericide for effective bacterial infection management."
136
- }
137
- ]
138
- elif ("fungus" in lower_disease or "fungicide" in lower_recommendation or
139
- "antibiotic" in lower_recommendation or "disease" in lower_disease):
140
- results = [
141
- {
142
- "title": "Plantomycin Bio Organic Antibiotic Effective Disease",
143
- "link": "https://www.amazon.in/Plantomycin-Bio-Organic-Antibiotic-Effective-Disease/dp/B0DRVVJKQ4",
144
- "snippet": "Bio organic antibiotic for effective control of plant diseases."
145
- },
146
- {
147
- "title": "WET-TREE Larvicide Thuringiensis Insecticide",
148
- "link": "https://www.amazon.in/WET-TREE-Larvicide-Thuringiensis-Insecticide/dp/B0D6R72KHV",
149
- "snippet": "Larvicide with thuringiensis for disease prevention."
150
- }
151
- ]
152
- elif ("insecticide" in lower_disease or "insect" in lower_disease or "pest" in lower_disease or
153
- "insecticide" in lower_recommendation or "insect" in lower_recommendation or "pest" in lower_recommendation):
154
- results = [
155
- {
156
- "title": "Syngenta Actara Insecticide",
157
- "link": "https://www.amazon.in/syngenta-Actara-Insect-Repellent-Insecticide/dp/B08W55XTHS",
158
- "snippet": "Effective systemic insecticide for pest control."
159
- },
160
- {
161
- "title": "Cyhalothrin Insecticide",
162
- "link": "https://www.amazon.in/Cyhalothrin-Control-Eradication-Mosquitoes-Crawling/dp/B01N53VH1T",
163
- "snippet": "Broad-spectrum insecticide for pest management."
164
- }
165
- ]
166
- else:
167
- results = [
168
- {
169
- "title": "Syngenta Actara Insecticide",
170
- "link": "https://www.amazon.in/syngenta-Actara-Insect-Repellent-Insecticide/dp/B08W55XTHS",
171
- "snippet": "Effective systemic insecticide for pest control."
172
- },
173
- {
174
- "title": "Cyhalothrin Insecticide",
175
- "link": "https://www.amazon.in/Cyhalothrin-Control-Eradication-Mosquitoes-Crawling/dp/B01N53VH1T",
176
- "snippet": "Broad-spectrum insecticide for pest management."
177
- }
178
- ]
179
-
180
- return results
181
-
182
-
183
- def get_relevant_feedback(plant_name):
184
- """Retrieve feedback entries relevant to the given plant name from feedback.json."""
185
- feedback_file = "feedback.json"
186
- if os.path.exists(feedback_file):
187
- try:
188
- with open(feedback_file, "r") as f:
189
- all_feedback = json.load(f)
190
- relevant = [entry.get("feedback") for entry in all_feedback if
191
- entry.get("plant_name", "").lower() == plant_name.lower()]
192
- if relevant:
193
- return " ".join(relevant[:3])
194
- except Exception as e:
195
- print(f"Error reading feedback for reinforcement: {e}")
196
- return ""
197
-
198
-
199
- def generate_audio(text, language, filename):
200
- """Generate an MP3 file from text using gTTS."""
201
  try:
202
- tts = gTTS(text=text, lang=language, slow=False)
203
- tts.save(filename)
 
 
 
 
 
 
 
204
  except Exception as e:
205
- print(f"Error generating audio: {e}")
 
206
 
207
 
208
- def analyze_plant_image(image_path, plant_name, language):
 
 
 
 
209
  try:
210
- # Load the image
211
- image_parts = [
212
- {
213
- "mime_type": "image/jpeg",
214
- "data": encode_image(image_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
215
  }
216
- ]
217
-
218
- # Load relevant feedback (reinforcement data) for this plant
219
- feedback_context = get_relevant_feedback(plant_name)
220
- feedback_instruction = f" Please consider the following user feedback from similar cases: {feedback_context}" if feedback_context else ""
221
 
222
- # Create prompt for Gemini API with language instruction and feedback reinforcement if available
223
  prompt = f"""
224
- Analyze this image of a {plant_name} plant and prioritize determining if it's healthy or has a disease or pest infestation.
225
-
226
- If a disease or pest is detected, provide the following information in JSON format:
227
- {{"results": [{{"type": "disease/pest", "name": "Name of disease or pest", "probability": "Probability as a percentage", "symptoms": "Describe the visible symptoms", "causes": "Main causes of the disease or pest", "severity": "Low/Medium/High", "spreading": "How it spreads", "treatment": "Treatment options", "prevention": "Preventive measures"}},{{}},{{}}], "is_healthy": boolean indicating if the plant appears healthy, "confidence": "Overall confidence in the analysis as a percentage"}}
228
-
229
- Only return the JSON data and nothing else. Ensure the JSON is valid and properly formatted.
230
- If the plant appears completely healthy, set is_healthy to true and include an empty results array.
231
- Additionally, provide the response in {language} language.
232
- and at end show which all data from feedback was taken into consideration and if no data was taken so no data.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  """
234
-
235
- # Send request to Gemini API
236
- response = model.generate_content([prompt] + image_parts)
237
-
238
- # Extract the JSON response
239
- response_text = response.text
240
-
241
- # Find JSON within response text if needed
242
- json_start = response_text.find('{')
243
- json_end = response_text.rfind('}') + 1
244
-
245
- if json_start >= 0 and json_end > 0:
246
- json_str = response_text[json_start:json_end]
247
- analysis_result = json.loads(json_str)
248
- else:
249
- return {
250
- "error": "Failed to parse the API response",
251
- "raw_response": response_text
252
- }
253
-
254
- # ---- Added audio generation feature ----
255
- # Create a summary text based on the analysis including Spreading, Treatment, and Prevention
256
- if analysis_result.get('is_healthy', False):
257
- summary_text = f"Your {plant_name} plant appears to be healthy. Continue with your current care practices."
258
- elif 'results' in analysis_result and analysis_result['results']:
259
- summary_text = "Detected issues: "
260
- for result in analysis_result['results']:
261
- summary_text += (f"{result.get('name', 'Unknown')}. Symptoms: {result.get('symptoms', '')}. "
262
- f"Causes: {result.get('causes', '')}. Spreading: {result.get('spreading', '')}. "
263
- f"Treatment: {result.get('treatment', '')}. Prevention: {result.get('prevention', '')}. ")
264
- else:
265
- summary_text = "Analysis inconclusive."
266
-
267
- # Map language name to gTTS language code
268
- lang_mapping = {"English": "en", "Hindi": "hi", "Bengali": "bn", "Telugu": "te", "Marathi": "mr", "Tamil": "ta",
269
- "Gujarati": "gu", "Urdu": "ur", "Kannada": "kn", "Odia": "or", "Malayalam": "ml"}
270
- gtts_lang = lang_mapping.get(language, 'en')
271
-
272
- # Generate unique audio filename
273
- timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
274
- audio_filename = f"audio_result.mp3"
275
- audio_path = os.path.join(AUDIO_FOLDER, audio_filename)
276
- generate_audio(summary_text, gtts_lang, audio_path)
277
-
278
- # Wait until the audio file is created and has nonzero size (up to 5 seconds)
279
- wait_time = 0
280
- while (not os.path.exists(audio_path) or os.path.getsize(audio_path) == 0) and wait_time < 5:
281
- time.sleep(0.5)
282
- wait_time += 0.5
283
-
284
- # Add relative audio file path for template rendering
285
- analysis_result['audio_file'] = os.path.join('audio', audio_filename)
286
- # -----------------------------------------
287
-
288
- return analysis_result
289
-
290
- except Exception as e:
291
- return {
292
- "error": str(e),
293
- "is_healthy": None,
294
- "results": []
295
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
 
298
- def cleanup_old_files(directory, max_age_hours=1): # Reduced to 1 hour for Hugging Face
299
- """Remove files older than the specified age from the directory"""
300
- while True:
301
- now = datetime.now()
302
- for filename in os.listdir(directory):
303
- if filename == '.gitkeep': # Skip the .gitkeep file
304
- continue
305
- file_path = os.path.join(directory, filename)
306
- file_age = now - datetime.fromtimestamp(os.path.getctime(file_path))
307
- if file_age > timedelta(hours=max_age_hours):
308
- try:
309
- os.remove(file_path)
310
- print(f"Removed old file: {file_path}")
311
- except Exception as e:
312
- print(f"Error removing {file_path}: {e}")
313
- time.sleep(300) # 5 minutes
314
-
315
-
316
- @app.route('/', methods=['GET'])
317
  def index():
318
- # GET request - show the upload form
319
- return render_template('index.html', show_results=False)
320
-
321
-
322
- @app.route('/feedback', methods=['POST'])
323
- def feedback():
324
- # Get feedback from form submission
325
- feedback_text = request.form.get("feedback")
326
- plant_name = request.form.get("plant_name", "Unknown")
327
- if not feedback_text:
328
- flash("Please provide your feedback before submitting.")
329
- return redirect(url_for('index'))
330
- feedback_data = {
331
- "plant_name": plant_name,
332
- "feedback": feedback_text,
333
- "timestamp": datetime.now().isoformat()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  }
335
- feedback_file = "feedback.json"
336
- if os.path.exists(feedback_file):
337
- try:
338
- with open(feedback_file, "r") as f:
339
- existing_feedback = json.load(f)
340
- except Exception as e:
341
- print(f"Error reading feedback file: {e}")
342
- existing_feedback = []
343
- else:
344
- existing_feedback = []
345
- existing_feedback.append(feedback_data)
346
- try:
347
- with open(feedback_file, "w") as f:
348
- json.dump(existing_feedback, f, indent=4)
349
- except Exception as e:
350
- flash(f"Error saving your feedback: {str(e)}")
351
- return redirect(url_for('index'))
352
- flash("Thank you for your feedback!")
353
- return redirect(url_for('index'))
354
-
355
-
356
- @app.route('/analyze', methods=['POST'])
357
- def analyze():
358
- if 'plant_image' not in request.files:
359
- flash('No file part')
360
- return redirect(url_for('index'))
361
-
362
- file = request.files['plant_image']
363
- plant_name = request.form.get('plant_name', 'unknown')
364
- language = request.form.get('language', 'English')
365
-
366
- if file.filename == '':
367
- flash('No selected file')
368
- return redirect(url_for('index'))
369
-
370
- if file and allowed_file(file.filename):
371
- timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
372
- original_filename = secure_filename(file.filename)
373
- filename = f"{timestamp}_{original_filename}"
374
- file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
375
- file.save(file_path)
376
-
377
- try:
378
- analysis_result = analyze_plant_image(file_path, plant_name, language)
379
- if 'error' in analysis_result:
380
- flash(f"Error analyzing image: {analysis_result['error']}")
381
- if os.path.exists(file_path):
382
- os.remove(file_path)
383
- return redirect(url_for('index'))
384
- web_info = {}
385
- product_info = {}
386
- if not analysis_result.get('is_healthy', False) and 'results' in analysis_result:
387
- for result in analysis_result['results']:
388
- disease_name = result.get('name', '')
389
- if disease_name:
390
- web_info[disease_name] = get_web_pesticide_info(disease_name, plant_name)
391
- treatment = result.get('treatment', '')
392
- if treatment:
393
- product_info[disease_name] = get_commercial_product_info(treatment, disease_name)
394
- response = render_template(
395
- 'results.html',
396
- results=analysis_result,
397
- plant_name=plant_name,
398
- image_path=file_path.replace('static/', '', 1),
399
- web_info=web_info,
400
- product_info=product_info
401
- )
402
-
403
- def delete_file_after_delay(path, delay=30):
404
- time.sleep(delay)
405
- if os.path.exists(path):
406
- try:
407
- os.remove(path)
408
- print(f"Deleted analyzed file: {path}")
409
- except Exception as e:
410
- print(f"Error deleting {path}: {e}")
411
-
412
- threading.Thread(
413
- target=delete_file_after_delay,
414
- args=(file_path,),
415
- daemon=True
416
- ).start()
417
-
418
- return response
419
-
420
- except Exception as e:
421
- flash(f"An error occurred: {str(e)}")
422
- if os.path.exists(file_path):
423
- os.remove(file_path)
424
- return redirect(url_for('index'))
425
-
426
- flash('Invalid file type. Please upload an image (png, jpg, jpeg, gif).')
427
- return redirect(url_for('index'))
428
-
429
-
430
- if __name__ == '__main__':
431
- cleanup_thread = threading.Thread(target=cleanup_old_files, args=(app.config['UPLOAD_FOLDER'],), daemon=True)
432
- cleanup_thread.start()
433
- port = int(os.environ.get("PORT", 7860))
434
- app.run(host='0.0.0.0', port=port)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ 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:
63
+ params["filters[district]"] = district
64
+ if market:
65
+ params["filters[market]"] = market
66
+ if commodity:
67
+ params["filters[commodity]"] = commodity
 
 
 
 
 
 
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  try:
70
+ response = requests.get(base_url, params=params)
71
+ if response.status_code == 200:
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'])
219
+ df_line = df.sort_values('arrival_date')
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)
238
+ }
239
+ if fig_line:
240
+ plots['line'] = pio.to_html(fig_line, full_html=False)
241
+
242
+ return plots
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">
270
+ <thead>
271
+ <tr>
272
+ <th>State</th>
273
+ <th>District</th>
274
+ <th>Market</th>
275
+ <th>Commodity</th>
276
+ <th>Variety</th>
277
+ <th>Grade</th>
278
+ <th>Arrival Date</th>
279
+ <th>Min Price</th>
280
+ <th>Max Price</th>
281
+ <th>Modal Price</th>
282
+ </tr>
283
+ </thead>
284
+ <tbody>
285
+ """
286
+
287
+ for _, row in df.iterrows():
288
+ market_table_html += f"""
289
+ <tr>
290
+ <td>{row['state']}</td>
291
+ <td>{row['district']}</td>
292
+ <td>{row['market']}</td>
293
+ <td>{row['commodity']}</td>
294
+ <td>{row['variety']}</td>
295
+ <td>{row['grade']}</td>
296
+ <td>{row['arrival_date']}</td>
297
+ <td>₹{row['min_price']}</td>
298
+ <td>₹{row['max_price']}</td>
299
+ <td>₹{row['modal_price']}</td>
300
+ </tr>
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">
308
+ <table class="table table-sm table-bordered">
309
+ <thead>
310
+ <tr>
311
+ <th>Commodity</th>
312
+ <th>Market</th>
313
+ <th>Modal Price</th>
314
+ </tr>
315
+ </thead>
316
+ <tbody>
317
+ """
318
+
319
+ for _, row in cheapest_crops.iterrows():
320
+ cheapest_table_html += f"""
321
+ <tr>
322
+ <td>{row['commodity']}</td>
323
+ <td>{row['market']}</td>
324
+ <td>₹{row['modal_price']}</td>
325
+ </tr>
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">
333
+ <table class="table table-sm table-bordered">
334
+ <thead>
335
+ <tr>
336
+ <th>Commodity</th>
337
+ <th>Market</th>
338
+ <th>Modal Price</th>
339
+ </tr>
340
+ </thead>
341
+ <tbody>
342
+ """
343
+
344
+ for _, row in costliest_crops.iterrows():
345
+ costliest_table_html += f"""
346
+ <tr>
347
+ <td>{row['commodity']}</td>
348
+ <td>{row['market']}</td>
349
+ <td>₹{row['modal_price']}</td>
350
+ </tr>
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}",
358
+ 'price_range': f"₹{df['modal_price'].min():.2f} - ₹{df['modal_price'].max():.2f}",
359
+ 'total_markets': len(df['market'].unique())
360
  }
361
+
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,
369
+ 'cheapest_html': cheapest_table_html,
370
+ 'costliest_html': costliest_table_html,
371
+ 'market_stats': market_stats
372
+ }
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())
494
+ return jsonify(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())
502
+ return jsonify(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
+