emmunger commited on
Commit
6e2acb7
·
verified ·
1 Parent(s): ab0e589

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +293 -58
app.py CHANGED
@@ -1,67 +1,233 @@
 
 
 
 
1
  import streamlit as st
 
 
2
  import requests
3
  import json
4
- import random
5
  import os
6
 
7
- # 1) OPTIONAL: If you plan to store your OpenAI API key in Hugging Face secrets,
8
- # you can retrieve it with:
9
- # OPENAI_API_KEY = os.getenv("OPENAI_API_KEY", "")
10
- #
11
- # 2) If you prefer just hard-coding your key for a quick demo, set it here:
12
- OPENAI_API_KEY = "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"
 
 
 
 
13
 
14
- def analyze_farm_data(soil_moisture, soil_ph, temperature, humidity, crop_health):
 
15
  """
16
- Simple local logic:
17
- - irrigation_needed: soil_moisture < 30
18
- - crop_health_status: "Healthy" if >85, else "Needs Attention"
19
- - random pest_outbreak (just for demonstration)
20
  """
21
- irrigation_needed = soil_moisture < 30
22
- crop_health_status = "Healthy" if crop_health > 85 else "Needs Attention"
23
- pest_outbreak = random.choice([True, False])
24
- return {
25
- "irrigation_needed": irrigation_needed,
26
- "crop_health_status": crop_health_status,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  "pest_outbreak": pest_outbreak
28
- }
 
29
 
30
- def ask_gpt(analysis):
 
31
  """
32
- Calls GPT with the analysis data and returns a user-friendly explanation.
 
 
 
33
  """
34
- text_summary = (
35
- f"Irrigation needed: {analysis['irrigation_needed']}\n"
36
- f"Crop health status: {analysis['crop_health_status']}\n"
37
- f"Pest outbreak: {analysis['pest_outbreak']}\n"
 
 
 
 
 
 
 
 
 
 
 
38
  )
 
 
39
 
40
- prompt = (
41
- "You are an agricultural AI assistant. "
42
- f"Local analysis says:\n{text_summary}\n"
43
- "Explain these results simply for a small-scale farmer and "
44
- "suggest steps to improve farming sustainably."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  )
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  endpoint = "https://api.openai.com/v1/chat/completions"
48
  headers = {
49
  "Content-Type": "application/json",
50
- "Authorization": f"Bearer {OPENAI_API_KEY}"
51
  }
52
  data = {
53
- "model": "gpt-3.5-turbo", # or 'gpt-4' if you have access
54
  "messages": [
55
- {"role": "system", "content": "You are a helpful farming assistant."},
56
- {"role": "user", "content": prompt}
57
  ],
58
- "max_tokens": 300,
59
  "temperature": 0.7
60
  }
61
 
62
  try:
63
- resp = requests.post(endpoint, headers=headers, data=json.dumps(data))
64
- result = resp.json()
65
  if "choices" in result and len(result["choices"]) > 0:
66
  return result["choices"][0]["message"]["content"].strip()
67
  else:
@@ -69,33 +235,102 @@ def ask_gpt(analysis):
69
  except Exception as e:
70
  return f"Error calling GPT: {e}"
71
 
 
 
 
 
72
  def main():
73
- st.title("Farm AI + GPT")
74
- st.markdown("Enter your farm data below, then click **Analyze** to see local results and GPT advice.")
 
 
 
 
 
 
75
 
76
- # Using a form for user input
 
 
 
 
 
 
 
 
 
 
 
 
77
  with st.form("farm_form"):
78
- soil_moisture = st.number_input("Soil Moisture (%)", 0.0, 100.0, 20.0)
79
- soil_ph = st.number_input("Soil pH", 0.0, 14.0, 6.0)
80
- temperature = st.number_input("Temperature (°C)", -10.0, 50.0, 25.0)
81
- humidity = st.number_input("Humidity (%)", 0.0, 100.0, 50.0)
82
- crop_health = st.number_input("Crop Health (0-100)", 0.0, 100.0, 80.0)
 
 
 
 
 
 
 
 
83
 
84
- submitted = st.form_submit_button("Analyze")
85
 
86
  if submitted:
87
- # Step A: Local Analysis
88
- analysis = analyze_farm_data(soil_moisture, soil_ph, temperature, humidity, crop_health)
89
-
90
- st.subheader("Local Analysis Results")
91
- st.write(f"- **Irrigation Needed?** {analysis['irrigation_needed']}")
92
- st.write(f"- **Crop Health Status:** {analysis['crop_health_status']}")
93
- st.write(f"- **Pest Outbreak?** {analysis['pest_outbreak']}")
94
-
95
- # Step B: GPT Explanation
96
- gpt_explanation = ask_gpt(analysis)
97
- st.subheader("GPT Explanation & Advice")
98
- st.write(gpt_explanation)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
  if __name__ == "__main__":
101
  main()
 
1
+ ##############################################
2
+ # app.py - Near-Perfect Accuracy Farm AI Demo
3
+ ##############################################
4
+
5
  import streamlit as st
6
+ import numpy as np
7
+ import pandas as pd
8
  import requests
9
  import json
 
10
  import os
11
 
12
+ from sklearn.ensemble import RandomForestClassifier, GradientBoostingRegressor
13
+ from sklearn.linear_model import LogisticRegression
14
+ from sklearn.preprocessing import PolynomialFeatures, StandardScaler
15
+ from sklearn.pipeline import Pipeline
16
+ from sklearn.model_selection import train_test_split
17
+ from sklearn.metrics import accuracy_score, mean_squared_error
18
+
19
+ ################################################################################
20
+ # 1) SYNTHETIC DATA GENERATION WITH NEAR-PERFECT RELATIONSHIPS
21
+ ################################################################################
22
 
23
+ @st.cache_data
24
+ def generate_pest_data(n=200):
25
  """
26
+ Generates synthetic data for pest outbreak classification with a strong,
27
+ easily learnable relationship so that the model can achieve near 100% accuracy.
28
+ Features: temperature, humidity, leaf_wetness
29
+ Target: pest_outbreak (0 or 1)
30
  """
31
+
32
+ # For reproducibility
33
+ np.random.seed(42)
34
+
35
+ # We'll create a 'perfect' or near-perfect relationship:
36
+ # pest_score = 0.3*temperature + 0.5*humidity + 0.1*leaf_wetness
37
+ # Then threshold around the median for 0/1.
38
+
39
+ temperature = np.random.uniform(15, 40, n)
40
+ humidity = np.random.uniform(30, 90, n)
41
+ leaf_wetness = np.random.uniform(0, 100, n)
42
+
43
+ pest_score = 0.3 * temperature + 0.5 * humidity + 0.1 * leaf_wetness
44
+ median_score = np.median(pest_score)
45
+ pest_outbreak = (pest_score >= median_score).astype(int)
46
+
47
+ df = pd.DataFrame({
48
+ "temperature": temperature,
49
+ "humidity": humidity,
50
+ "leaf_wetness": leaf_wetness,
51
  "pest_outbreak": pest_outbreak
52
+ })
53
+ return df
54
 
55
+ @st.cache_data
56
+ def generate_disease_data(n=200):
57
  """
58
+ Synthetic data for disease detection classification with near-perfect relationship.
59
+ We'll use a polynomial link so the model can memorize it well.
60
+ Features: soil_pH, rainfall, planting_density
61
+ Target: disease_present (0 or 1)
62
  """
63
+
64
+ np.random.seed(123)
65
+
66
+ soil_ph = np.random.uniform(5.0, 8.0, n)
67
+ rainfall = np.random.uniform(0, 200, n)
68
+ planting_density = np.random.uniform(50, 200, n)
69
+
70
+ # 'Perfect' polynomial relationship:
71
+ # disease_score = -(soil_ph - 6.5)^2 + 0.02*rainfall + 0.006*planting_density
72
+ # Then threshold around median for 0/1
73
+
74
+ disease_score = (
75
+ -1.0 * (soil_ph - 6.5)**2
76
+ + 0.02 * rainfall
77
+ + 0.006 * planting_density
78
  )
79
+ median_score = np.median(disease_score)
80
+ disease_present = (disease_score >= median_score).astype(int)
81
 
82
+ df = pd.DataFrame({
83
+ "soil_ph": soil_ph,
84
+ "rainfall": rainfall,
85
+ "planting_density": planting_density,
86
+ "disease_present": disease_present
87
+ })
88
+ return df
89
+
90
+ @st.cache_data
91
+ def generate_yield_data(n=200):
92
+ """
93
+ Synthetic data for yield regression with near-perfect correlation.
94
+ We'll ensure a strong linear relationship so the model can achieve very low error.
95
+ Features: soil_fertility, temperature, irrigation_freq, fertilizer_score
96
+ Target: crop_yield (tons/ha)
97
+ """
98
+
99
+ np.random.seed(999)
100
+
101
+ soil_fertility = np.random.uniform(0, 100, n)
102
+ temperature = np.random.uniform(15, 35, n)
103
+ irrigation_freq = np.random.uniform(0, 10, n)
104
+ fertilizer_score = np.random.uniform(0, 100, n)
105
+
106
+ # Near-perfect linear relationship:
107
+ # yield_val = 2.0*soil_fertility + (-0.3)*(abs(temperature-25)) + 3.0*irrigation_freq
108
+ # + 0.8*fertilizer_score
109
+ # plus tiny normal noise
110
+
111
+ yield_val = (
112
+ 2.0 * soil_fertility
113
+ + (-0.3) * np.abs(temperature - 25)
114
+ + 3.0 * irrigation_freq
115
+ + 0.8 * fertilizer_score
116
+ + np.random.normal(0, 1, n) # small noise
117
  )
118
 
119
+ df = pd.DataFrame({
120
+ "soil_fertility": soil_fertility,
121
+ "temperature": temperature,
122
+ "irrigation_freq": irrigation_freq,
123
+ "fertilizer_score": fertilizer_score,
124
+ "crop_yield": yield_val
125
+ })
126
+ return df
127
+
128
+ ################################################################################
129
+ # 2) TRAINING MODELS (CACHED FOR PERFORMANCE)
130
+ ################################################################################
131
+
132
+ @st.cache_resource
133
+ def train_all_models():
134
+ """
135
+ Trains all three models on near-perfect synthetic data:
136
+ - Pest Outbreak (RandomForest)
137
+ - Disease Presence (LogisticRegression w/ polynomial)
138
+ - Yield Regression (GradientBoosting)
139
+ Returns pipelines + metrics in a dict.
140
+ """
141
+
142
+ # 2.1 Pest Model
143
+ pest_df = generate_pest_data()
144
+ X_pest = pest_df[["temperature", "humidity", "leaf_wetness"]]
145
+ y_pest = pest_df["pest_outbreak"]
146
+
147
+ pest_pipeline = Pipeline([
148
+ ("scaler", StandardScaler()),
149
+ ("rf", RandomForestClassifier(n_estimators=50, random_state=42))
150
+ ])
151
+ pest_pipeline.fit(X_pest, y_pest)
152
+ pest_pred_train = pest_pipeline.predict(X_pest)
153
+ pest_accuracy = accuracy_score(y_pest, pest_pred_train)
154
+
155
+ # 2.2 Disease Model
156
+ disease_df = generate_disease_data()
157
+ X_dis = disease_df[["soil_ph", "rainfall", "planting_density"]]
158
+ y_dis = disease_df["disease_present"]
159
+
160
+ disease_pipeline = Pipeline([
161
+ ("poly", PolynomialFeatures(degree=2, include_bias=False)),
162
+ ("scaler", StandardScaler()),
163
+ ("lr", LogisticRegression(random_state=42, max_iter=2000))
164
+ ])
165
+ disease_pipeline.fit(X_dis, y_dis)
166
+ disease_pred_train = disease_pipeline.predict(X_dis)
167
+ disease_accuracy = accuracy_score(y_dis, disease_pred_train)
168
+
169
+ # 2.3 Yield Model
170
+ yield_df = generate_yield_data()
171
+ X_yield = yield_df[["soil_fertility", "temperature", "irrigation_freq", "fertilizer_score"]]
172
+ y_yield = yield_df["crop_yield"]
173
+
174
+ X_train, X_test, y_train, y_test = train_test_split(X_yield, y_yield, test_size=0.2, random_state=42)
175
+
176
+ yield_pipeline = Pipeline([
177
+ ("scaler", StandardScaler()),
178
+ ("gbr", GradientBoostingRegressor(n_estimators=50, learning_rate=0.1, random_state=42))
179
+ ])
180
+ yield_pipeline.fit(X_train, y_train)
181
+
182
+ # Evaluate on train data to see near-perfect learning
183
+ yield_pred_train = yield_pipeline.predict(X_train)
184
+ yield_rmse_train = mean_squared_error(y_train, yield_pred_train, squared=False)
185
+
186
+ # Also check test set
187
+ yield_pred_test = yield_pipeline.predict(X_test)
188
+ yield_rmse_test = mean_squared_error(y_test, yield_pred_test, squared=False)
189
+
190
+ return {
191
+ "pest_model": pest_pipeline,
192
+ "pest_accuracy": pest_accuracy,
193
+ "disease_model": disease_pipeline,
194
+ "disease_accuracy": disease_accuracy,
195
+ "yield_model": yield_pipeline,
196
+ "yield_rmse_train": yield_rmse_train,
197
+ "yield_rmse_test": yield_rmse_test
198
+ }
199
+
200
+ ################################################################################
201
+ # 3) GPT CALLS (BYPASSING 'openai' LIB)
202
+ ################################################################################
203
+
204
+ def call_gpt(prompt_text, openai_api_key):
205
+ """
206
+ Posts to the Chat Completions endpoint with the user prompt.
207
+ Returns GPT's text.
208
+ """
209
+
210
+ if not openai_api_key:
211
+ return "ERROR: No OpenAI API key provided. Please enter it to get GPT advice."
212
+
213
  endpoint = "https://api.openai.com/v1/chat/completions"
214
  headers = {
215
  "Content-Type": "application/json",
216
+ "Authorization": f"Bearer {openai_api_key}"
217
  }
218
  data = {
219
+ "model": "gpt-3.5-turbo", # or "gpt-4" if you have access
220
  "messages": [
221
+ {"role": "system", "content": "You are a highly knowledgeable, helpful farm AI assistant."},
222
+ {"role": "user", "content": prompt_text}
223
  ],
224
+ "max_tokens": 500,
225
  "temperature": 0.7
226
  }
227
 
228
  try:
229
+ response = requests.post(endpoint, headers=headers, json=data, timeout=30)
230
+ result = response.json()
231
  if "choices" in result and len(result["choices"]) > 0:
232
  return result["choices"][0]["message"]["content"].strip()
233
  else:
 
235
  except Exception as e:
236
  return f"Error calling GPT: {e}"
237
 
238
+ ################################################################################
239
+ # 4) STREAMLIT APP (NEAR-PERFECT ACCURACY, SCALABLE POC)
240
+ ################################################################################
241
+
242
  def main():
243
+ st.title("Near-Perfect Farm AI + GPT (Scalable PoC)")
244
+ st.markdown("""
245
+ **Features**:
246
+ - Three local ML models (pest, disease, yield) with near-perfect synthetic data.
247
+ - GPT for advanced explanations and advice.
248
+ - Demonstrates a scalable approach for real production: replace synthetic data
249
+ and model training with real data or pre-trained models.
250
+ """)
251
 
252
+ # 4.1 Load/Train Models
253
+ with st.spinner("Training models on near-perfect synthetic data..."):
254
+ models = train_all_models()
255
+
256
+ # 4.2 Sidebar: Show training metrics
257
+ st.sidebar.header("Local Model Performance")
258
+ st.sidebar.write(f"**Pest Model Accuracy:** {models['pest_accuracy']*100:.2f}%")
259
+ st.sidebar.write(f"**Disease Model Accuracy:** {models['disease_accuracy']*100:.2f}%")
260
+ st.sidebar.write(f"**Yield RMSE (Train):** {models['yield_rmse_train']:.2f}")
261
+ st.sidebar.write(f"**Yield RMSE (Test):** {models['yield_rmse_test']:.2f}")
262
+
263
+ # 4.3 User Input Form
264
+ st.subheader("Enter Your Farm Conditions")
265
  with st.form("farm_form"):
266
+ soil_moisture = st.slider("Soil Moisture (%)", 0.0, 100.0, 25.0, 1.0)
267
+ soil_ph = st.slider("Soil pH", 0.0, 14.0, 6.5, 0.1)
268
+ temperature = st.slider("Temperature (°C)", 0.0, 50.0, 28.0, 1.0)
269
+ humidity = st.slider("Humidity (%)", 0.0, 100.0, 60.0, 1.0)
270
+ crop_health = st.slider("Crop Health (0-100)", 0.0, 100.0, 80.0, 1.0)
271
+ leaf_wetness = st.slider("Leaf Wetness (0-100)", 0.0, 100.0, 40.0, 1.0)
272
+ rainfall = st.number_input("Rainfall (mm)", 0.0, 500.0, 50.0, 5.0)
273
+ planting_density = st.number_input("#Plants/Acre", 10.0, 500.0, 100.0, 10.0)
274
+ irrigation_freq = st.number_input("Irrigation Frequency (times/week)", 0.0, 14.0, 3.0, 1.0)
275
+ fertilizer_score = st.slider("Fertilizer Score (0-100)", 0.0, 100.0, 50.0, 1.0)
276
+
277
+ st.markdown("### GPT Setup")
278
+ openai_api_key = st.text_input("OpenAI API Key (for GPT)", type="password")
279
 
280
+ submitted = st.form_submit_button("Analyze & Get GPT Advice")
281
 
282
  if submitted:
283
+ st.subheader("Local Analysis & Predictions")
284
+ # 4.3.1 Basic rules
285
+ irrigation_needed = (soil_moisture < 30)
286
+ crop_health_status = "Healthy" if crop_health > 85 else "Needs Attention"
287
+
288
+ # 4.3.2 Pest Prediction
289
+ X_pest = np.array([[temperature, humidity, leaf_wetness]])
290
+ pest_outbreak = (models["pest_model"].predict(X_pest)[0] == 1)
291
+
292
+ # 4.3.3 Disease Detection
293
+ X_dis = np.array([[soil_ph, rainfall, planting_density]])
294
+ disease_present = (models["disease_model"].predict(X_dis)[0] == 1)
295
+
296
+ # 4.3.4 Yield Regression
297
+ # We treat "crop_health" as a stand-in for "soil_fertility" here.
298
+ X_yield = np.array([[crop_health, temperature, irrigation_freq, fertilizer_score]])
299
+ yield_prediction = models["yield_model"].predict(X_yield)[0]
300
+
301
+ # Display local results
302
+ st.write(f"- **Irrigation Needed?** {irrigation_needed}")
303
+ st.write(f"- **Crop Health Status:** {crop_health_status}")
304
+ st.write(f"- **Pest Outbreak Likely?** {pest_outbreak}")
305
+ st.write(f"- **Disease Present?** {disease_present}")
306
+ st.write(f"- **Predicted Yield (t/ha):** {yield_prediction:.2f}")
307
+
308
+ # 4.3.5 GPT Explanation
309
+ summary_prompt = (
310
+ "These are the farm conditions:\n"
311
+ f" - Soil Moisture: {soil_moisture:.1f}%\n"
312
+ f" - Soil pH: {soil_ph:.1f}\n"
313
+ f" - Temperature: {temperature:.1f} °C\n"
314
+ f" - Humidity: {humidity:.1f}%\n"
315
+ f" - Crop Health: {crop_health:.1f}\n"
316
+ f" - Leaf Wetness: {leaf_wetness:.1f}\n"
317
+ f" - Rainfall: {rainfall:.1f} mm\n"
318
+ f" - Planting Density: {planting_density:.1f}\n"
319
+ f" - Irrigation Frequency: {irrigation_freq:.1f} times/week\n"
320
+ f" - Fertilizer Score: {fertilizer_score:.1f}\n\n"
321
+ "Local ML Results:\n"
322
+ f" - Irrigation Needed: {irrigation_needed}\n"
323
+ f" - Crop Health Status: {crop_health_status}\n"
324
+ f" - Pest Outbreak: {pest_outbreak}\n"
325
+ f" - Disease Present: {disease_present}\n"
326
+ f" - Yield: {yield_prediction:.2f} t/ha\n\n"
327
+ "Please provide a clear, helpful explanation in plain language, "
328
+ "along with sustainable, cost-effective steps to improve or maintain these conditions."
329
+ )
330
+
331
+ st.subheader("GPT Advice")
332
+ gpt_response = call_gpt(summary_prompt, openai_api_key)
333
+ st.write(gpt_response)
334
 
335
  if __name__ == "__main__":
336
  main()