Chaitanya895 commited on
Commit
3aea0a4
·
verified ·
1 Parent(s): e2e2eec

Upload 31 files

Browse files
.gitattributes ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ models/market_model_corn.pkl filter=lfs diff=lfs merge=lfs -text
2
+ models/market_model_rice.pkl filter=lfs diff=lfs merge=lfs -text
3
+ models/market_model_soybean.pkl filter=lfs diff=lfs merge=lfs -text
4
+ models/market_model_wheat.pkl filter=lfs diff=lfs merge=lfs -text
5
+ models/rain_model.pkl filter=lfs diff=lfs merge=lfs -text
6
+ models/sustainable_farming.db filter=lfs diff=lfs merge=lfs -text
7
+ models/temp_model.pkl filter=lfs diff=lfs merge=lfs -text
models/ai ADDED
File without changes
models/au ADDED
File without changes
models/central_coordinator.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joblib
2
+ from Models.farmer_advisor import FarmerAdvisor
3
+ from Models.market_Researcher import MarketResearcher
4
+ from Models.weather_Analyst import WeatherAnalyst
5
+ from Models.sustainability_Expert import SustainabilityExpert
6
+ import matplotlib.pyplot as plt
7
+ from Models import weather_api
8
+ from Models.pest_disease_predictor import PestDiseasePredictor
9
+
10
+
11
+ class CentralCoordinator:
12
+ def __init__(self):
13
+ db_path = "database/sustainable_farming.db"
14
+ self.farmer_advisor = FarmerAdvisor(db_path=db_path)
15
+ self.market_researcher = MarketResearcher(db_path=db_path)
16
+ self.weather_analyst = WeatherAnalyst(db_path=db_path)
17
+ self.sustainability_expert = SustainabilityExpert(db_path=db_path)
18
+ self.pest_predictor = PestDiseasePredictor()
19
+
20
+ def generate_recommendation(self, soil_ph, soil_moisture, temperature, rainfall,
21
+ fertilizer, pesticide, crop_yield, city_name=None):
22
+ warnings = []
23
+ # If city_name is provided, fetch real-time weather
24
+ if city_name:
25
+ try:
26
+ weather = weather_api.get_current_weather(city_name)
27
+ temperature = weather['temperature']
28
+ rainfall = weather['rainfall']
29
+ except Exception as e:
30
+ warnings.append(f"Weather API error: {e}")
31
+
32
+ # 1. Recommend crop using FarmerAdvisor
33
+ crop = self.farmer_advisor.recommend(
34
+ soil_ph, soil_moisture, temperature, rainfall,
35
+ fertilizer, pesticide, crop_yield
36
+ )
37
+
38
+ # Pest/Disease prediction
39
+ pest_advice = self.pest_predictor.predict(
40
+ crop_type=crop,
41
+ soil_ph=soil_ph,
42
+ soil_moisture=soil_moisture,
43
+ temperature=temperature,
44
+ rainfall=rainfall
45
+ )
46
+
47
+ # 2. Prepare dummy input for MarketResearcher
48
+ market_features = {
49
+ 'Demand_Index': 0.5,
50
+ 'Supply_Index': 0.5,
51
+ 'Competitor_Price_per_ton': 1000.0,
52
+ 'Economic_Indicator': 0.8,
53
+ 'Weather_Impact_Score': 0.7,
54
+ 'Seasonal_Factor': 'Medium',
55
+ 'Consumer_Trend_Index': 0.6
56
+ }
57
+
58
+ # 3. Market forecast for recommended crop
59
+ market_forecast = self.market_researcher.forecast(product=crop, input_features=market_features)
60
+ market_score = market_forecast[0] / 1000 # Normalize
61
+
62
+ # 4. Weather forecast
63
+ weather_forecast = self.weather_analyst.forecast(
64
+ soil_ph=soil_ph,
65
+ soil_moisture=soil_moisture,
66
+ fertilizer=fertilizer,
67
+ pesticide=pesticide
68
+ )
69
+ predicted_temp = weather_forecast['temperature'][0]
70
+ predicted_rain = weather_forecast['rainfall'][0]
71
+
72
+ # 5. Weather suitability score
73
+ weather_score = 1 - abs(predicted_temp - temperature) / 50 - abs(predicted_rain - rainfall) / 100
74
+ weather_score = max(0, round(weather_score, 2))
75
+
76
+ # 6. Get sustainability scores
77
+ scores = self.sustainability_expert.evaluate(
78
+ [crop],
79
+ soil_ph=soil_ph,
80
+ soil_moisture=soil_moisture,
81
+ rainfall=rainfall,
82
+ fertilizer=fertilizer,
83
+ pesticide=pesticide,
84
+ crop_yield=crop_yield
85
+ )
86
+
87
+ # Get the scores dictionary from the tuple returned by evaluate
88
+ sustainability_scores = scores[1] # Dictionary with all scores
89
+
90
+ # 7. Final weighted score
91
+ final_score = (
92
+ 0.25 * market_score +
93
+ 0.20 * weather_score +
94
+ 0.20 * sustainability_scores['sustainability'] +
95
+ 0.15 * sustainability_scores['carbon'] +
96
+ 0.10 * sustainability_scores['water'] +
97
+ 0.10 * sustainability_scores['erosion']
98
+ )
99
+
100
+ # 8. Enhanced Weather Warnings
101
+ if city_name:
102
+ # General weather hazards
103
+ if temperature > 40:
104
+ warnings.append("Warning: High temperature detected! Crop stress and yield loss possible.")
105
+ if rainfall > 50:
106
+ warnings.append("Warning: Heavy rainfall detected! Risk of flooding and waterlogging.")
107
+ if temperature < 5:
108
+ warnings.append("Warning: Low temperature detected! Frost risk and stunted growth possible.")
109
+ if rainfall < 5:
110
+ warnings.append("Warning: Very low rainfall detected! Drought risk and irrigation needed.")
111
+ # Crop-specific suitability (example ranges, can be refined per crop)
112
+ crop_temp_ranges = {
113
+ 'Wheat': (10, 25),
114
+ 'Rice': (20, 35),
115
+ 'Corn': (15, 35),
116
+ 'Soybeans': (15, 30),
117
+ 'Cotton': (20, 35)
118
+ }
119
+ crop_rain_ranges = {
120
+ 'Wheat': (30, 90),
121
+ 'Rice': (100, 200),
122
+ 'Corn': (50, 120),
123
+ 'Soybeans': (50, 100),
124
+ 'Cotton': (50, 100)
125
+ }
126
+ temp_range = crop_temp_ranges.get(crop)
127
+ rain_range = crop_rain_ranges.get(crop)
128
+ if temp_range:
129
+ if not (temp_range[0] <= temperature <= temp_range[1]):
130
+ warnings.append(f"Warning: Real-time temperature ({temperature}°C) is outside the optimal range for {crop} ({temp_range[0]}–{temp_range[1]}°C).")
131
+ if rain_range:
132
+ if not (rain_range[0] <= rainfall <= rain_range[1]):
133
+ warnings.append(f"Warning: Real-time rainfall ({rainfall} mm) is outside the optimal range for {crop} ({rain_range[0]}–{rain_range[1]} mm).")
134
+ # Severe weather
135
+ if temperature > 45:
136
+ warnings.append("Severe Alert: Extreme heat! Crop failure likely.")
137
+ if temperature < 0:
138
+ warnings.append("Severe Alert: Freezing conditions! Crop loss likely.")
139
+ if rainfall > 100:
140
+ warnings.append("Severe Alert: Torrential rain! Flooding and root rot risk.")
141
+
142
+ result = {
143
+ 'Recommended Crop': crop,
144
+ 'Market Score': round(market_score, 2),
145
+ 'Weather Suitability Score': weather_score,
146
+ 'Sustainability Score': round(sustainability_scores['sustainability'], 2),
147
+ 'Carbon Footprint Score': round(sustainability_scores['carbon'], 2),
148
+ 'Water Score': round(sustainability_scores['water'], 2),
149
+ 'Erosion Score': round(sustainability_scores['erosion'], 2),
150
+ 'Final Score': round(final_score, 2),
151
+ 'Predicted Temperature': round(predicted_temp, 2),
152
+ 'Predicted Rainfall': round(predicted_rain, 2),
153
+ 'Real-Time Temperature': round(temperature, 2) if city_name else None,
154
+ 'Real-Time Rainfall': round(rainfall, 2) if city_name else None,
155
+ 'Warnings': warnings,
156
+ 'Pest/Disease Advice': pest_advice
157
+ }
158
+ return result
159
+
160
+ @staticmethod
161
+ def plot_scores(result):
162
+ # Extract relevant numeric scores
163
+ labels = []
164
+ values = []
165
+ for key in ['Market Score', 'Weather Suitability Score', 'Sustainability Score',
166
+ 'Carbon Footprint Score', 'Water Score', 'Erosion Score', 'Final Score']:
167
+ val = result.get(key)
168
+ if val is not None:
169
+ labels.append(key)
170
+ values.append(val)
171
+
172
+ # Plot
173
+ plt.figure(figsize=(10, 8))
174
+ colors = ['#4caf50', '#2196f3', '#ff9800', '#607d8b',
175
+ '#00bcd4', '#795548', '#e91e63']
176
+
177
+ # Create pie chart
178
+ plt.pie(values, labels=labels, colors=colors, autopct='%1.1f%%',
179
+ startangle=90, shadow=True)
180
+ plt.title('Crop Recommendation Score Distribution')
181
+ plt.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle
182
+ plt.tight_layout()
183
+ plt.show()
184
+
185
+
186
+ # Run it directly (for testing)
187
+ if __name__ == "__main__":
188
+ coordinator = CentralCoordinator()
189
+ result = coordinator.generate_recommendation(
190
+ soil_ph=6.5,
191
+ soil_moisture=35,
192
+ temperature=27,
193
+ rainfall=60,
194
+ fertilizer=20,
195
+ pesticide=5,
196
+ crop_yield=3.5,
197
+ city_name="New York"
198
+ )
199
+
200
+ print("\n --- Final Recommendation ---")
201
+ for k, v in result.items():
202
+ print(f"{k}: {v}")
203
+
204
+ CentralCoordinator.plot_scores(result)
models/enhanced_pest_predictor.py ADDED
@@ -0,0 +1,419 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from typing import Dict, List, Optional, Tuple
4
+ from datetime import datetime, timedelta
5
+ import pandas as pd
6
+ from dotenv import load_dotenv
7
+ from transformers import AutoTokenizer, AutoModelForCausalLM
8
+ import torch
9
+ import json
10
+
11
+ # Load environment variables
12
+ load_dotenv()
13
+
14
+ # Set up logging
15
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
16
+ logger = logging.getLogger(__name__)
17
+
18
+ class EnhancedPestDiseasePredictor:
19
+ """
20
+ Enhanced pest and disease predictor using Llama 2 for intelligent analysis
21
+ """
22
+
23
+ def __init__(self):
24
+ # Initialize Llama 2 model for pest/disease analysis
25
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
26
+ self.model_name = "meta-llama/Llama-2-7b-chat-hf"
27
+
28
+ try:
29
+ self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
30
+ self.model = AutoModelForCausalLM.from_pretrained(
31
+ self.model_name,
32
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
33
+ device_map="auto" if self.device == "cuda" else None
34
+ )
35
+ logger.info(f"Loaded Llama 2 model for pest prediction on {self.device}")
36
+ except Exception as e:
37
+ logger.warning(f"Could not load Llama 2 model: {e}. Using rule-based fallback.")
38
+ self.model = None
39
+ self.tokenizer = None
40
+
41
+ # Pest and disease database
42
+ self.pest_database = self._load_pest_database()
43
+ self.disease_database = self._load_disease_database()
44
+
45
+ def _load_pest_database(self) -> Dict:
46
+ """Load comprehensive pest database"""
47
+ return {
48
+ 'wheat': {
49
+ 'aphids': {
50
+ 'conditions': {'temp_range': (15, 25), 'humidity_range': (40, 80), 'rainfall_range': (20, 100)},
51
+ 'symptoms': 'Yellowing leaves, sticky honeydew, stunted growth',
52
+ 'treatment': 'Neem oil spray, beneficial insects, resistant varieties',
53
+ 'risk_factors': ['high_nitrogen', 'dense_planting', 'poor_air_circulation']
54
+ },
55
+ 'rust': {
56
+ 'conditions': {'temp_range': (15, 25), 'humidity_range': (70, 95), 'rainfall_range': (50, 150)},
57
+ 'symptoms': 'Orange or brown pustules on leaves and stems',
58
+ 'treatment': 'Fungicide application, crop rotation, resistant varieties',
59
+ 'risk_factors': ['high_humidity', 'warm_temperatures', 'previous_infestation']
60
+ },
61
+ 'armyworm': {
62
+ 'conditions': {'temp_range': (20, 30), 'humidity_range': (50, 90), 'rainfall_range': (30, 120)},
63
+ 'symptoms': 'Chewed leaves, defoliation, larvae visible',
64
+ 'treatment': 'Bacillus thuringiensis, pheromone traps, natural predators',
65
+ 'risk_factors': ['warm_weather', 'high_humidity', 'dense_vegetation']
66
+ }
67
+ },
68
+ 'rice': {
69
+ 'brown_planthopper': {
70
+ 'conditions': {'temp_range': (25, 35), 'humidity_range': (70, 95), 'rainfall_range': (100, 300)},
71
+ 'symptoms': 'Yellowing and wilting, honeydew secretion, sooty mold',
72
+ 'treatment': 'Systemic insecticides, resistant varieties, proper water management',
73
+ 'risk_factors': ['high_nitrogen', 'excessive_irrigation', 'dense_planting']
74
+ },
75
+ 'bacterial_leaf_blight': {
76
+ 'conditions': {'temp_range': (25, 35), 'humidity_range': (80, 95), 'rainfall_range': (150, 400)},
77
+ 'symptoms': 'Yellow stripes on leaves, wilting, plant death',
78
+ 'treatment': 'Copper-based fungicides, resistant varieties, proper drainage',
79
+ 'risk_factors': ['high_humidity', 'warm_temperatures', 'poor_drainage']
80
+ },
81
+ 'rice_blast': {
82
+ 'conditions': {'temp_range': (20, 30), 'humidity_range': (85, 95), 'rainfall_range': (100, 300)},
83
+ 'symptoms': 'Diamond-shaped lesions on leaves, neck rot, yield loss',
84
+ 'treatment': 'Fungicide application, resistant varieties, proper spacing',
85
+ 'risk_factors': ['high_humidity', 'cool_temperatures', 'excessive_nitrogen']
86
+ }
87
+ },
88
+ 'corn': {
89
+ 'corn_borer': {
90
+ 'conditions': {'temp_range': (20, 30), 'humidity_range': (50, 80), 'rainfall_range': (40, 120)},
91
+ 'symptoms': 'Holes in stalks, ear damage, reduced yield',
92
+ 'treatment': 'Bt corn varieties, beneficial insects, crop rotation',
93
+ 'risk_factors': ['warm_weather', 'dense_planting', 'previous_infestation']
94
+ },
95
+ 'corn_earworm': {
96
+ 'conditions': {'temp_range': (25, 35), 'humidity_range': (60, 85), 'rainfall_range': (50, 150)},
97
+ 'symptoms': 'Damage to ears, frass in silk, reduced quality',
98
+ 'treatment': 'Insecticides, Bt varieties, pheromone traps',
99
+ 'risk_factors': ['warm_weather', 'high_humidity', 'late_planting']
100
+ },
101
+ 'gray_leaf_spot': {
102
+ 'conditions': {'temp_range': (20, 30), 'humidity_range': (80, 95), 'rainfall_range': (80, 200)},
103
+ 'symptoms': 'Gray lesions on leaves, premature death',
104
+ 'treatment': 'Fungicide application, resistant varieties, crop rotation',
105
+ 'risk_factors': ['high_humidity', 'warm_temperatures', 'continuous_corn']
106
+ }
107
+ },
108
+ 'tomato': {
109
+ 'aphids': {
110
+ 'conditions': {'temp_range': (20, 30), 'humidity_range': (50, 80), 'rainfall_range': (30, 100)},
111
+ 'symptoms': 'Curled leaves, honeydew, virus transmission',
112
+ 'treatment': 'Neem oil, beneficial insects, reflective mulches',
113
+ 'risk_factors': ['high_nitrogen', 'dense_planting', 'poor_air_circulation']
114
+ },
115
+ 'late_blight': {
116
+ 'conditions': {'temp_range': (15, 25), 'humidity_range': (85, 95), 'rainfall_range': (50, 150)},
117
+ 'symptoms': 'Water-soaked lesions, white mold, rapid spread',
118
+ 'treatment': 'Copper fungicides, resistant varieties, proper spacing',
119
+ 'risk_factors': ['high_humidity', 'cool_temperatures', 'poor_air_circulation']
120
+ },
121
+ 'whitefly': {
122
+ 'conditions': {'temp_range': (25, 35), 'humidity_range': (40, 70), 'rainfall_range': (20, 80)},
123
+ 'symptoms': 'Yellowing leaves, honeydew, sooty mold',
124
+ 'treatment': 'Yellow sticky traps, beneficial insects, reflective mulches',
125
+ 'risk_factors': ['warm_weather', 'low_humidity', 'dense_planting']
126
+ }
127
+ }
128
+ }
129
+
130
+ def _load_disease_database(self) -> Dict:
131
+ """Load comprehensive disease database"""
132
+ return {
133
+ 'fungal_diseases': {
134
+ 'powdery_mildew': {
135
+ 'conditions': {'temp_range': (15, 25), 'humidity_range': (70, 90), 'rainfall_range': (20, 100)},
136
+ 'symptoms': 'White powdery coating on leaves',
137
+ 'treatment': 'Sulfur fungicides, resistant varieties, proper spacing',
138
+ 'affected_crops': ['wheat', 'tomato', 'cucumber', 'grape']
139
+ },
140
+ 'downy_mildew': {
141
+ 'conditions': {'temp_range': (10, 20), 'humidity_range': (85, 95), 'rainfall_range': (50, 200)},
142
+ 'symptoms': 'Yellow spots on upper leaves, white mold underneath',
143
+ 'treatment': 'Copper fungicides, resistant varieties, proper drainage',
144
+ 'affected_crops': ['lettuce', 'cucumber', 'grape', 'onion']
145
+ }
146
+ },
147
+ 'bacterial_diseases': {
148
+ 'bacterial_wilt': {
149
+ 'conditions': {'temp_range': (25, 35), 'humidity_range': (70, 90), 'rainfall_range': (50, 200)},
150
+ 'symptoms': 'Wilting, yellowing, plant death',
151
+ 'treatment': 'Copper-based bactericides, resistant varieties, crop rotation',
152
+ 'affected_crops': ['tomato', 'pepper', 'cucumber', 'eggplant']
153
+ }
154
+ },
155
+ 'viral_diseases': {
156
+ 'mosaic_viruses': {
157
+ 'conditions': {'temp_range': (20, 30), 'humidity_range': (50, 80), 'rainfall_range': (30, 120)},
158
+ 'symptoms': 'Mottled leaves, stunted growth, reduced yield',
159
+ 'treatment': 'Virus-free seeds, vector control, resistant varieties',
160
+ 'affected_crops': ['tomato', 'cucumber', 'tobacco', 'pepper']
161
+ }
162
+ }
163
+ }
164
+
165
+ def predict_with_llama(self, crop_type: str, weather_data: Dict, soil_data: Dict) -> str:
166
+ """
167
+ Use Llama 2 to predict pest and disease risks
168
+ """
169
+ if not self.model or not self.tokenizer:
170
+ return self._rule_based_prediction(crop_type, weather_data, soil_data)
171
+
172
+ try:
173
+ # Prepare context for Llama 2
174
+ context = f"""
175
+ As an agricultural pest and disease expert, analyze the following conditions for {crop_type} farming:
176
+
177
+ Weather Conditions:
178
+ - Temperature: {weather_data.get('temperature', 'N/A')}°C
179
+ - Humidity: {weather_data.get('humidity', 'N/A')}%
180
+ - Rainfall: {weather_data.get('rainfall', 'N/A')} mm
181
+ - Wind Speed: {weather_data.get('wind_speed', 'N/A')} m/s
182
+ - Description: {weather_data.get('description', 'N/A')}
183
+
184
+ Soil Conditions:
185
+ - pH: {soil_data.get('ph', 'N/A')}
186
+ - Moisture: {soil_data.get('moisture', 'N/A')}%
187
+ - Type: {soil_data.get('type', 'N/A')}
188
+
189
+ Provide a comprehensive pest and disease risk assessment for {crop_type} including:
190
+ 1. Most likely pests and diseases based on current conditions
191
+ 2. Risk level (Low/Medium/High) for each threat
192
+ 3. Specific symptoms to watch for
193
+ 4. Recommended preventive measures
194
+ 5. Treatment options if infestation occurs
195
+ 6. Timing for monitoring and intervention
196
+
197
+ Focus on practical, actionable advice for farmers.
198
+ """
199
+
200
+ # Tokenize and generate response
201
+ inputs = self.tokenizer.encode(context, return_tensors="pt").to(self.device)
202
+
203
+ with torch.no_grad():
204
+ outputs = self.model.generate(
205
+ inputs,
206
+ max_length=inputs.shape[1] + 300,
207
+ num_return_sequences=1,
208
+ temperature=0.7,
209
+ do_sample=True,
210
+ pad_token_id=self.tokenizer.eos_token_id
211
+ )
212
+
213
+ response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
214
+
215
+ # Extract the generated part
216
+ generated_text = response[len(context):].strip()
217
+
218
+ return generated_text if generated_text else self._rule_based_prediction(crop_type, weather_data, soil_data)
219
+
220
+ except Exception as e:
221
+ logger.error(f"Error in Llama 2 pest prediction: {e}")
222
+ return self._rule_based_prediction(crop_type, weather_data, soil_data)
223
+
224
+ def predict(self, crop_type: str, soil_ph: float, soil_moisture: float,
225
+ temperature: float, rainfall: float, additional_data: Dict = None) -> str:
226
+ """
227
+ Main prediction method that combines Llama 2 analysis with rule-based fallback
228
+ """
229
+ try:
230
+ # Prepare weather and soil data
231
+ weather_data = {
232
+ 'temperature': temperature,
233
+ 'humidity': 65.0, # Default if not provided
234
+ 'rainfall': rainfall,
235
+ 'wind_speed': 3.0, # Default if not provided
236
+ 'description': 'partly cloudy' # Default if not provided
237
+ }
238
+
239
+ soil_data = {
240
+ 'ph': soil_ph,
241
+ 'moisture': soil_moisture,
242
+ 'type': 'loamy' # Default if not provided
243
+ }
244
+
245
+ # Update with additional data if provided
246
+ if additional_data:
247
+ weather_data.update(additional_data.get('weather', {}))
248
+ soil_data.update(additional_data.get('soil', {}))
249
+
250
+ # Get Llama 2 prediction
251
+ llama_prediction = self.predict_with_llama(crop_type, weather_data, soil_data)
252
+
253
+ # Get rule-based risk assessment
254
+ risk_assessment = self._assess_risks(crop_type, weather_data, soil_data)
255
+
256
+ # Combine predictions
257
+ combined_prediction = self._combine_predictions(llama_prediction, risk_assessment, crop_type)
258
+
259
+ return combined_prediction
260
+
261
+ except Exception as e:
262
+ logger.error(f"Error in pest prediction: {e}")
263
+ return self._rule_based_prediction(crop_type, weather_data, soil_data)
264
+
265
+ def _assess_risks(self, crop_type: str, weather_data: Dict, soil_data: Dict) -> Dict:
266
+ """Assess pest and disease risks using rule-based approach"""
267
+ risks = {
268
+ 'pests': [],
269
+ 'diseases': [],
270
+ 'overall_risk': 'low',
271
+ 'recommendations': []
272
+ }
273
+
274
+ temp = weather_data.get('temperature', 25)
275
+ humidity = weather_data.get('humidity', 65)
276
+ rainfall = weather_data.get('rainfall', 50)
277
+ soil_ph = soil_data.get('ph', 6.5)
278
+ soil_moisture = soil_data.get('moisture', 50)
279
+
280
+ crop_lower = crop_type.lower()
281
+
282
+ # Check for specific pests based on crop type
283
+ if crop_lower in self.pest_database:
284
+ for pest_name, pest_info in self.pest_database[crop_lower].items():
285
+ conditions = pest_info['conditions']
286
+
287
+ # Check temperature conditions
288
+ temp_ok = conditions['temp_range'][0] <= temp <= conditions['temp_range'][1]
289
+ humidity_ok = conditions['humidity_range'][0] <= humidity <= conditions['humidity_range'][1]
290
+ rainfall_ok = conditions['rainfall_range'][0] <= rainfall <= conditions['rainfall_range'][1]
291
+
292
+ if temp_ok and humidity_ok and rainfall_ok:
293
+ risks['pests'].append({
294
+ 'name': pest_name,
295
+ 'risk_level': 'high',
296
+ 'symptoms': pest_info['symptoms'],
297
+ 'treatment': pest_info['treatment']
298
+ })
299
+ elif any([temp_ok, humidity_ok, rainfall_ok]):
300
+ risks['pests'].append({
301
+ 'name': pest_name,
302
+ 'risk_level': 'medium',
303
+ 'symptoms': pest_info['symptoms'],
304
+ 'treatment': pest_info['treatment']
305
+ })
306
+
307
+ # Check for diseases
308
+ for disease_category, diseases in self.disease_database.items():
309
+ for disease_name, disease_info in diseases.items():
310
+ if crop_lower in disease_info.get('affected_crops', []):
311
+ conditions = disease_info['conditions']
312
+
313
+ temp_ok = conditions['temp_range'][0] <= temp <= conditions['temp_range'][1]
314
+ humidity_ok = conditions['humidity_range'][0] <= humidity <= conditions['humidity_range'][1]
315
+ rainfall_ok = conditions['rainfall_range'][0] <= rainfall <= conditions['rainfall_range'][1]
316
+
317
+ if temp_ok and humidity_ok and rainfall_ok:
318
+ risks['diseases'].append({
319
+ 'name': disease_name,
320
+ 'category': disease_category,
321
+ 'risk_level': 'high',
322
+ 'symptoms': disease_info['symptoms'],
323
+ 'treatment': disease_info['treatment']
324
+ })
325
+
326
+ # Determine overall risk level
327
+ high_risks = len([p for p in risks['pests'] if p['risk_level'] == 'high']) + \
328
+ len([d for d in risks['diseases'] if d['risk_level'] == 'high'])
329
+
330
+ if high_risks > 0:
331
+ risks['overall_risk'] = 'high'
332
+ elif len(risks['pests']) + len(risks['diseases']) > 0:
333
+ risks['overall_risk'] = 'medium'
334
+
335
+ # Generate recommendations
336
+ risks['recommendations'] = self._generate_recommendations(risks, crop_type)
337
+
338
+ return risks
339
+
340
+ def _generate_recommendations(self, risks: Dict, crop_type: str) -> List[str]:
341
+ """Generate specific recommendations based on risk assessment"""
342
+ recommendations = []
343
+
344
+ if risks['overall_risk'] == 'high':
345
+ recommendations.append("🚨 HIGH RISK: Immediate action required. Monitor crops daily.")
346
+ elif risks['overall_risk'] == 'medium':
347
+ recommendations.append("⚠️ MEDIUM RISK: Increased monitoring recommended.")
348
+ else:
349
+ recommendations.append("✅ LOW RISK: Continue regular monitoring.")
350
+
351
+ # Add specific recommendations for pests
352
+ for pest in risks['pests']:
353
+ if pest['risk_level'] == 'high':
354
+ recommendations.append(f"🐛 High risk of {pest['name']}: {pest['treatment']}")
355
+
356
+ # Add specific recommendations for diseases
357
+ for disease in risks['diseases']:
358
+ if disease['risk_level'] == 'high':
359
+ recommendations.append(f"🦠 High risk of {disease['name']}: {disease['treatment']}")
360
+
361
+ # General recommendations
362
+ recommendations.append("📅 Monitor crops every 2-3 days during high-risk periods.")
363
+ recommendations.append("🔍 Look for early symptoms and take preventive action.")
364
+ recommendations.append("🌱 Consider resistant varieties for future plantings.")
365
+
366
+ return recommendations
367
+
368
+ def _combine_predictions(self, llama_prediction: str, risk_assessment: Dict, crop_type: str) -> str:
369
+ """Combine Llama 2 prediction with rule-based assessment"""
370
+ combined = f"🤖 AI Analysis for {crop_type}:\n\n"
371
+ combined += llama_prediction + "\n\n"
372
+
373
+ combined += "📊 Risk Assessment:\n"
374
+ combined += f"Overall Risk Level: {risk_assessment['overall_risk'].upper()}\n\n"
375
+
376
+ if risk_assessment['pests']:
377
+ combined += "🐛 Pest Risks:\n"
378
+ for pest in risk_assessment['pests']:
379
+ combined += f"- {pest['name']} ({pest['risk_level']} risk)\n"
380
+ combined += "\n"
381
+
382
+ if risk_assessment['diseases']:
383
+ combined += "🦠 Disease Risks:\n"
384
+ for disease in risk_assessment['diseases']:
385
+ combined += f"- {disease['name']} ({disease['risk_level']} risk)\n"
386
+ combined += "\n"
387
+
388
+ combined += "💡 Recommendations:\n"
389
+ for rec in risk_assessment['recommendations']:
390
+ combined += f"- {rec}\n"
391
+
392
+ return combined
393
+
394
+ def _rule_based_prediction(self, crop_type: str, weather_data: Dict, soil_data: Dict) -> str:
395
+ """Fallback rule-based prediction when Llama 2 is not available"""
396
+ temp = weather_data.get('temperature', 25)
397
+ humidity = weather_data.get('humidity', 65)
398
+ rainfall = weather_data.get('rainfall', 50)
399
+
400
+ prediction = f"Pest and Disease Risk Assessment for {crop_type}:\n\n"
401
+
402
+ # Basic risk assessment
403
+ if temp > 30 and humidity > 80:
404
+ prediction += "⚠️ High risk of fungal diseases due to hot, humid conditions.\n"
405
+ elif temp < 15 and humidity > 85:
406
+ prediction += "⚠️ High risk of bacterial diseases due to cool, wet conditions.\n"
407
+ elif temp > 25 and humidity < 40:
408
+ prediction += "⚠️ High risk of pest infestation due to hot, dry conditions.\n"
409
+ else:
410
+ prediction += "✅ Conditions appear favorable with low disease risk.\n"
411
+
412
+ # General recommendations
413
+ prediction += "\nGeneral Recommendations:\n"
414
+ prediction += "- Monitor crops regularly for early signs of problems\n"
415
+ prediction += "- Maintain proper spacing for air circulation\n"
416
+ prediction += "- Use disease-resistant varieties when possible\n"
417
+ prediction += "- Practice crop rotation to break pest cycles\n"
418
+
419
+ return prediction
models/enhanced_weather_analyst.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import json
4
+ import logging
5
+ from datetime import datetime, timedelta
6
+ from typing import Dict, List, Optional
7
+ import pandas as pd
8
+ from dotenv import load_dotenv
9
+ from transformers import AutoTokenizer, AutoModelForCausalLM
10
+ import torch
11
+
12
+ # Load environment variables
13
+ load_dotenv()
14
+
15
+ # Set up logging
16
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
+ logger = logging.getLogger(__name__)
18
+
19
+ class EnhancedWeatherAnalyst:
20
+ """
21
+ Enhanced weather analyst that uses real weather APIs and Llama 2 for intelligent forecasting
22
+ """
23
+
24
+ def __init__(self, openweather_api_key: Optional[str] = None):
25
+ self.openweather_api_key = openweather_api_key or os.getenv('OPENWEATHER_API_KEY')
26
+ self.base_url = "https://api.openweathermap.org/data/2.5"
27
+
28
+ # Initialize Llama 2 model for weather analysis
29
+ self.device = "cuda" if torch.cuda.is_available() else "cpu"
30
+ self.model_name = "meta-llama/Llama-2-7b-chat-hf"
31
+
32
+ try:
33
+ self.tokenizer = AutoTokenizer.from_pretrained(self.model_name)
34
+ self.model = AutoModelForCausalLM.from_pretrained(
35
+ self.model_name,
36
+ torch_dtype=torch.float16 if self.device == "cuda" else torch.float32,
37
+ device_map="auto" if self.device == "cuda" else None
38
+ )
39
+ logger.info(f"Loaded Llama 2 model on {self.device}")
40
+ except Exception as e:
41
+ logger.warning(f"Could not load Llama 2 model: {e}. Using fallback analysis.")
42
+ self.model = None
43
+ self.tokenizer = None
44
+
45
+ def get_current_weather(self, lat: float = 12.9716, lon: float = 77.5946) -> Dict:
46
+ """
47
+ Get current weather data from OpenWeatherMap API
48
+ Default coordinates are for Bangalore, India
49
+ """
50
+ if not self.openweather_api_key:
51
+ logger.warning("No OpenWeatherMap API key provided. Using simulated data.")
52
+ return self._get_simulated_weather()
53
+
54
+ try:
55
+ url = f"{self.base_url}/weather"
56
+ params = {
57
+ 'lat': lat,
58
+ 'lon': lon,
59
+ 'appid': self.openweather_api_key,
60
+ 'units': 'metric'
61
+ }
62
+
63
+ response = requests.get(url, params=params, timeout=10)
64
+ response.raise_for_status()
65
+
66
+ data = response.json()
67
+
68
+ return {
69
+ 'temperature': data['main']['temp'],
70
+ 'humidity': data['main']['humidity'],
71
+ 'pressure': data['main']['pressure'],
72
+ 'wind_speed': data['wind']['speed'],
73
+ 'wind_direction': data['wind'].get('deg', 0),
74
+ 'description': data['weather'][0]['description'],
75
+ 'visibility': data.get('visibility', 10000) / 1000, # Convert to km
76
+ 'clouds': data['clouds']['all'],
77
+ 'timestamp': datetime.now().isoformat()
78
+ }
79
+
80
+ except Exception as e:
81
+ logger.error(f"Error fetching current weather: {e}")
82
+ return self._get_simulated_weather()
83
+
84
+ def get_weather_forecast(self, lat: float = 12.9716, lon: float = 77.5946, days: int = 5) -> List[Dict]:
85
+ """
86
+ Get 5-day weather forecast from OpenWeatherMap API
87
+ """
88
+ if not self.openweather_api_key:
89
+ logger.warning("No OpenWeatherMap API key provided. Using simulated data.")
90
+ return self._get_simulated_forecast(days)
91
+
92
+ try:
93
+ url = f"{self.base_url}/forecast"
94
+ params = {
95
+ 'lat': lat,
96
+ 'lon': lon,
97
+ 'appid': self.openweather_api_key,
98
+ 'units': 'metric'
99
+ }
100
+
101
+ response = requests.get(url, params=params, timeout=10)
102
+ response.raise_for_status()
103
+
104
+ data = response.json()
105
+ forecasts = []
106
+
107
+ for item in data['list'][:days * 8]: # 8 forecasts per day (3-hour intervals)
108
+ forecasts.append({
109
+ 'datetime': item['dt_txt'],
110
+ 'temperature': item['main']['temp'],
111
+ 'humidity': item['main']['humidity'],
112
+ 'pressure': item['main']['pressure'],
113
+ 'wind_speed': item['wind']['speed'],
114
+ 'wind_direction': item['wind'].get('deg', 0),
115
+ 'description': item['weather'][0]['description'],
116
+ 'rain_probability': item.get('pop', 0) * 100, # Probability of precipitation
117
+ 'rain_volume': item.get('rain', {}).get('3h', 0), # Rain volume for 3h
118
+ 'clouds': item['clouds']['all']
119
+ })
120
+
121
+ return forecasts
122
+
123
+ except Exception as e:
124
+ logger.error(f"Error fetching weather forecast: {e}")
125
+ return self._get_simulated_forecast(days)
126
+
127
+ def analyze_weather_with_llama(self, weather_data: Dict, crop_type: str = "wheat") -> str:
128
+ """
129
+ Use Llama 2 to analyze weather data and provide agricultural insights
130
+ """
131
+ if not self.model or not self.tokenizer:
132
+ return self._get_fallback_analysis(weather_data, crop_type)
133
+
134
+ try:
135
+ # Prepare context for Llama 2
136
+ context = f"""
137
+ As an agricultural weather expert, analyze the following weather data for {crop_type} farming:
138
+
139
+ Current Weather:
140
+ - Temperature: {weather_data.get('temperature', 'N/A')}°C
141
+ - Humidity: {weather_data.get('humidity', 'N/A')}%
142
+ - Pressure: {weather_data.get('pressure', 'N/A')} hPa
143
+ - Wind Speed: {weather_data.get('wind_speed', 'N/A')} m/s
144
+ - Description: {weather_data.get('description', 'N/A')}
145
+ - Visibility: {weather_data.get('visibility', 'N/A')} km
146
+ - Cloud Cover: {weather_data.get('clouds', 'N/A')}%
147
+
148
+ Provide specific agricultural recommendations for {crop_type} farming based on these conditions.
149
+ Focus on:
150
+ 1. Crop growth implications
151
+ 2. Irrigation needs
152
+ 3. Pest and disease risks
153
+ 4. Harvest timing considerations
154
+ 5. Any weather warnings or alerts
155
+
156
+ Keep the response concise and actionable for farmers.
157
+ """
158
+
159
+ # Tokenize and generate response
160
+ inputs = self.tokenizer.encode(context, return_tensors="pt").to(self.device)
161
+
162
+ with torch.no_grad():
163
+ outputs = self.model.generate(
164
+ inputs,
165
+ max_length=inputs.shape[1] + 200,
166
+ num_return_sequences=1,
167
+ temperature=0.7,
168
+ do_sample=True,
169
+ pad_token_id=self.tokenizer.eos_token_id
170
+ )
171
+
172
+ response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
173
+
174
+ # Extract the generated part (remove the input context)
175
+ generated_text = response[len(context):].strip()
176
+
177
+ return generated_text if generated_text else self._get_fallback_analysis(weather_data, crop_type)
178
+
179
+ except Exception as e:
180
+ logger.error(f"Error in Llama 2 analysis: {e}")
181
+ return self._get_fallback_analysis(weather_data, crop_type)
182
+
183
+ def forecast_agricultural_conditions(self, lat: float = 12.9716, lon: float = 77.5946,
184
+ crop_type: str = "wheat") -> Dict:
185
+ """
186
+ Main method to get comprehensive weather forecast with agricultural insights
187
+ """
188
+ try:
189
+ # Get current weather
190
+ current_weather = self.get_current_weather(lat, lon)
191
+
192
+ # Get forecast
193
+ forecast_data = self.get_weather_forecast(lat, lon, 5)
194
+
195
+ # Analyze with Llama 2
196
+ analysis = self.analyze_weather_with_llama(current_weather, crop_type)
197
+
198
+ # Calculate agricultural metrics
199
+ avg_temp = sum([day['temperature'] for day in forecast_data[:8]]) / min(8, len(forecast_data))
200
+ total_rainfall = sum([day['rain_volume'] for day in forecast_data[:8]])
201
+ avg_humidity = sum([day['humidity'] for day in forecast_data[:8]]) / min(8, len(forecast_data))
202
+
203
+ # Determine agricultural conditions
204
+ conditions = self._assess_agricultural_conditions(avg_temp, total_rainfall, avg_humidity, crop_type)
205
+
206
+ return {
207
+ 'current_weather': current_weather,
208
+ 'forecast': forecast_data,
209
+ 'analysis': analysis,
210
+ 'agricultural_conditions': conditions,
211
+ 'metrics': {
212
+ 'avg_temperature': round(avg_temp, 1),
213
+ 'total_rainfall': round(total_rainfall, 1),
214
+ 'avg_humidity': round(avg_humidity, 1)
215
+ },
216
+ 'recommendations': self._generate_recommendations(conditions, crop_type)
217
+ }
218
+
219
+ except Exception as e:
220
+ logger.error(f"Error in agricultural weather forecast: {e}")
221
+ return self._get_fallback_forecast(crop_type)
222
+
223
+ def _assess_agricultural_conditions(self, temp: float, rainfall: float, humidity: float, crop_type: str) -> Dict:
224
+ """Assess agricultural conditions based on weather metrics"""
225
+ conditions = {
226
+ 'temperature_status': 'optimal',
227
+ 'rainfall_status': 'adequate',
228
+ 'humidity_status': 'normal',
229
+ 'overall_risk': 'low'
230
+ }
231
+
232
+ # Temperature assessment
233
+ if temp < 10 or temp > 35:
234
+ conditions['temperature_status'] = 'extreme'
235
+ conditions['overall_risk'] = 'high'
236
+ elif temp < 15 or temp > 30:
237
+ conditions['temperature_status'] = 'suboptimal'
238
+ if conditions['overall_risk'] == 'low':
239
+ conditions['overall_risk'] = 'medium'
240
+
241
+ # Rainfall assessment
242
+ if rainfall < 10:
243
+ conditions['rainfall_status'] = 'insufficient'
244
+ if conditions['overall_risk'] == 'low':
245
+ conditions['overall_risk'] = 'medium'
246
+ elif rainfall > 50:
247
+ conditions['rainfall_status'] = 'excessive'
248
+ if conditions['overall_risk'] == 'low':
249
+ conditions['overall_risk'] = 'medium'
250
+
251
+ # Humidity assessment
252
+ if humidity < 30:
253
+ conditions['humidity_status'] = 'low'
254
+ elif humidity > 80:
255
+ conditions['humidity_status'] = 'high'
256
+ if conditions['overall_risk'] == 'low':
257
+ conditions['overall_risk'] = 'medium'
258
+
259
+ return conditions
260
+
261
+ def _generate_recommendations(self, conditions: Dict, crop_type: str) -> List[str]:
262
+ """Generate specific recommendations based on conditions"""
263
+ recommendations = []
264
+
265
+ if conditions['temperature_status'] == 'extreme':
266
+ if conditions['temperature_status'] == 'extreme':
267
+ recommendations.append("⚠️ Extreme temperature detected. Consider protective measures like shade nets or heating systems.")
268
+
269
+ if conditions['rainfall_status'] == 'insufficient':
270
+ recommendations.append("💧 Insufficient rainfall. Irrigation may be necessary.")
271
+ elif conditions['rainfall_status'] == 'excessive':
272
+ recommendations.append("🌧️ Excessive rainfall expected. Ensure proper drainage to prevent waterlogging.")
273
+
274
+ if conditions['humidity_status'] == 'high':
275
+ recommendations.append("🌫️ High humidity conditions. Monitor for fungal diseases and ensure good air circulation.")
276
+ elif conditions['humidity_status'] == 'low':
277
+ recommendations.append("🏜️ Low humidity conditions. Consider misting or increased irrigation frequency.")
278
+
279
+ if conditions['overall_risk'] == 'high':
280
+ recommendations.append("🚨 High risk conditions detected. Consult with agricultural experts before proceeding.")
281
+
282
+ return recommendations
283
+
284
+ def _get_simulated_weather(self) -> Dict:
285
+ """Fallback simulated weather data"""
286
+ return {
287
+ 'temperature': 25.0,
288
+ 'humidity': 65.0,
289
+ 'pressure': 1013.25,
290
+ 'wind_speed': 3.5,
291
+ 'wind_direction': 180,
292
+ 'description': 'partly cloudy',
293
+ 'visibility': 10.0,
294
+ 'clouds': 40,
295
+ 'timestamp': datetime.now().isoformat()
296
+ }
297
+
298
+ def _get_simulated_forecast(self, days: int) -> List[Dict]:
299
+ """Fallback simulated forecast data"""
300
+ forecasts = []
301
+ base_temp = 25.0
302
+
303
+ for i in range(days * 8):
304
+ temp = base_temp + (i % 3 - 1) * 2 # Slight variation
305
+ forecasts.append({
306
+ 'datetime': (datetime.now() + timedelta(hours=i*3)).strftime('%Y-%m-%d %H:%M:%S'),
307
+ 'temperature': temp,
308
+ 'humidity': 60 + (i % 5) * 2,
309
+ 'pressure': 1013 + (i % 3 - 1) * 2,
310
+ 'wind_speed': 2 + (i % 4),
311
+ 'wind_direction': (i * 45) % 360,
312
+ 'description': 'partly cloudy',
313
+ 'rain_probability': 20 + (i % 3) * 10,
314
+ 'rain_volume': (i % 7) * 0.5,
315
+ 'clouds': 30 + (i % 4) * 10
316
+ })
317
+
318
+ return forecasts
319
+
320
+ def _get_fallback_analysis(self, weather_data: Dict, crop_type: str) -> str:
321
+ """Fallback analysis when Llama 2 is not available"""
322
+ temp = weather_data.get('temperature', 25)
323
+ humidity = weather_data.get('humidity', 65)
324
+
325
+ analysis = f"Weather analysis for {crop_type} farming:\n"
326
+ analysis += f"Current temperature: {temp}°C - "
327
+
328
+ if temp < 15:
329
+ analysis += "Cool conditions may slow growth.\n"
330
+ elif temp > 30:
331
+ analysis += "Hot conditions may stress plants.\n"
332
+ else:
333
+ analysis += "Optimal temperature range.\n"
334
+
335
+ analysis += f"Humidity: {humidity}% - "
336
+ if humidity > 80:
337
+ analysis += "High humidity increases disease risk.\n"
338
+ elif humidity < 30:
339
+ analysis += "Low humidity may require more irrigation.\n"
340
+ else:
341
+ analysis += "Normal humidity levels.\n"
342
+
343
+ return analysis
344
+
345
+ def _get_fallback_forecast(self, crop_type: str) -> Dict:
346
+ """Fallback forecast when API fails"""
347
+ return {
348
+ 'current_weather': self._get_simulated_weather(),
349
+ 'forecast': self._get_simulated_forecast(5),
350
+ 'analysis': self._get_fallback_analysis(self._get_simulated_weather(), crop_type),
351
+ 'agricultural_conditions': {
352
+ 'temperature_status': 'optimal',
353
+ 'rainfall_status': 'adequate',
354
+ 'humidity_status': 'normal',
355
+ 'overall_risk': 'low'
356
+ },
357
+ 'metrics': {
358
+ 'avg_temperature': 25.0,
359
+ 'total_rainfall': 15.0,
360
+ 'avg_humidity': 65.0
361
+ },
362
+ 'recommendations': ["Monitor weather conditions regularly."]
363
+ }
models/farmer_advisor.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+ import pandas as pd
3
+ import joblib
4
+ from sklearn.tree import DecisionTreeClassifier, export_text
5
+ from sklearn.preprocessing import LabelEncoder
6
+ from sklearn.model_selection import train_test_split
7
+ from sklearn.metrics import accuracy_score
8
+ import warnings
9
+ import os
10
+
11
+ class FarmerAdvisor:
12
+ def __init__(self, db_path='Models/database/sustainable_farming.db'):
13
+ self.db_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'database', 'sustainable_farming.db'))
14
+ self.model = None
15
+ self.encoders = {}
16
+ model_path = 'models/farmer_advisor_model.pkl'
17
+ encoder_path = 'models/farmer_encoders.pkl'
18
+ if os.path.exists(model_path) and os.path.exists(encoder_path):
19
+ self.model = joblib.load(model_path)
20
+ self.encoders = joblib.load(encoder_path)
21
+ else:
22
+ self._load_data()
23
+ self._preprocess()
24
+ self._train_model()
25
+
26
+ def _load_data(self):
27
+ with sqlite3.connect(self.db_path) as conn:
28
+ self.df = pd.read_sql("""
29
+ SELECT Soil_pH, Soil_Moisture, Temperature_C, Rainfall_mm,
30
+ Fertilizer_Usage_kg, Pesticide_Usage_kg, Crop_Yield_ton,
31
+ Crop_Type, Sustainability_Score
32
+ FROM farmer_advisor
33
+ """, conn)
34
+
35
+ # Calculate Carbon Footprint, Water, and Erosion Scores
36
+ self.df["Carbon_Footprint_Score"] = 100 - self.df["Fertilizer_Usage_kg"].fillna(0) * 0.6
37
+ self.df["Water_Score"] = 100 - self.df["Soil_Moisture"].fillna(0) * 0.7
38
+ self.df["Erosion_Score"] = 100 - self.df["Rainfall_mm"].fillna(0) * 0.5
39
+
40
+ # Clip the scores to be within 0 to 100
41
+ self.df["Carbon_Footprint_Score"] = self.df["Carbon_Footprint_Score"].clip(0, 100)
42
+ self.df["Water_Score"] = self.df["Water_Score"].clip(0, 100)
43
+ self.df["Erosion_Score"] = self.df["Erosion_Score"].clip(0, 100)
44
+
45
+ def _preprocess(self):
46
+ # Drop rows where Crop_Type is missing
47
+ self.df.dropna(subset=['Crop_Type'], inplace=True)
48
+ # Initialize and fit the label encoder
49
+ self.encoders['crop'] = LabelEncoder()
50
+ self.df['Crop_encoded'] = self.encoders['crop'].fit_transform(self.df['Crop_Type'].astype(str))
51
+
52
+ def _train_model(self):
53
+ # Define feature columns
54
+ feature_cols = [
55
+ 'Soil_pH', 'Soil_Moisture', 'Temperature_C', 'Rainfall_mm',
56
+ 'Fertilizer_Usage_kg', 'Pesticide_Usage_kg', 'Crop_Yield_ton'
57
+ ]
58
+ # Prepare features and target
59
+ X = self.df[feature_cols].fillna(0)
60
+ y = self.df['Crop_encoded']
61
+ X_train, X_test, y_train, y_test = train_test_split(
62
+ X, y, test_size=0.2, stratify=y, random_state=42
63
+ )
64
+ self.model = DecisionTreeClassifier(
65
+ max_depth=8,
66
+ min_samples_split=6,
67
+ random_state=42
68
+ )
69
+ self.model.fit(X_train, y_train)
70
+ os.makedirs('models', exist_ok=True)
71
+ joblib.dump(self.model, 'models/farmer_advisor_model.pkl')
72
+ joblib.dump(self.encoders, 'models/farmer_encoders.pkl')
73
+ # Only print accuracy and rules if running as a script (not imported)
74
+ if __name__ == "__main__":
75
+ y_pred = self.model.predict(X_test)
76
+ acc = accuracy_score(y_test, y_pred)
77
+ print(f"\nFarmerAdvisor Model Accuracy: {acc:.2f}")
78
+ with warnings.catch_warnings():
79
+ warnings.simplefilter("ignore")
80
+ rules = export_text(self.model, feature_names=feature_cols)
81
+ print("\nDecision Tree Rules for Crop Recommendation:\n")
82
+ print(rules)
83
+
84
+ def recommend(self, soil_ph, soil_moisture, temp, rainfall, fertilizer, pesticide, crop_yield,
85
+ carbon_score=None, water_score=None, erosion_score=None):
86
+ if self.model is None:
87
+ self.model = joblib.load('models/farmer_advisor_model.pkl')
88
+ if not self.encoders:
89
+ self.encoders = joblib.load('models/farmer_encoders.pkl')
90
+
91
+ input_df = pd.DataFrame([[
92
+ soil_ph, soil_moisture, temp, rainfall,
93
+ fertilizer, pesticide, crop_yield
94
+ ]], columns=[
95
+ 'Soil_pH', 'Soil_Moisture', 'Temperature_C', 'Rainfall_mm',
96
+ 'Fertilizer_Usage_kg', 'Pesticide_Usage_kg', 'Crop_Yield_ton'
97
+ ])
98
+
99
+ crop_code = self.model.predict(input_df)[0]
100
+ return self.encoders['crop'].inverse_transform([crop_code])[0]
models/farmer_advisor_model.pkl ADDED
Binary file (18.5 kB). View file
 
models/farmer_encoders.pkl ADDED
Binary file (515 Bytes). View file
 
models/market_Researcher.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+ import pandas as pd
3
+ import joblib
4
+ import os
5
+ from sklearn.ensemble import RandomForestRegressor
6
+ from sklearn.model_selection import train_test_split
7
+ from sklearn.preprocessing import LabelEncoder, StandardScaler
8
+
9
+ class MarketResearcher:
10
+ def __init__(self, db_path="Models/database/sustainable_farming.db"):
11
+ # Prefer explicitly provided db_path if it exists; else fall back to project default
12
+ provided_path = db_path if db_path else ""
13
+ default_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'database', 'sustainable_farming.db'))
14
+ resolved_path = os.path.abspath(provided_path)
15
+ self.db_path = resolved_path if os.path.exists(resolved_path) else default_path
16
+ self.models = {}
17
+ self.encoders = {}
18
+ self.scalers = {}
19
+ # Only train if any model/encoder/scaler file is missing for any product
20
+ base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'models'))
21
+ with sqlite3.connect(self.db_path) as conn:
22
+ products = pd.read_sql(
23
+ "SELECT DISTINCT Product FROM market_researcher", conn
24
+ )['Product'].dropna().unique().tolist()
25
+ missing = False
26
+ for product in products:
27
+ model_name = product.strip().lower().replace(" ", "_")
28
+ if not (os.path.exists(os.path.join(base_dir, f"market_model_{model_name}.pkl")) and \
29
+ os.path.exists(os.path.join(base_dir, f"market_encoder_{model_name}.pkl")) and \
30
+ os.path.exists(os.path.join(base_dir, f"market_scaler_{model_name}.pkl"))):
31
+ missing = True
32
+ break
33
+ if missing:
34
+ self._train_all_models()
35
+
36
+ def _train_all_models(self):
37
+ with sqlite3.connect(self.db_path) as conn:
38
+ products = pd.read_sql(
39
+ "SELECT DISTINCT Product FROM market_researcher", conn
40
+ )['Product'].dropna().unique().tolist()
41
+
42
+ for product in products:
43
+ model_name = product.strip().lower().replace(" ", "_")
44
+ base_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'models'))
45
+ model_path = os.path.join(base_dir, f"market_model_{model_name}.pkl")
46
+ encoder_path = os.path.join(base_dir, f"market_encoder_{model_name}.pkl")
47
+ scaler_path = os.path.join(base_dir, f"market_scaler_{model_name}.pkl")
48
+ if os.path.exists(model_path) and os.path.exists(encoder_path) and os.path.exists(scaler_path):
49
+ continue
50
+ df = pd.read_sql("""
51
+ SELECT Product, Market_Price_per_ton, Demand_Index, Supply_Index,
52
+ Competitor_Price_per_ton, Economic_Indicator,
53
+ Weather_Impact_Score, Seasonal_Factor, Consumer_Trend_Index
54
+ FROM market_researcher
55
+ WHERE Product = ?
56
+ """, conn, params=(product,))
57
+ if len(df) < 10:
58
+ continue
59
+ df['Seasonal_Factor'] = df['Seasonal_Factor'].fillna('None')
60
+ le = LabelEncoder()
61
+ df['Seasonal_Factor_Encoded'] = le.fit_transform(df['Seasonal_Factor'])
62
+ self.encoders[product] = le
63
+ features = ['Demand_Index', 'Supply_Index', 'Competitor_Price_per_ton',
64
+ 'Economic_Indicator', 'Weather_Impact_Score',
65
+ 'Seasonal_Factor_Encoded', 'Consumer_Trend_Index']
66
+ X = df[features]
67
+ y = df['Market_Price_per_ton']
68
+ scaler = StandardScaler()
69
+ X_scaled = scaler.fit_transform(X)
70
+ self.scalers[product] = scaler
71
+ X_train, _, y_train, _ = train_test_split(X_scaled, y, test_size=0.2, random_state=42)
72
+ model = RandomForestRegressor(n_estimators=100, random_state=42)
73
+ model.fit(X_train, y_train)
74
+ os.makedirs(base_dir, exist_ok=True)
75
+ joblib.dump(model, model_path)
76
+ joblib.dump(le, encoder_path)
77
+ joblib.dump(scaler, scaler_path)
78
+
79
+ def forecast(self, product, input_features):
80
+ model_name = product.strip().lower().replace(" ", "_")
81
+ model_path = f"models/market_model_{model_name}.pkl"
82
+ encoder_path = f"models/market_encoder_{model_name}.pkl"
83
+ scaler_path = f"models/market_scaler_{model_name}.pkl"
84
+
85
+ if not os.path.exists(model_path) or not os.path.exists(encoder_path) or not os.path.exists(scaler_path):
86
+ raise ValueError(f"No trained model found for product: {product}")
87
+
88
+ model = joblib.load(model_path)
89
+ le = joblib.load(encoder_path)
90
+ scaler = joblib.load(scaler_path)
91
+
92
+ sf = input_features.get('Seasonal_Factor', 'None')
93
+ if sf not in le.classes_:
94
+ sf = le.classes_[0]
95
+
96
+ sf_encoded = le.transform([sf])[0]
97
+
98
+ input_df = pd.DataFrame([[
99
+ input_features.get('Demand_Index', 0),
100
+ input_features.get('Supply_Index', 0),
101
+ input_features.get('Competitor_Price_per_ton', 0),
102
+ input_features.get('Economic_Indicator', 0),
103
+ input_features.get('Weather_Impact_Score', 0),
104
+ sf_encoded,
105
+ input_features.get('Consumer_Trend_Index', 0)
106
+ ]], columns=[
107
+ 'Demand_Index', 'Supply_Index', 'Competitor_Price_per_ton',
108
+ 'Economic_Indicator', 'Weather_Impact_Score',
109
+ 'Seasonal_Factor_Encoded', 'Consumer_Trend_Index'
110
+ ])
111
+
112
+ input_scaled = scaler.transform(input_df)
113
+ prediction = model.predict(input_scaled)
114
+ return prediction.tolist()
models/market_encoder_corn.pkl ADDED
Binary file (495 Bytes). View file
 
models/market_encoder_rice.pkl ADDED
Binary file (495 Bytes). View file
 
models/market_encoder_soybean.pkl ADDED
Binary file (495 Bytes). View file
 
models/market_encoder_wheat.pkl ADDED
Binary file (495 Bytes). View file
 
models/market_model_corn.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b70f05f98895fe52e199e193be035af378cd2889d79879257ce0f9b22617db69
3
+ size 17862433
models/market_model_rice.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d6c5c89d70d15b43c43298a2f7c7b455c07c9b8fdb4ba7cd8a0e0f174e82192c
3
+ size 18663073
models/market_model_soybean.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:381882ee9739adaf56c99433be9cb22ea5218e204482253bcf8970ba52bde543
3
+ size 18323953
models/market_model_wheat.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b948159a30a1767989ca39f95d29cd555c504efb882e6560c015c499f030bb9f
3
+ size 18040417
models/market_scaler_corn.pkl ADDED
Binary file (1.17 kB). View file
 
models/market_scaler_rice.pkl ADDED
Binary file (1.17 kB). View file
 
models/market_scaler_soybean.pkl ADDED
Binary file (1.17 kB). View file
 
models/market_scaler_wheat.pkl ADDED
Binary file (1.17 kB). View file
 
models/pest_disease_predictor.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class PestDiseasePredictor:
2
+ def predict(self, crop_type, soil_ph, soil_moisture, temperature, rainfall):
3
+ # Example rules (customize as needed)
4
+ crop = crop_type.lower()
5
+ if crop == "tomato":
6
+ if temperature > 28 and rainfall > 60:
7
+ return "High risk of aphids in tomatoes; consider neem oil treatment."
8
+ elif temperature < 15:
9
+ return "Risk of late blight in tomatoes; monitor for leaf spots."
10
+ elif crop == "wheat":
11
+ if rainfall > 80:
12
+ return "High risk of rust disease in wheat; consider fungicide spray."
13
+ elif crop == "rice":
14
+ if temperature > 30 and rainfall > 100:
15
+ return "High risk of bacterial leaf blight in rice; ensure proper drainage."
16
+ elif crop == "corn":
17
+ if temperature > 32 and rainfall < 40:
18
+ return "Risk of corn borer infestation; monitor for larvae."
19
+ elif crop == "soybeans":
20
+ if soil_moisture > 35:
21
+ return "Risk of root rot in soybeans; avoid over-irrigation."
22
+ # Add more rules for other crops as needed
23
+ return "No significant pest or disease risk detected."
24
+ class PestDiseasePredictor:
25
+ def predict(self, crop_type, soil_ph, soil_moisture, temperature, rainfall):
26
+ # Example rules (customize as needed)
27
+ crop = crop_type.lower()
28
+ if crop == "tomato":
29
+ if temperature > 28 and rainfall > 60:
30
+ return "High risk of aphids in tomatoes; consider neem oil treatment."
31
+ elif temperature < 15:
32
+ return "Risk of late blight in tomatoes; monitor for leaf spots."
33
+ elif crop == "wheat":
34
+ if rainfall > 80:
35
+ return "High risk of rust disease in wheat; consider fungicide spray."
36
+ elif crop == "rice":
37
+ if temperature > 30 and rainfall > 100:
38
+ return "High risk of bacterial leaf blight in rice; ensure proper drainage."
39
+ elif crop == "corn":
40
+ if temperature > 32 and rainfall < 40:
41
+ return "Risk of corn borer infestation; monitor for larvae."
42
+ elif crop == "soybeans":
43
+ if soil_moisture > 35:
44
+ return "Risk of root rot in soybeans; avoid over-irrigation."
45
+ # Add more rules for other crops as needed
46
+ return "No significant pest or disease risk detected."
models/rain_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5f442fe0bc96a49622c85a4bcf216b4b56ecc62c081a805d9973b6dd8d44db34
3
+ size 91073185
models/speech_interface.py ADDED
@@ -0,0 +1,487 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import speech_recognition as sr
3
+ import pyttsx3
4
+ from gtts import gTTS
5
+ import io
6
+ import tempfile
7
+ import os
8
+ import threading
9
+ import time
10
+ from typing import Optional, Dict, List
11
+ import logging
12
+
13
+ # Set up logging
14
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class SpeechInterface:
18
+ """
19
+ Comprehensive speech interface supporting multiple languages for farmers
20
+ """
21
+
22
+ def __init__(self):
23
+ self.recognizer = sr.Recognizer()
24
+ self.microphone = None
25
+ self.pyaudio_available = False
26
+
27
+ # Try to initialize microphone with error handling
28
+ try:
29
+ self.microphone = sr.Microphone()
30
+ self.pyaudio_available = True
31
+ logger.info("PyAudio and microphone initialized successfully")
32
+ except AttributeError as e:
33
+ if "PyAudio" in str(e):
34
+ logger.warning("PyAudio not available. Voice input will be disabled.")
35
+ self.pyaudio_available = False
36
+ else:
37
+ logger.error(f"Microphone initialization error: {e}")
38
+ self.pyaudio_available = False
39
+ except Exception as e:
40
+ logger.error(f"Unexpected error initializing microphone: {e}")
41
+ self.pyaudio_available = False
42
+
43
+ # Language mapping for speech recognition and synthesis
44
+ self.language_codes = {
45
+ 'English': 'en',
46
+ 'Hindi': 'hi',
47
+ 'Telugu': 'te',
48
+ 'Kannada': 'kn',
49
+ 'Tamil': 'ta',
50
+ 'Malayalam': 'ml',
51
+ 'Marathi': 'mr',
52
+ 'Bengali': 'bn',
53
+ 'Gujarati': 'gu',
54
+ 'Punjabi': 'pa',
55
+ 'Urdu': 'ur',
56
+ 'French': 'fr',
57
+ 'Spanish': 'es'
58
+ }
59
+
60
+ # Initialize text-to-speech engine
61
+ try:
62
+ self.tts_engine = pyttsx3.init()
63
+ self.tts_engine.setProperty('rate', 150) # Speed of speech
64
+ self.tts_engine.setProperty('volume', 0.9) # Volume level
65
+ except Exception as e:
66
+ logger.warning(f"Could not initialize TTS engine: {e}")
67
+ self.tts_engine = None
68
+
69
+ def speech_to_text(self, language: str = 'English', timeout: int = 5) -> Optional[str]:
70
+ """
71
+ Convert speech to text using microphone input
72
+ """
73
+ if not self.pyaudio_available or self.microphone is None:
74
+ st.error("❌ Microphone not available. PyAudio is not installed or not working properly.")
75
+ st.info("💡 **To fix this:**\n"
76
+ "1. Install PyAudio: `pip install pyaudio`\n"
77
+ "2. On Windows, you might need: `pip install pipwin` then `pipwin install pyaudio`\n"
78
+ "3. Or use conda: `conda install pyaudio`")
79
+ return None
80
+
81
+ try:
82
+ with self.microphone as source:
83
+ # Adjust for ambient noise
84
+ self.recognizer.adjust_for_ambient_noise(source, duration=0.5)
85
+
86
+ # Show listening indicator
87
+ st.info("🎤 Listening... Speak now!")
88
+
89
+ # Listen for audio
90
+ audio = self.recognizer.listen(source, timeout=timeout, phrase_time_limit=10)
91
+
92
+ # Show processing indicator
93
+ st.info("🔄 Processing your speech...")
94
+
95
+ # Convert speech to text
96
+ language_code = self.language_codes.get(language, 'en')
97
+ text = self.recognizer.recognize_google(audio, language=language_code)
98
+
99
+ st.success(f"✅ Heard: {text}")
100
+ return text
101
+
102
+ except sr.WaitTimeoutError:
103
+ st.warning("⏰ No speech detected. Please try again.")
104
+ return None
105
+ except sr.UnknownValueError:
106
+ st.error("❌ Could not understand the speech. Please speak clearly.")
107
+ return None
108
+ except sr.RequestError as e:
109
+ st.error(f"❌ Speech recognition service error: {e}")
110
+ return None
111
+ except Exception as e:
112
+ st.error(f"❌ Unexpected error: {e}")
113
+ return None
114
+
115
+ def text_to_speech(self, text: str, language: str = 'English', use_gtts: bool = True) -> bool:
116
+ """
117
+ Convert text to speech using either gTTS (online) or pyttsx3 (offline)
118
+ """
119
+ try:
120
+ if use_gtts and text.strip():
121
+ # Use Google Text-to-Speech (online, better quality, supports more languages)
122
+ language_code = self.language_codes.get(language, 'en')
123
+ tts = gTTS(text=text, lang=language_code, slow=False)
124
+
125
+ # Create temporary file with better handling
126
+ import uuid
127
+ temp_filename = f"tts_{uuid.uuid4().hex}.mp3"
128
+ temp_path = os.path.join(tempfile.gettempdir(), temp_filename)
129
+
130
+ try:
131
+ tts.save(temp_path)
132
+
133
+ # Play audio in Streamlit
134
+ with open(temp_path, 'rb') as audio_file:
135
+ audio_bytes = audio_file.read()
136
+ st.audio(audio_bytes, format='audio/mp3')
137
+ st.info(f"🔊 Audio generated! If you don't hear anything, check your speakers/headphones and browser audio settings.")
138
+
139
+ # Provide download option as fallback
140
+ st.download_button(
141
+ label="⬇️ Download Audio File",
142
+ data=audio_bytes,
143
+ file_name=f"recommendation_audio_{uuid.uuid4().hex[:8]}.mp3",
144
+ mime="audio/mp3",
145
+ help="Download the audio file to play it in your preferred audio player"
146
+ )
147
+
148
+ # Clean up with retry mechanism
149
+ try:
150
+ os.unlink(temp_path)
151
+ except PermissionError:
152
+ # File might still be in use, try again after a short delay
153
+ import time
154
+ time.sleep(0.5)
155
+ try:
156
+ os.unlink(temp_path)
157
+ except:
158
+ # If still can't delete, just leave it - temp files are cleaned up by system
159
+ pass
160
+
161
+ return True
162
+
163
+ except Exception as e:
164
+ logger.error(f"Error with gTTS file handling: {e}")
165
+ # Fallback to pyttsx3
166
+ if self.tts_engine:
167
+ self.tts_engine.say(text)
168
+ self.tts_engine.runAndWait()
169
+ return True
170
+ return False
171
+
172
+ elif self.tts_engine and text.strip():
173
+ # Use pyttsx3 (offline, limited language support)
174
+ try:
175
+ self.tts_engine.say(text)
176
+ self.tts_engine.runAndWait()
177
+ st.info("🔊 Playing audio using offline TTS engine...")
178
+ return True
179
+ except Exception as e:
180
+ logger.error(f"Error with pyttsx3: {e}")
181
+ st.error(f"❌ Offline TTS error: {e}")
182
+ return False
183
+
184
+ else:
185
+ if not text.strip():
186
+ st.warning("⚠️ No text provided to speak")
187
+ else:
188
+ st.warning("⚠️ No TTS engine available. Please check your internet connection for online TTS or install offline TTS dependencies.")
189
+ return False
190
+
191
+ except Exception as e:
192
+ logger.error(f"Error in text-to-speech: {e}")
193
+ st.error(f"❌ Text-to-speech error: {e}")
194
+ return False
195
+
196
+ def create_voice_input_widget(self, label: str, language: str = 'English',
197
+ key: str = None, help_text: str = None) -> Optional[str]:
198
+ """
199
+ Create a voice input widget for Streamlit
200
+ """
201
+ col1, col2 = st.columns([3, 1])
202
+
203
+ # Get the current value from session state
204
+ text_key = f"{key}_text" if key else "text_input"
205
+ voice_result_key = f"{key}_voice_result" if key else "voice_result"
206
+
207
+ # Initialize session state for voice result
208
+ if voice_result_key not in st.session_state:
209
+ st.session_state[voice_result_key] = ""
210
+
211
+ with col1:
212
+ text_input = st.text_input(
213
+ label,
214
+ key=text_key,
215
+ help=help_text
216
+ )
217
+
218
+ with col2:
219
+ if st.button("🎤 Voice", key=f"{key}_voice_btn" if key else None, help="Click to speak"):
220
+ if not self.pyaudio_available:
221
+ st.error("❌ Microphone not available")
222
+ return text_input
223
+
224
+ with st.spinner("Preparing microphone..."):
225
+ time.sleep(1) # Give time for microphone to initialize
226
+
227
+ try:
228
+ voice_text = self.speech_to_text(language)
229
+ if voice_text:
230
+ # Store voice input in session state
231
+ st.session_state[voice_result_key] = voice_text
232
+ st.success(f"✅ Voice input: {voice_text}")
233
+ # Show the voice input in a separate display
234
+ st.info(f"🎤 Voice input captured: **{voice_text}**")
235
+ st.info("💡 Copy this text and paste it into the input field above")
236
+ # Force a rerun to update the text input
237
+ st.rerun()
238
+ else:
239
+ st.warning("⚠️ No voice input detected")
240
+ except Exception as e:
241
+ st.error(f"❌ Voice input error: {e}")
242
+ logger.error(f"Voice input error: {e}")
243
+
244
+ # Show voice result if available
245
+ if st.session_state.get(voice_result_key):
246
+ st.info(f"🎤 Last voice input: **{st.session_state[voice_result_key]}**")
247
+
248
+ return text_input
249
+
250
+ def create_voice_output_button(self, text: str, language: str = 'English',
251
+ button_text: str = "🔊 Listen", key: str = None):
252
+ """
253
+ Create a voice output button for Streamlit
254
+ """
255
+ if st.button(button_text, key=f"{key}_speak" if key else None, help="Click to hear the text"):
256
+ if not text or not text.strip():
257
+ st.warning("⚠️ No text to speak")
258
+ return
259
+
260
+ with st.spinner("Generating speech..."):
261
+ success = self.text_to_speech(text, language)
262
+ if success:
263
+ st.success("✅ Audio generated successfully!")
264
+ else:
265
+ st.error("❌ Failed to generate audio. Please try again.")
266
+
267
+ def create_voice_interface_for_sustainability(self, language: str = 'English') -> Dict:
268
+ """
269
+ Create voice interface specifically for sustainability tracker
270
+ """
271
+ st.markdown("### 🎤 Voice Input for Sustainability Data")
272
+
273
+ # Voice input for water usage
274
+ water_usage_text = self.create_voice_input_widget(
275
+ "💧 Water Usage (ML/ha) - Voice Input",
276
+ language=language,
277
+ key="water_voice",
278
+ help_text="Speak the water usage amount"
279
+ )
280
+
281
+ # Voice input for fertilizer usage
282
+ fertilizer_usage_text = self.create_voice_input_widget(
283
+ "🧪 Fertilizer Usage (tons/ha) - Voice Input",
284
+ language=language,
285
+ key="fertilizer_voice",
286
+ help_text="Speak the fertilizer usage amount"
287
+ )
288
+
289
+ # Voice input for crop rotation
290
+ rotation_text = self.create_voice_input_widget(
291
+ "🔄 Crop Rotation (Yes/No) - Voice Input",
292
+ language=language,
293
+ key="rotation_voice",
294
+ help_text="Say 'Yes' or 'No' for crop rotation"
295
+ )
296
+
297
+ # Get voice results from session state
298
+ water_voice = st.session_state.get("water_voice_voice_result", "")
299
+ fertilizer_voice = st.session_state.get("fertilizer_voice_voice_result", "")
300
+ rotation_voice = st.session_state.get("rotation_voice_voice_result", "")
301
+
302
+ # Use voice input if available, otherwise use text input
303
+ water_usage_text = water_voice if water_voice else water_usage_text
304
+ fertilizer_usage_text = fertilizer_voice if fertilizer_voice else fertilizer_usage_text
305
+ rotation_text = rotation_voice if rotation_voice else rotation_text
306
+
307
+ # Process voice inputs
308
+ data = {}
309
+
310
+ if water_usage_text:
311
+ try:
312
+ # Extract numbers from voice input
313
+ import re
314
+ numbers = re.findall(r'\d+\.?\d*', water_usage_text)
315
+ if numbers:
316
+ data['water_score'] = float(numbers[0])
317
+ except:
318
+ st.warning("Could not parse water usage from voice input")
319
+
320
+ if fertilizer_usage_text:
321
+ try:
322
+ import re
323
+ numbers = re.findall(r'\d+\.?\d*', fertilizer_usage_text)
324
+ if numbers:
325
+ data['fertilizer_use'] = float(numbers[0])
326
+ except:
327
+ st.warning("Could not parse fertilizer usage from voice input")
328
+
329
+ if rotation_text:
330
+ rotation_lower = rotation_text.lower()
331
+ if any(word in rotation_lower for word in ['yes', 'haan', 'ಹೌದು', 'అవును', 'ஆம்', 'അതെ', 'हाँ', 'oui', 'sí']):
332
+ data['rotation'] = True
333
+ elif any(word in rotation_lower for word in ['no', 'nahi', 'ಇಲ್ಲ', 'లేదు', 'இல்லை', 'ഇല്ല', 'नहीं', 'non', 'no']):
334
+ data['rotation'] = False
335
+
336
+ return data
337
+
338
+ def create_voice_interface_for_farm_details(self, language: str = 'English') -> Dict:
339
+ """
340
+ Create voice interface for farm details input
341
+ """
342
+ st.markdown("### 🎤 Voice Input for Farm Details")
343
+
344
+ # Voice input for farm size
345
+ farm_size_text = self.create_voice_input_widget(
346
+ "🌾 Farm Size (hectares) - Voice Input",
347
+ language=language,
348
+ key="farm_size_voice",
349
+ help_text="Speak the farm size in hectares"
350
+ )
351
+
352
+ # Voice input for crop preference
353
+ crop_preference_text = self.create_voice_input_widget(
354
+ "🌱 Crop Preference - Voice Input",
355
+ language=language,
356
+ key="crop_preference_voice",
357
+ help_text="Speak your crop preference (Grains, Vegetables, Fruits)"
358
+ )
359
+
360
+ # Voice input for soil type
361
+ soil_type_text = self.create_voice_input_widget(
362
+ "🗺️ Soil Type - Voice Input",
363
+ language=language,
364
+ key="soil_type_voice",
365
+ help_text="Speak the soil type (Loamy, Sandy, Clay)"
366
+ )
367
+
368
+ # Get voice results from session state
369
+ farm_size_voice = st.session_state.get("farm_size_voice_voice_result", "")
370
+ crop_preference_voice = st.session_state.get("crop_preference_voice_voice_result", "")
371
+ soil_type_voice = st.session_state.get("soil_type_voice_voice_result", "")
372
+
373
+ # Use voice input if available, otherwise use text input
374
+ farm_size_text = farm_size_voice if farm_size_voice else farm_size_text
375
+ crop_preference_text = crop_preference_voice if crop_preference_voice else crop_preference_text
376
+ soil_type_text = soil_type_voice if soil_type_voice else soil_type_text
377
+
378
+ # Process voice inputs
379
+ data = {}
380
+
381
+ # Debug: Show what was captured
382
+ if farm_size_text or crop_preference_text or soil_type_text:
383
+ st.info(f"🎤 Voice inputs captured: Farm Size='{farm_size_text}', Crop='{crop_preference_text}', Soil='{soil_type_text}'")
384
+
385
+ if farm_size_text:
386
+ try:
387
+ import re
388
+ numbers = re.findall(r'\d+', farm_size_text)
389
+ if numbers:
390
+ data['land_size'] = int(numbers[0])
391
+ st.success(f"✅ Parsed land size: {data['land_size']} hectares")
392
+ else:
393
+ st.warning("Could not find numbers in farm size voice input")
394
+ except Exception as e:
395
+ st.warning(f"Could not parse farm size from voice input: {e}")
396
+
397
+ if crop_preference_text:
398
+ crop_lower = crop_preference_text.lower()
399
+ if any(word in crop_lower for word in ['grain', 'grains', 'अनाज', 'ಧಾನ್ಯ', 'ధాన్యం', 'தானியம்', 'ധാന്യം']):
400
+ data['crop_preference'] = 'Grains'
401
+ st.success(f"✅ Parsed crop preference: {data['crop_preference']}")
402
+ elif any(word in crop_lower for word in ['vegetable', 'vegetables', 'सब्जी', 'ತರಕಾರಿ', 'కూరగాయలు', 'காய்கறி', 'പച്ചക്കറി']):
403
+ data['crop_preference'] = 'Vegetables'
404
+ st.success(f"✅ Parsed crop preference: {data['crop_preference']}")
405
+ elif any(word in crop_lower for word in ['fruit', 'fruits', 'फल', 'ಹಣ್ಣು', 'పండు', 'பழம்', 'പഴം']):
406
+ data['crop_preference'] = 'Fruits'
407
+ st.success(f"✅ Parsed crop preference: {data['crop_preference']}")
408
+ else:
409
+ st.warning(f"Could not recognize crop preference from: '{crop_preference_text}'")
410
+
411
+ if soil_type_text:
412
+ soil_lower = soil_type_text.lower()
413
+ if any(word in soil_lower for word in ['loamy', 'loam', 'दोमट', 'ಲೋಮಿ', 'లోమి', 'லோமி', 'ലോമി']):
414
+ data['soil_type'] = 'Loamy'
415
+ st.success(f"✅ Parsed soil type: {data['soil_type']}")
416
+ elif any(word in soil_lower for word in ['sandy', 'sand', 'बालू', 'ಮರಳು', 'ఇసుక', 'மணல்', 'മണൽ']):
417
+ data['soil_type'] = 'Sandy'
418
+ st.success(f"✅ Parsed soil type: {data['soil_type']}")
419
+ elif any(word in soil_lower for word in ['clay', 'चिकनी', 'ಕ್ಲೇ', 'క్లే', 'களிமண்', 'കളിമണ്ണ്']):
420
+ data['soil_type'] = 'Clay'
421
+ st.success(f"✅ Parsed soil type: {data['soil_type']}")
422
+ else:
423
+ st.warning(f"Could not recognize soil type from: '{soil_type_text}'")
424
+
425
+ return data
426
+
427
+ def create_voice_help_system(self, language: str = 'English'):
428
+ """
429
+ Create a voice help system for farmers
430
+ """
431
+ st.markdown("### 🎤 Voice Help System")
432
+
433
+ help_texts = {
434
+ 'English': {
435
+ 'welcome': "Welcome to the Sustainable Farming AI Platform. You can use voice commands to interact with the system.",
436
+ 'farm_details': "To enter farm details, speak your farm size, crop preference, and soil type.",
437
+ 'sustainability': "To log sustainability data, speak your water usage, fertilizer usage, and whether you practice crop rotation.",
438
+ 'recommendations': "Click the generate recommendation button to get AI-powered farming advice based on your inputs."
439
+ },
440
+ 'Hindi': {
441
+ 'welcome': "सस्टेनेबल फार्मिंग AI प्लेटफॉर्म में आपका स्वागत है। आप सिस्टम के साथ बातचीत करने के लिए आवाज कमांड का उपयोग कर सकते हैं।",
442
+ 'farm_details': "फार्म विवरण दर्ज करने के लिए, अपने फार्म का आकार, फसल पसंद और मिट्टी का प्रकार बोलें।",
443
+ 'sustainability': "सस्टेनेबलिटी डेटा लॉग करने के लिए, अपने पानी के उपयोग, उर्वरक के उपयोग और क्या आप फसल चक्रण का अभ्यास करते हैं, बोलें।",
444
+ 'recommendations': "अपने इनपुट के आधार पर AI-संचालित खेती सलाह प्राप्त करने के लिए सिफारिश बटन पर क्लिक करें।"
445
+ },
446
+ 'Telugu': {
447
+ 'welcome': "సస్టైనబుల్ ఫార్మింగ్ AI ప్లాట్‌ఫారమ్‌కు స్వాగతం. మీరు సిస్టమ్‌తో ఇంటరాక్ట్ చేయడానికి వాయిస్ కమాండ్‌లను ఉపయోగించవచ్చు.",
448
+ 'farm_details': "ఫార్మ్ వివరాలను నమోదు చేయడానికి, మీ ఫార్మ్ పరిమాణం, పంట ప్రాధాన్యత మరియు నేల రకాన్ని మాట్లాడండి.",
449
+ 'sustainability': "సస్టైనబిలిటీ డేటాను లాగ్ చేయడానికి, మీ నీటి వినియోగం, ఎరువు వినియోగం మరియు మీరు పంట మార్పిడిని అభ్యసిస్తున్నారా అని మాట్లాడండి.",
450
+ 'recommendations': "మీ ఇన్‌పుట్‌ల ఆధారంగా AI-ఆధారిత వ్యవసాయ సలహా పొందడానికి సిఫారసు బటన్‌పై క్లిక్ చేయండి."
451
+ }
452
+ }
453
+
454
+ help_data = help_texts.get(language, help_texts['English'])
455
+
456
+ col1, col2 = st.columns(2)
457
+
458
+ with col1:
459
+ if st.button("🔊 Listen to Welcome", key="help_welcome"):
460
+ self.text_to_speech(help_data['welcome'], language)
461
+
462
+ with col2:
463
+ if st.button("🔊 Listen to Farm Details Help", key="help_farm"):
464
+ self.text_to_speech(help_data['farm_details'], language)
465
+
466
+ col3, col4 = st.columns(2)
467
+
468
+ with col3:
469
+ if st.button("🔊 Listen to Sustainability Help", key="help_sustainability"):
470
+ self.text_to_speech(help_data['sustainability'], language)
471
+
472
+ with col4:
473
+ if st.button("🔊 Listen to Recommendations Help", key="help_recommendations"):
474
+ self.text_to_speech(help_data['recommendations'], language)
475
+
476
+ def get_supported_languages(self) -> List[str]:
477
+ """
478
+ Get list of supported languages
479
+ """
480
+ return list(self.language_codes.keys())
481
+
482
+ def is_voice_available(self) -> bool:
483
+ """
484
+ Check if voice functionality is available
485
+ """
486
+ return self.pyaudio_available and self.microphone is not None
487
+
models/sustainability_Expert.py ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+ import pandas as pd
3
+ import numpy as np
4
+ import os
5
+
6
+ class SustainabilityExpert:
7
+ def __init__(self, db_path="Models/database/sustainable_farming.db"):
8
+ self.db_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'database', 'sustainable_farming.db'))
9
+ self.sustainability_db = self._load_sustainability_data()
10
+
11
+ def _load_sustainability_data(self):
12
+ with sqlite3.connect(self.db_path) as conn:
13
+ df = pd.read_sql("""
14
+ SELECT Crop_Type,
15
+ AVG(Sustainability_Score) AS avg_score,
16
+ AVG(Fertilizer_Usage_kg) AS avg_fertilizer,
17
+ AVG(Soil_Moisture) AS avg_moisture,
18
+ AVG(Pesticide_Usage_kg) AS avg_pesticide,
19
+ AVG(Crop_Yield_ton) AS avg_yield
20
+ FROM farmer_advisor
21
+ GROUP BY Crop_Type
22
+ """, conn)
23
+ return df.set_index('Crop_Type').to_dict('index')
24
+
25
+ def calculate_carbon_score(self, fertilizer, pesticide, crop_yield):
26
+ # Carbon footprint score based on fertilizer and pesticide usage
27
+ # Lower usage and higher yield means better score
28
+ fertilizer_impact = 1 - (fertilizer / 100) # Normalize to 0-1
29
+ pesticide_impact = 1 - (pesticide / 20) # Normalize to 0-1
30
+ yield_impact = min(crop_yield / 5, 1) # Normalize to 0-1
31
+
32
+ return (0.4 * fertilizer_impact + 0.3 * pesticide_impact + 0.3 * yield_impact)
33
+
34
+ def calculate_water_score(self, soil_moisture, rainfall):
35
+ # Water score based on soil moisture and rainfall
36
+ # Optimal moisture is between 30-40%
37
+ moisture_score = 1 - abs(soil_moisture - 35) / 35
38
+ rainfall_score = min(rainfall / 100, 1)
39
+
40
+ return (0.6 * moisture_score + 0.4 * rainfall_score)
41
+
42
+ def calculate_erosion_score(self, soil_ph, soil_moisture):
43
+ # Erosion score based on soil pH and moisture
44
+ # Optimal pH is between 6-7
45
+ ph_score = 1 - abs(soil_ph - 6.5) / 3.5
46
+ moisture_score = 1 - abs(soil_moisture - 35) / 35
47
+
48
+ return (0.5 * ph_score + 0.5 * moisture_score)
49
+
50
+ def evaluate(self, crops, soil_ph, soil_moisture, rainfall, fertilizer, pesticide, crop_yield):
51
+ """Evaluate sustainability of crops based on environmental factors"""
52
+ results = {}
53
+ for crop in crops:
54
+ # Calculate individual scores
55
+ carbon_score = self.calculate_carbon_score(fertilizer, pesticide, crop_yield)
56
+ water_score = self.calculate_water_score(soil_moisture, rainfall)
57
+ erosion_score = self.calculate_erosion_score(soil_ph, soil_moisture)
58
+
59
+ # Calculate overall sustainability score
60
+ sustainability_score = (
61
+ 0.4 * carbon_score +
62
+ 0.3 * water_score +
63
+ 0.3 * erosion_score
64
+ )
65
+
66
+ results[crop] = {
67
+ 'sustainability': sustainability_score,
68
+ 'carbon': carbon_score,
69
+ 'water': water_score,
70
+ 'erosion': erosion_score
71
+ }
72
+
73
+ # Return the first crop's results since we're only evaluating one crop at a time
74
+ return crops[0], results[crops[0]]
models/sustainable_farming.db ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:808edbd5def2a5dc97c70c955c1a96666afd71aa0ce844b93d032714189ae4c8
3
+ size 3477504
models/temp_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5373e356705070954f5db3543e1d00088ecc78cd6afe57ee81a49daf4ae7e513
3
+ size 91073329
models/test_recommendation.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from Models.central_coordinator import CentralCoordinator
2
+
3
+ # Initialize the CentralCoordinator
4
+ coordinator = CentralCoordinator()
5
+
6
+ # Generate recommendation with sample input values and real-time weather for a city
7
+ result = coordinator.generate_recommendation(
8
+ soil_ph=4.0,
9
+ soil_moisture=10,
10
+ temperature=32,
11
+ rainfall=35,
12
+ fertilizer=0.5,
13
+ pesticide=0.3,
14
+ crop_yield=15,
15
+ city_name="bangalore" # Use real-time weather for Delhi
16
+ )
17
+
18
+ # Print recommendation results
19
+ print("\n--- Final Crop Recommendation ---")
20
+ for key, value in result.items():
21
+ if key == "Warnings" and value:
22
+ print("Warnings:")
23
+ for warning in value:
24
+ print(f" - {warning}")
25
+ else:
26
+ print(f"{key}: {value}")
27
+
28
+ # Automatically plot the result scores
29
+ CentralCoordinator.plot_scores(result)
models/weather_Analyst.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+ import pandas as pd
3
+ import joblib
4
+ import os
5
+ import logging
6
+ from sklearn.ensemble import RandomForestRegressor
7
+ from sklearn.preprocessing import StandardScaler
8
+ from sklearn.model_selection import train_test_split
9
+
10
+ # Set up logging
11
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class WeatherAnalyst:
15
+
16
+ def __init__(self, db_path=None):
17
+ if db_path is None:
18
+ db_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'database', 'sustainable_farming.db'))
19
+ self.db_path = db_path
20
+ # Always use absolute path for models_dir
21
+ self.models_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'models'))
22
+
23
+ if not os.path.exists(self.models_dir):
24
+ os.makedirs(self.models_dir)
25
+ logger.info(f"Created models directory at: {self.models_dir}")
26
+
27
+ self.scaler = StandardScaler()
28
+ self.df = None
29
+ temp_model_path = os.path.join(self.models_dir, 'temp_model.pkl')
30
+ rain_model_path = os.path.join(self.models_dir, 'rain_model.pkl')
31
+ scaler_path = os.path.join(self.models_dir, 'weather_scaler.pkl')
32
+ if os.path.exists(temp_model_path) and os.path.exists(rain_model_path) and os.path.exists(scaler_path):
33
+ # Models already exist, do not retrain
34
+ pass
35
+ else:
36
+ self._prepare_data()
37
+ self._train_models()
38
+
39
+ def _prepare_data(self):
40
+ try:
41
+ with sqlite3.connect(self.db_path) as conn:
42
+ self.df = pd.read_sql("""
43
+ SELECT Soil_pH, Soil_Moisture, Temperature_C, Rainfall_mm,
44
+ Fertilizer_Usage_kg, Pesticide_Usage_kg
45
+ FROM farmer_advisor
46
+ """, conn)
47
+ if self.df.empty:
48
+ logger.warning("No data found in farmer_advisor table.")
49
+ raise ValueError("The farmer_advisor table is empty. Please populate it with data.")
50
+ logger.info(f"Loaded {len(self.df)} rows from farmer_advisor table.")
51
+ except sqlite3.Error as e:
52
+ logger.error(f"Database error: {str(e)}")
53
+ raise sqlite3.Error(f"Failed to connect to database or query data: {str(e)}")
54
+ except Exception as e:
55
+ logger.error(f"Error preparing data: {str(e)}")
56
+ raise
57
+
58
+ def _train_models(self):
59
+ try:
60
+ features = ['Soil_pH', 'Soil_Moisture', 'Fertilizer_Usage_kg', 'Pesticide_Usage_kg']
61
+ X = self.df[features]
62
+ X_scaled = self.scaler.fit_transform(X)
63
+
64
+ y_temp = self.df['Temperature_C']
65
+ y_rain = self.df['Rainfall_mm']
66
+
67
+ temp_model = RandomForestRegressor(n_estimators=100, random_state=42)
68
+ temp_model.fit(X_scaled, y_temp)
69
+
70
+ rain_model = RandomForestRegressor(n_estimators=100, random_state=42)
71
+ rain_model.fit(X_scaled, y_rain)
72
+
73
+ temp_model_path = os.path.join(self.models_dir, 'temp_model.pkl')
74
+ rain_model_path = os.path.join(self.models_dir, 'rain_model.pkl')
75
+ scaler_path = os.path.join(self.models_dir, 'weather_scaler.pkl')
76
+
77
+ # Remove files if they exist to avoid OneDrive/Windows file lock issues
78
+ for path in [temp_model_path, rain_model_path, scaler_path]:
79
+ try:
80
+ if os.path.exists(path):
81
+ os.remove(path)
82
+ except Exception as e:
83
+ logger.warning(f"Could not remove existing model file {path}: {e}")
84
+
85
+ joblib.dump(temp_model, temp_model_path)
86
+ logger.info(f"Saved temperature model at {temp_model_path}")
87
+
88
+ joblib.dump(rain_model, rain_model_path)
89
+ logger.info(f"Saved rainfall model at {rain_model_path}")
90
+
91
+ joblib.dump(self.scaler, scaler_path)
92
+ logger.info(f"Saved scaler at {scaler_path}")
93
+ except Exception as e:
94
+ logger.error(f"Error training models: {str(e)}")
95
+ raise
96
+
97
+ def forecast(self, soil_ph, soil_moisture, fertilizer, pesticide):
98
+ try:
99
+ temp_model = joblib.load(os.path.join(self.models_dir, 'temp_model.pkl'))
100
+ rain_model = joblib.load(os.path.join(self.models_dir, 'rain_model.pkl'))
101
+ scaler = joblib.load(os.path.join(self.models_dir, 'weather_scaler.pkl'))
102
+
103
+ input_df = pd.DataFrame([[soil_ph, soil_moisture, fertilizer, pesticide]],
104
+ columns=['Soil_pH', 'Soil_Moisture', 'Fertilizer_Usage_kg', 'Pesticide_Usage_kg'])
105
+ input_scaled = scaler.transform(input_df)
106
+
107
+ predicted_temp = temp_model.predict(input_scaled)[0]
108
+ predicted_rain = rain_model.predict(input_scaled)[0]
109
+ return {'temperature': [predicted_temp], 'rainfall': [predicted_rain]}
110
+ except Exception as e:
111
+ logger.error(f"Error during forecasting: {str(e)}")
112
+ raise
models/weather_api.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+
3
+ API_KEY = "8acd7401e3d1478a87596f7e00e76226"
4
+ BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
5
+
6
+ def get_current_weather(city_name):
7
+ """
8
+ Fetch current weather data for a given city using OpenWeatherMap API.
9
+ Returns a dictionary with temperature (Celsius) and rainfall (mm, if available).
10
+ """
11
+ params = {
12
+ 'q': city_name,
13
+ 'appid': API_KEY,
14
+ 'units': 'metric'
15
+ }
16
+ response = requests.get(BASE_URL, params=params)
17
+ data = response.json()
18
+ if response.status_code != 200:
19
+ raise Exception(f"Weather API error: {data.get('message', 'Unknown error')}")
20
+ temp = data['main']['temp']
21
+ # Rainfall may not always be present
22
+ rain = data.get('rain', {}).get('1h', 0.0)
23
+ return {
24
+ 'temperature': temp,
25
+ 'rainfall': rain
26
+ }
27
+ import requests
28
+
29
+ API_KEY = "8acd7401e3d1478a87596f7e00e76226"
30
+ BASE_URL = "https://api.openweathermap.org/data/2.5/weather"
31
+
32
+ def get_current_weather(city_name):
33
+ """
34
+ Fetch current weather data for a given city using OpenWeatherMap API.
35
+ Returns a dictionary with temperature (Celsius) and rainfall (mm, if available).
36
+ """
37
+ params = {
38
+ 'q': city_name,
39
+ 'appid': API_KEY,
40
+ 'units': 'metric'
41
+ }
42
+ response = requests.get(BASE_URL, params=params)
43
+ data = response.json()
44
+ if response.status_code != 200:
45
+ raise Exception(f"Weather API error: {data.get('message', 'Unknown error')}")
46
+ temp = data['main']['temp']
47
+ # Rainfall may not always be present
48
+ rain = data.get('rain', {}).get('1h', 0.0)
49
+ return {
50
+ 'temperature': temp,
51
+ 'rainfall': rain
52
+ }
models/weather_scaler.pkl ADDED
Binary file (1.1 kB). View file