Jeff28 commited on
Commit
654a6ea
·
verified ·
1 Parent(s): 3a50973

Initial commit: Add app.py with Groq API integration

Browse files
Files changed (1) hide show
  1. app.py +371 -0
app.py ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ import tensorflow as tf
4
+ from tensorflow.keras.preprocessing import image
5
+ import gradio as gr
6
+ import requests
7
+ import json
8
+
9
+ # Suppress TensorFlow warnings
10
+ os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
11
+ device = "cuda" if tf.test.is_gpu_available() else "cpu"
12
+ print(f"Running on: {device.upper()}")
13
+
14
+ # Groq API key for AI assistant
15
+ GROQ_API_KEY = "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"
16
+ GROQ_MODEL = "llama3-70b-8192" # Using Llama 3 70B model
17
+
18
+ # Fallback to Hugging Face token if Groq fails
19
+ HF_API_TOKEN = os.getenv("HUGGINGFACE_TOKEN")
20
+ print(f"API tokens available: Groq=Yes, HF={'Yes' if HF_API_TOKEN else 'No'}")
21
+
22
+ # Load the trained tomato disease detection model
23
+ model = tf.keras.models.load_model("Tomato_Leaf_Disease_Model.h5")
24
+
25
+ # Disease categories
26
+ class_labels = [
27
+ "Tomato Bacterial Spot",
28
+ "Tomato Early Blight",
29
+ "Tomato Late Blight",
30
+ "Tomato Mosaic Virus",
31
+ "Tomato Yellow Leaf Curl Virus"
32
+ ]
33
+
34
+ # Disease information database (fallback if API fails)
35
+ disease_info = {
36
+ "Tomato Bacterial Spot": {
37
+ "description": "A bacterial disease that causes small, dark spots on leaves, stems, and fruits.",
38
+ "causes": "Caused by Xanthomonas bacteria, spread by water splash, contaminated tools, and seeds.",
39
+ "recommendations": [
40
+ "Remove and destroy infected plants",
41
+ "Rotate crops with non-solanaceous plants",
42
+ "Use copper-based fungicides",
43
+ "Avoid overhead irrigation"
44
+ ]
45
+ },
46
+ "Tomato Early Blight": {
47
+ "description": "A fungal disease that causes dark spots with concentric rings on lower leaves first.",
48
+ "causes": "Caused by Alternaria solani fungus, favored by warm, humid conditions.",
49
+ "recommendations": [
50
+ "Remove infected leaves promptly",
51
+ "Improve air circulation around plants",
52
+ "Apply fungicides preventatively",
53
+ "Mulch around plants to prevent soil splash"
54
+ ]
55
+ },
56
+ "Tomato Late Blight": {
57
+ "description": "A devastating fungal disease that causes dark, water-soaked lesions on leaves and fruits.",
58
+ "causes": "Caused by Phytophthora infestans, favored by cool, wet conditions.",
59
+ "recommendations": [
60
+ "Remove and destroy infected plants immediately",
61
+ "Apply fungicides preventatively in humid conditions",
62
+ "Improve drainage and air circulation",
63
+ "Plant resistant varieties when available"
64
+ ]
65
+ },
66
+ "Tomato Mosaic Virus": {
67
+ "description": "A viral disease that causes mottled green/yellow patterns on leaves and stunted growth.",
68
+ "causes": "Caused by tobacco mosaic virus (TMV), spread by handling, tools, and sometimes seeds.",
69
+ "recommendations": [
70
+ "Remove and destroy infected plants",
71
+ "Wash hands and tools after handling infected plants",
72
+ "Control insect vectors like aphids",
73
+ "Plant resistant varieties"
74
+ ]
75
+ },
76
+ "Tomato Yellow Leaf Curl Virus": {
77
+ "description": "A viral disease transmitted by whiteflies that causes yellowing and curling of leaves.",
78
+ "causes": "Caused by a begomovirus, transmitted primarily by whiteflies.",
79
+ "recommendations": [
80
+ "Use whitefly control measures",
81
+ "Remove and destroy infected plants",
82
+ "Use reflective mulches to repel whiteflies",
83
+ "Plant resistant varieties"
84
+ ]
85
+ }
86
+ }
87
+
88
+ # Image preprocessing function
89
+ def preprocess_image(img):
90
+ img = img.resize((224, 224)) # Resize for model input
91
+ img = image.img_to_array(img) / 255.0 # Normalize
92
+ return np.expand_dims(img, axis=0) # Add batch dimension
93
+
94
+ # Temperature Scaling: Adjusts predictions using a temperature parameter.
95
+ def apply_temperature_scaling(prediction, temperature):
96
+ # Avoid log(0) by adding a small epsilon
97
+ eps = 1e-8
98
+ scaled_logits = np.log(np.maximum(prediction, eps)) / temperature
99
+ exp_logits = np.exp(scaled_logits)
100
+ scaled_probs = exp_logits / np.sum(exp_logits)
101
+ return scaled_probs
102
+
103
+ # Min-Max Normalization: Scales the raw confidence based on provided min and max values.
104
+ def apply_min_max_scaling(confidence, min_conf, max_conf):
105
+ norm = (confidence - min_conf) / (max_conf - min_conf) * 100
106
+ norm = np.clip(norm, 0, 100)
107
+ return norm
108
+
109
+ # Call Groq API for AI assistant
110
+ def call_groq_api(prompt):
111
+ """Call Groq API for detailed disease analysis and advice"""
112
+ headers = {
113
+ "Authorization": f"Bearer {GROQ_API_KEY}",
114
+ "Content-Type": "application/json"
115
+ }
116
+
117
+ payload = {
118
+ "model": GROQ_MODEL,
119
+ "messages": [
120
+ {"role": "system", "content": "You are an expert agricultural advisor specializing in tomato farming and plant diseases."},
121
+ {"role": "user", "content": prompt}
122
+ ],
123
+ "max_tokens": 800,
124
+ "temperature": 0.7
125
+ }
126
+
127
+ try:
128
+ response = requests.post(
129
+ "https://api.groq.com/openai/v1/chat/completions",
130
+ headers=headers,
131
+ json=payload,
132
+ timeout=30
133
+ )
134
+
135
+ if response.status_code == 200:
136
+ result = response.json()
137
+ if "choices" in result and len(result["choices"]) > 0:
138
+ return result["choices"][0]["message"]["content"]
139
+
140
+ print(f"Groq API error: {response.status_code} - {response.text}")
141
+ return None
142
+
143
+ except Exception as e:
144
+ print(f"Error with Groq API: {str(e)}")
145
+ return None
146
+
147
+ # Fallback to Hugging Face if Groq fails
148
+ def call_hf_model(prompt, model_id="mistralai/Mistral-7B-Instruct-v0.2"):
149
+ """Call an AI model on Hugging Face for detailed disease analysis."""
150
+ if not HF_API_TOKEN:
151
+ return None
152
+
153
+ headers = {"Authorization": f"Bearer {HF_API_TOKEN}"}
154
+
155
+ # Format prompt for instruction-tuned models
156
+ formatted_prompt = f"""<s>[INST] {prompt} [/INST]"""
157
+
158
+ payload = {
159
+ "inputs": formatted_prompt,
160
+ "parameters": {
161
+ "max_new_tokens": 500,
162
+ "temperature": 0.7,
163
+ "top_p": 0.95,
164
+ "do_sample": True
165
+ }
166
+ }
167
+
168
+ url = f"https://api-inference.huggingface.co/models/{model_id}"
169
+
170
+ try:
171
+ response = requests.post(url, headers=headers, json=payload, timeout=30)
172
+
173
+ if response.status_code == 200:
174
+ result = response.json()
175
+ if isinstance(result, list) and len(result) > 0:
176
+ if "generated_text" in result[0]:
177
+ # Extract just the response part (after the prompt)
178
+ generated_text = result[0]["generated_text"]
179
+ # Remove the prompt from the response
180
+ response_text = generated_text.split("[/INST]")[-1].strip()
181
+ return response_text
182
+
183
+ return None
184
+
185
+ except Exception as e:
186
+ print(f"Exception when calling HF model: {str(e)}")
187
+ return None
188
+
189
+ # Combined AI model call with fallback
190
+ def call_ai_model(prompt):
191
+ """Call AI models with fallback mechanisms"""
192
+ # Try Groq first
193
+ response = call_groq_api(prompt)
194
+ if response:
195
+ return response
196
+
197
+ # If Groq fails, try Hugging Face
198
+ response = call_hf_model(prompt)
199
+ if response:
200
+ return response
201
+
202
+ # If both fail, return fallback message
203
+ return "Sorry, I'm having trouble connecting to the AI service. Using fallback information instead."
204
+
205
+ # Generate AI response for disease analysis
206
+ def generate_ai_response(disease_name, confidence):
207
+ """Generate a detailed AI response about the detected disease."""
208
+ # Get fallback information in case AI call fails
209
+ info = disease_info.get(disease_name, {
210
+ "description": "Information not available for this disease.",
211
+ "causes": "Unknown causes.",
212
+ "recommendations": ["Consult with a local agricultural extension service."]
213
+ })
214
+
215
+ # Create prompt for AI model
216
+ prompt = (
217
+ f"You are an agricultural expert advisor. A tomato plant disease has been detected: {disease_name} "
218
+ f"with {confidence:.2f}% confidence. "
219
+ f"Provide a detailed analysis including: "
220
+ f"1) A brief description of the disease "
221
+ f"2) What causes it and how it spreads "
222
+ f"3) The impact on tomato plants and yield "
223
+ f"4) Detailed treatment options (both organic and chemical) "
224
+ f"5) Prevention strategies for future crops "
225
+ f"Format your response in clear sections with bullet points where appropriate."
226
+ )
227
+
228
+ # Call AI model with fallback mechanisms
229
+ ai_response = call_ai_model(prompt)
230
+
231
+ # If AI response contains error message, use fallback information
232
+ if "Sorry, I'm having trouble" in ai_response:
233
+ ai_response = f"""
234
+ # Disease: {disease_name}
235
+
236
+ ## Description
237
+ {info['description']}
238
+
239
+ ## Causes
240
+ {info.get('causes', 'Information not available.')}
241
+
242
+ ## Recommended Treatment
243
+ {chr(10).join(f"- {rec}" for rec in info['recommendations'])}
244
+
245
+ *Note: This is fallback information. For more detailed advice, please try again later when the AI service is available.*
246
+ """
247
+
248
+ return ai_response
249
+
250
+ # Chat with agricultural expert
251
+ def chat_with_expert(message, chat_history):
252
+ """Handle chat interactions with farmers about agricultural topics."""
253
+ if not message.strip():
254
+ return "", chat_history
255
+
256
+ # Prepare context from chat history - use last 3 exchanges for context to avoid token limits
257
+ context = "\n".join([f"Farmer: {q}\nExpert: {a}" for q, a in chat_history[-3:]])
258
+
259
+ prompt = (
260
+ f"You are an expert agricultural advisor specializing in tomato farming and plant diseases. "
261
+ f"You provide helpful, accurate, and practical advice to farmers. "
262
+ f"Always be respectful and considerate of farmers' knowledge while providing expert guidance. "
263
+ f"If you're unsure about something, acknowledge it and provide the best information you can. "
264
+ f"Previous conversation:\n{context}\n\n"
265
+ f"Farmer's new question: {message}\n\n"
266
+ f"Provide a helpful, informative response about farming, focusing on tomatoes if relevant."
267
+ )
268
+
269
+ # Call AI model with fallback mechanisms
270
+ response = call_ai_model(prompt)
271
+
272
+ # If AI response contains error message, use fallback response
273
+ if "Sorry, I'm having trouble" in response:
274
+ response = "I apologize, but I'm having trouble connecting to my knowledge base at the moment. Please try again later, or ask a different question about tomato farming or plant diseases."
275
+
276
+ chat_history.append((message, response))
277
+ return "", chat_history
278
+
279
+ # Main detection function with adjustable confidence scaling
280
+ def detect_disease_scaled(img, scaling_method, temperature, min_conf, max_conf):
281
+ processed_img = preprocess_image(img)
282
+ prediction = model.predict(processed_img)[0] # Get prediction for single image
283
+ raw_confidence = np.max(prediction) * 100
284
+ class_idx = np.argmax(prediction)
285
+ disease_name = class_labels[class_idx]
286
+
287
+ if scaling_method == "Temperature Scaling":
288
+ scaled_probs = apply_temperature_scaling(prediction, temperature)
289
+ adjusted_confidence = np.max(scaled_probs) * 100
290
+ elif scaling_method == "Min-Max Normalization":
291
+ adjusted_confidence = apply_min_max_scaling(raw_confidence, min_conf, max_conf)
292
+ else:
293
+ adjusted_confidence = raw_confidence
294
+
295
+ # Generate AI response
296
+ ai_response = generate_ai_response(disease_name, adjusted_confidence)
297
+
298
+ # Return results
299
+ result = f"{disease_name} (Confidence: {adjusted_confidence:.2f}%)"
300
+ raw_text = f"Raw Confidence: {raw_confidence:.2f}%"
301
+ return result, raw_text, ai_response
302
+
303
+ # Simplified Gradio UI for better compatibility
304
+ with gr.Blocks() as demo:
305
+ gr.Markdown("# 🍅 EvSentry8: Tomato Disease Detection with AI Assistant")
306
+
307
+ with gr.Tab("Disease Detection"):
308
+ with gr.Row():
309
+ with gr.Column():
310
+ image_input = gr.Image(type="pil", label="Upload a Tomato Leaf Image")
311
+
312
+ scaling_method = gr.Radio(
313
+ ["Temperature Scaling", "Min-Max Normalization"],
314
+ label="Confidence Scaling Method",
315
+ value="Temperature Scaling"
316
+ )
317
+ temperature_slider = gr.Slider(0.5, 2.0, step=0.1, label="Temperature", value=1.0)
318
+ min_conf_slider = gr.Slider(0, 100, step=1, label="Min Confidence", value=20)
319
+ max_conf_slider = gr.Slider(0, 100, step=1, label="Max Confidence", value=90)
320
+
321
+ detect_button = gr.Button("Detect Disease")
322
+
323
+ with gr.Column():
324
+ disease_output = gr.Textbox(label="Detected Disease & Adjusted Confidence")
325
+ raw_confidence_output = gr.Textbox(label="Raw Confidence")
326
+ ai_response_output = gr.Markdown(label="AI Assistant's Analysis & Recommendations")
327
+
328
+ with gr.Tab("Chat with Expert"):
329
+ gr.Markdown("# 💬 Chat with Agricultural Expert")
330
+ gr.Markdown("Ask any questions about tomato farming, diseases, or agricultural practices.")
331
+
332
+ chatbot = gr.Chatbot(height=400)
333
+
334
+ with gr.Row():
335
+ chat_input = gr.Textbox(
336
+ label="Your Question",
337
+ placeholder="Ask about tomato farming, diseases, or agricultural practices...",
338
+ lines=2
339
+ )
340
+ chat_button = gr.Button("Send")
341
+
342
+ gr.Markdown("""
343
+ ### Example Questions:
344
+ - How do I identify tomato bacterial spot?
345
+ - What's the best way to prevent late blight?
346
+ - How often should I water my tomato plants?
347
+ - What are the signs of nutrient deficiency in tomatoes?
348
+ """)
349
+
350
+ # Set up event handlers
351
+ detect_button.click(
352
+ detect_disease_scaled,
353
+ inputs=[image_input, scaling_method, temperature_slider, min_conf_slider, max_conf_slider],
354
+ outputs=[disease_output, raw_confidence_output, ai_response_output]
355
+ )
356
+
357
+ # Chat functionality
358
+ chat_button.click(
359
+ fn=chat_with_expert,
360
+ inputs=[chat_input, chatbot],
361
+ outputs=[chat_input, chatbot]
362
+ )
363
+
364
+ # Also allow pressing Enter to send chat
365
+ chat_input.submit(
366
+ fn=chat_with_expert,
367
+ inputs=[chat_input, chatbot],
368
+ outputs=[chat_input, chatbot]
369
+ )
370
+
371
+ demo.launch()