Emmanuel Frimpong Asante commited on
Commit
1e5e843
·
1 Parent(s): 0693545

update space

Browse files
Files changed (3) hide show
  1. app.py +58 -268
  2. requirements.txt +0 -10
  3. utils.py +215 -0
app.py CHANGED
@@ -1,17 +1,16 @@
 
 
1
  # Import necessary libraries
2
  import os
3
  import logging
4
  import dotenv
5
- import tensorflow as tf
6
- from keras.models import load_model
7
  import gradio as gr
8
- import cv2
9
  import numpy as np
10
- from huggingface_hub import login
11
  from pymongo import MongoClient
12
- from transformers import AutoModelForCausalLM, AutoTokenizer
13
  from datetime import datetime
14
  from werkzeug.security import generate_password_hash, check_password_hash
 
 
15
 
16
  # Load environment variables from .env file
17
  dotenv.load_dotenv()
@@ -29,7 +28,6 @@ enquiries_collection = db.enquiries # Collection to store farmer enquiries
29
  users_collection = db.users # Collection to store user credentials
30
  logs_collection = db.logs # Collection to store application logs
31
 
32
-
33
  def log_to_db(level, message):
34
  log_entry = {
35
  "level": level,
@@ -38,14 +36,12 @@ def log_to_db(level, message):
38
  }
39
  logs_collection.insert_one(log_entry)
40
 
41
-
42
  # Override logger methods to also log to MongoDB
43
  class MongoHandler(logging.Handler):
44
  def emit(self, record):
45
  log_entry = self.format(record)
46
  log_to_db(record.levelname, log_entry)
47
 
48
-
49
  mongo_handler = MongoHandler()
50
  mongo_handler.setLevel(logging.INFO)
51
  formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
@@ -57,230 +53,9 @@ tok = os.getenv('HF_TOKEN')
57
  if tok:
58
  # Log in to Hugging Face using the token from environment variables
59
  logger.info("Logging in to Hugging Face.")
60
- login(token=tok, add_to_git_credential=True)
61
  else:
62
  logger.warning("Hugging Face token not found in environment variables.")
63
 
64
- # GPU Setup for TensorFlow
65
- logger.info("TensorFlow version: %s", tf.__version__)
66
- logger.info("Eager execution: %s", tf.executing_eagerly())
67
- logger.info("TensorFlow GPU Available: %s", tf.config.list_physical_devices('GPU'))
68
-
69
- # Set TensorFlow to use mixed precision if GPU is available
70
- from tensorflow.keras import mixed_precision
71
-
72
- if len(tf.config.list_physical_devices('GPU')) > 0:
73
- # Set mixed precision policy to improve GPU performance
74
- policy = mixed_precision.Policy('mixed_float16')
75
- mixed_precision.set_global_policy(policy)
76
- logger.info("Using mixed precision with GPU")
77
- else:
78
- logger.info("Using CPU without mixed precision")
79
-
80
-
81
- # Model loading utility
82
- def load_model_with_device(model_path, device_name):
83
- """
84
- Load a Keras model on the specified device.
85
-
86
- Args:
87
- model_path (str): Path to the model file.
88
- device_name (str): Device to load the model on ('/GPU:0' or '/CPU:0').
89
-
90
- Returns:
91
- Model object if successful, None otherwise.
92
- """
93
- try:
94
- logger.info(f"Loading model from '{model_path}' on {device_name}.")
95
- with tf.device(device_name):
96
- model = load_model(model_path, compile=True)
97
- logger.info(f"Model '{model_path}' loaded successfully on {device_name}.")
98
- return model
99
- except Exception as e:
100
- logger.error(f"Error loading model '{model_path}': {e}")
101
- return None
102
-
103
-
104
- # Load disease detection model and authentication model
105
- device_name = '/GPU:0' if len(tf.config.list_physical_devices('GPU')) > 0 else '/CPU:0'
106
- logger.info("Loading disease detection model.")
107
- my_model = load_model_with_device('models/Final_Chicken_disease_model.h5', device_name)
108
-
109
- # Disease names and recommendations
110
- name_disease = {0: 'Coccidiosis', 1: 'Healthy', 2: 'New Castle Disease', 3: 'Salmonella'}
111
- result = {0: 'Critical', 1: 'No issue', 2: 'Critical', 3: 'Critical'}
112
- recommend = {
113
- 0: 'Panadol',
114
- 1: 'You have no need Medicine',
115
- 2: 'Paracetamol',
116
- 3: 'Ponstan'
117
- }
118
-
119
-
120
- # PoultryFarmBot class definition
121
- class PoultryFarmBot:
122
- def __init__(self, db):
123
- """
124
- Initialize the PoultryFarmBot with a MongoDB database connection.
125
-
126
- Args:
127
- db (MongoClient): MongoDB database instance.
128
- """
129
- self.db = db # MongoDB database for future use
130
- logger.info("PoultryFarmBot initialized with MongoDB connection.")
131
-
132
- def preprocess_image(self, image):
133
- """
134
- Preprocess the input image for disease detection.
135
-
136
- Args:
137
- image (numpy.ndarray): Input image to preprocess.
138
-
139
- Returns:
140
- numpy.ndarray: Preprocessed image ready for model input.
141
- """
142
- try:
143
- logger.info("Preprocessing image for disease detection.")
144
- # Resize the image to match the model input size (224x224)
145
- image_check = cv2.resize(image, (224, 224))
146
- # Add a batch dimension to the image
147
- image_check = np.expand_dims(image_check, axis=0)
148
- logger.info("Image preprocessing successful.")
149
- return image_check
150
- except Exception as e:
151
- logger.error(f"Error in image preprocessing: {e}")
152
- return None
153
-
154
- def predict_disease(self, image):
155
- """
156
- Predict the disease from the given poultry fecal image.
157
-
158
- Args:
159
- image (numpy.ndarray): Input image to predict.
160
-
161
- Returns:
162
- tuple: Detailed response, disease name, status, and recommendation.
163
- """
164
- # Preprocess the image
165
- logger.info("Starting disease prediction.")
166
- image_check = self.preprocess_image(image)
167
- if image_check is None:
168
- logger.warning("Image preprocessing failed.")
169
- return "Image preprocessing failed.", None, None, None
170
-
171
- # Predict the disease using the loaded model
172
- try:
173
- logger.info("Running model prediction.")
174
- indx = my_model.predict(image_check).argmax()
175
- name = name_disease.get(indx, "Unknown disease")
176
- status = result.get(indx, "unknown condition")
177
- recom = recommend.get(indx, "no recommendation available")
178
- logger.info(f"Disease prediction successful: {name}, Status: {status}, Recommendation: {recom}")
179
- # Generate a detailed response about the disease
180
- detailed_response = self.generate_disease_response(name, status, recom)
181
- return detailed_response, name, status, recom
182
- except Exception as e:
183
- logger.error(f"Error during disease prediction: {e}")
184
- return "Error during prediction.", None, None, None
185
-
186
- def generate_disease_response(self, disease_name, status, recommendation):
187
- """
188
- Generate a detailed response about the detected disease.
189
-
190
- Args:
191
- disease_name (str): Name of the detected disease.
192
- status (str): Status of the disease (e.g., critical or no issue).
193
- recommendation (str): Recommended action.
194
-
195
- Returns:
196
- str: Detailed response generated by Llama 3.2 model.
197
- """
198
- logger.info(f"Generating detailed response for disease: {disease_name}")
199
- prompt = (
200
- f"The disease detected is {disease_name}, classified as {status}. "
201
- f"Recommended action: {recommendation}. "
202
- f"Here is some information about {disease_name}: causes, symptoms, and treatment methods "
203
- "to effectively manage this condition on a poultry farm."
204
- )
205
- response = llama3_response(prompt)
206
- return response.replace(prompt, "").strip()
207
-
208
- def diagnose_disease(self, image):
209
- """
210
- Diagnose the disease from the given image.
211
-
212
- Args:
213
- image (numpy.ndarray): Input image to diagnose.
214
-
215
- Returns:
216
- tuple: Detailed response, disease name, status, and recommendation.
217
- """
218
- if image is not None and image.size > 0:
219
- logger.info("Image provided, starting diagnosis.")
220
- return self.predict_disease(image)
221
- logger.warning("No image provided for diagnosis.")
222
- return "Please provide an image of poultry fecal matter for disease detection.", None, None, None
223
-
224
- def log_enquiry(self, enquiry_type, content, response, user_id):
225
- """
226
- Log a farmer's enquiry in the database.
227
-
228
- Args:
229
- enquiry_type (str): Type of the enquiry ('image' or 'text').
230
- content (str): The content of the enquiry.
231
- response (str): The response given by the system.
232
- user_id (str): The ID of the user making the enquiry.
233
- """
234
- enquiry = {
235
- "user_id": user_id,
236
- "enquiry_type": enquiry_type,
237
- "content": content,
238
- "response": response,
239
- "timestamp": datetime.utcnow()
240
- }
241
- logger.info(f"Logging enquiry: {enquiry}")
242
- enquiries_collection.insert_one(enquiry)
243
-
244
- def authenticate_user(self, username, password):
245
- """
246
- Authenticate a user with username and password.
247
-
248
- Args:
249
- username (str): Username of the user.
250
- password (str): Password of the user.
251
-
252
- Returns:
253
- dict: User information if authentication is successful, None otherwise.
254
- """
255
- logger.info(f"Authenticating user: {username}")
256
- user = users_collection.find_one({"username": username})
257
- if user and check_password_hash(user['password'], password):
258
- logger.info("Authentication successful.")
259
- return user
260
- logger.warning("Authentication failed.")
261
- return None
262
-
263
- def register_user(self, username, password):
264
- """
265
- Register a new user with username and password.
266
-
267
- Args:
268
- username (str): Username of the new user.
269
- password (str): Password of the new user.
270
-
271
- Returns:
272
- bool: True if registration is successful, False otherwise.
273
- """
274
- logger.info(f"Registering user: {username}")
275
- if users_collection.find_one({"username": username}):
276
- logger.warning("Username already exists.")
277
- return False
278
- hashed_password = generate_password_hash(password)
279
- users_collection.insert_one({"username": username, "password": hashed_password})
280
- logger.info("User registration successful.")
281
- return True
282
-
283
-
284
  # Initialize the bot instance
285
  logger.info("Initializing PoultryFarmBot instance.")
286
  bot = PoultryFarmBot(db)
@@ -297,41 +72,6 @@ if tokenizer.pad_token is None:
297
  tokenizer.add_special_tokens({'pad_token': '[PAD]'})
298
  model.resize_token_embeddings(len(tokenizer))
299
 
300
-
301
- # Llama 3 response generation
302
- def llama3_response(user_input):
303
- """
304
- Generate a response using the Llama 3.2 model.
305
-
306
- Args:
307
- user_input (str): Input prompt for the Llama 3.2 model.
308
-
309
- Returns:
310
- str: Generated response from the model.
311
- """
312
- try:
313
- logger.info("Generating response using Llama 3.2 model.")
314
- # Tokenize the input prompt
315
- inputs = tokenizer(user_input, return_tensors="pt", truncation=True, max_length=150, padding=True)
316
- # Generate a response using the Llama 3.2 model
317
- outputs = model.generate(
318
- inputs["input_ids"],
319
- max_length=150,
320
- do_sample=True,
321
- temperature=0.7,
322
- pad_token_id=tokenizer.pad_token_id,
323
- attention_mask=inputs["attention_mask"]
324
- )
325
- # Decode the generated response
326
- response = tokenizer.decode(outputs[0], skip_special_tokens=True)
327
- logger.info("Response generation successful.")
328
- return response
329
- except Exception as e:
330
- logger.error(f"Error generating response: {str(e)}")
331
- return f"Error generating response: {str(e)}"
332
-
333
-
334
- # Main chatbot function
335
  def chatbot_response(image, text, username, password):
336
  """
337
  Handle user input and generate appropriate responses.
@@ -366,11 +106,10 @@ def chatbot_response(image, text, username, password):
366
  else:
367
  # Generate a response using Llama 3.2 for general text input
368
  logger.info("Text input detected. Generating response.")
369
- response = llama3_response(text)
370
  bot.log_enquiry("text", text, response, user_id)
371
  return response
372
 
373
-
374
  # Gradio interface
375
  def build_gradio_interface():
376
  """
@@ -382,12 +121,63 @@ def build_gradio_interface():
382
  logger.info("Building Gradio interface.")
383
  with gr.Blocks(theme=gr.themes.Base()):
384
  gr.Markdown("# 🐔 Poultry Management Chatbot")
385
- gr.Markdown(
386
- "Welcome! This chatbot helps you manage your poultry with ease. You can upload an image for disease diagnosis or ask any questions about poultry management.")
387
 
388
  chat_history = gr.Chatbot()
389
  with gr.Row():
390
  with gr.Column(scale=1):
391
  fecal_image = gr.Image(
392
  label="Upload Image of Poultry Feces (Optional)",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+
3
  # Import necessary libraries
4
  import os
5
  import logging
6
  import dotenv
 
 
7
  import gradio as gr
 
8
  import numpy as np
 
9
  from pymongo import MongoClient
 
10
  from datetime import datetime
11
  from werkzeug.security import generate_password_hash, check_password_hash
12
+ from utils import PoultryFarmBot, llama3_response
13
+ from transformers import AutoModelForCausalLM, AutoTokenizer
14
 
15
  # Load environment variables from .env file
16
  dotenv.load_dotenv()
 
28
  users_collection = db.users # Collection to store user credentials
29
  logs_collection = db.logs # Collection to store application logs
30
 
 
31
  def log_to_db(level, message):
32
  log_entry = {
33
  "level": level,
 
36
  }
37
  logs_collection.insert_one(log_entry)
38
 
 
39
  # Override logger methods to also log to MongoDB
40
  class MongoHandler(logging.Handler):
41
  def emit(self, record):
42
  log_entry = self.format(record)
43
  log_to_db(record.levelname, log_entry)
44
 
 
45
  mongo_handler = MongoHandler()
46
  mongo_handler.setLevel(logging.INFO)
47
  formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
 
53
  if tok:
54
  # Log in to Hugging Face using the token from environment variables
55
  logger.info("Logging in to Hugging Face.")
 
56
  else:
57
  logger.warning("Hugging Face token not found in environment variables.")
58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  # Initialize the bot instance
60
  logger.info("Initializing PoultryFarmBot instance.")
61
  bot = PoultryFarmBot(db)
 
72
  tokenizer.add_special_tokens({'pad_token': '[PAD]'})
73
  model.resize_token_embeddings(len(tokenizer))
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  def chatbot_response(image, text, username, password):
76
  """
77
  Handle user input and generate appropriate responses.
 
106
  else:
107
  # Generate a response using Llama 3.2 for general text input
108
  logger.info("Text input detected. Generating response.")
109
+ response = llama3_response(text, tokenizer, model)
110
  bot.log_enquiry("text", text, response, user_id)
111
  return response
112
 
 
113
  # Gradio interface
114
  def build_gradio_interface():
115
  """
 
121
  logger.info("Building Gradio interface.")
122
  with gr.Blocks(theme=gr.themes.Base()):
123
  gr.Markdown("# 🐔 Poultry Management Chatbot")
124
+ gr.Markdown("Welcome! This chatbot helps you manage your poultry with ease. You can upload an image for disease diagnosis or ask any questions about poultry management.")
 
125
 
126
  chat_history = gr.Chatbot()
127
  with gr.Row():
128
  with gr.Column(scale=1):
129
  fecal_image = gr.Image(
130
  label="Upload Image of Poultry Feces (Optional)",
131
+ type="numpy",
132
+ elem_id="image-upload",
133
+ show_label=True,
134
+ )
135
+ with gr.Column(scale=2):
136
+ user_input = gr.Textbox(
137
+ label="Ask a question",
138
+ placeholder="Ask about poultry management...",
139
+ lines=3,
140
+ elem_id="user-input",
141
+ )
142
+ username = gr.Textbox(
143
+ label="Username",
144
+ placeholder="Enter your username",
145
+ lines=1,
146
+ elem_id="username-input",
147
+ )
148
+ password = gr.Textbox(
149
+ label="Password",
150
+ placeholder="Enter your password",
151
+ type="password",
152
+ lines=1,
153
+ elem_id="password-input",
154
+ )
155
+
156
+ output_box = gr.Textbox(
157
+ label="Response",
158
+ placeholder="Response will appear here...",
159
+ interactive=False,
160
+ lines=10,
161
+ elem_id="output-box",
162
+ )
163
 
164
+ submit_button = gr.Button(
165
+ "Submit",
166
+ variant="primary",
167
+ elem_id="submit-button"
168
+ )
169
+ # Connect the submit button to the chatbot response function
170
+ submit_button.click(
171
+ fn=chatbot_response,
172
+ inputs=[fecal_image, user_input, username, password],
173
+ outputs=[output_box]
174
+ )
175
+ logger.info("Gradio interface built successfully.")
176
+ return chatbot_interface
177
+
178
+ # Launch the Gradio interface
179
+ if __name__ == "__main__":
180
+ logger.info("Launching Gradio interface.")
181
+ interface = build_gradio_interface()
182
+ # Launch the interface with queuing enabled for concurrent requests
183
+ interface.queue().launch(debug=True, share=True)
requirements.txt CHANGED
@@ -12,16 +12,6 @@ accelerate
12
  # Image Processing Libraries
13
  opencv-python
14
 
15
- # Web Framework and MongoDB
16
- flask
17
- pymongo
18
- bcrypt
19
- PyJWT
20
- python-dotenv
21
- gunicorn
22
-
23
- # streamlit Interface for the Chatbot
24
- streamlit
25
 
26
  # Data Handling and Analysis
27
  pandas
 
12
  # Image Processing Libraries
13
  opencv-python
14
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  # Data Handling and Analysis
17
  pandas
utils.py ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # utils.py
2
+
3
+ import tensorflow as tf
4
+ from keras.models import load_model
5
+ import cv2
6
+ import logging
7
+ import numpy as np
8
+ from transformers import AutoModelForCausalLM, AutoTokenizer
9
+ from datetime import datetime
10
+ from werkzeug.security import generate_password_hash, check_password_hash
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+ def load_model_with_device(model_path, device_name):
15
+ """
16
+ Load a Keras model on the specified device.
17
+
18
+ Args:
19
+ model_path (str): Path to the model file.
20
+ device_name (str): Device to load the model on ('/GPU:0' or '/CPU:0').
21
+
22
+ Returns:
23
+ Model object if successful, None otherwise.
24
+ """
25
+ try:
26
+ logger.info(f"Loading model from '{model_path}' on {device_name}.")
27
+ with tf.device(device_name):
28
+ model = load_model(model_path, compile=True)
29
+ logger.info(f"Model '{model_path}' loaded successfully on {device_name}.")
30
+ return model
31
+ except Exception as e:
32
+ logger.error(f"Error loading model '{model_path}': {e}")
33
+ return None
34
+
35
+ def llama3_response(user_input, tokenizer, model):
36
+ """
37
+ Generate a response using the Llama 3.2 model.
38
+
39
+ Args:
40
+ user_input (str): Input prompt for the Llama 3.2 model.
41
+ tokenizer (AutoTokenizer): Tokenizer to preprocess the input.
42
+ model (AutoModelForCausalLM): Pre-trained language model for generating responses.
43
+
44
+ Returns:
45
+ str: Generated response from the model.
46
+ """
47
+ try:
48
+ logger.info("Generating response using Llama 3.2 model.")
49
+ # Tokenize the input prompt
50
+ inputs = tokenizer(user_input, return_tensors="pt", truncation=True, max_length=150, padding=True)
51
+ # Generate a response using the Llama 3.2 model
52
+ outputs = model.generate(
53
+ inputs["input_ids"],
54
+ max_length=150,
55
+ do_sample=True,
56
+ temperature=0.7,
57
+ pad_token_id=tokenizer.pad_token_id,
58
+ attention_mask=inputs["attention_mask"]
59
+ )
60
+ # Decode the generated response
61
+ response = tokenizer.decode(outputs[0], skip_special_tokens=True)
62
+ logger.info("Response generation successful.")
63
+ return response
64
+ except Exception as e:
65
+ logger.error(f"Error generating response: {str(e)}")
66
+ return f"Error generating response: {str(e)}"
67
+
68
+ class PoultryFarmBot:
69
+ def __init__(self, db):
70
+ """
71
+ Initialize the PoultryFarmBot with a MongoDB database connection.
72
+
73
+ Args:
74
+ db (MongoClient): MongoDB database instance.
75
+ """
76
+ self.db = db # MongoDB database for future use
77
+ logger.info("PoultryFarmBot initialized with MongoDB connection.")
78
+
79
+ def preprocess_image(self, image):
80
+ """
81
+ Preprocess the input image for disease detection.
82
+
83
+ Args:
84
+ image (numpy.ndarray): Input image to preprocess.
85
+
86
+ Returns:
87
+ numpy.ndarray: Preprocessed image ready for model input.
88
+ """
89
+ try:
90
+ logger.info("Preprocessing image for disease detection.")
91
+ # Resize the image to match the model input size (224, 224)
92
+ image_check = cv2.resize(image, (224, 224))
93
+ # Add a batch dimension to the image
94
+ image_check = np.expand_dims(image_check, axis=0)
95
+ logger.info("Image preprocessing successful.")
96
+ return image_check
97
+ except Exception as e:
98
+ logger.error(f"Error in image preprocessing: {e}")
99
+ return None
100
+
101
+ def predict_disease(self, image, model, name_disease, result, recommend):
102
+ """
103
+ Predict the disease from the given poultry fecal image.
104
+
105
+ Args:
106
+ image (numpy.ndarray): Input image to predict.
107
+ model (tf.keras.Model): Loaded Keras model for disease prediction.
108
+ name_disease (dict): Dictionary mapping class indices to disease names.
109
+ result (dict): Dictionary mapping class indices to status.
110
+ recommend (dict): Dictionary mapping class indices to recommendations.
111
+
112
+ Returns:
113
+ tuple: Detailed response, disease name, status, and recommendation.
114
+ """
115
+ logger.info("Starting disease prediction.")
116
+ image_check = self.preprocess_image(image)
117
+ if image_check is None:
118
+ logger.warning("Image preprocessing failed.")
119
+ return "Image preprocessing failed.", None, None, None
120
+
121
+ try:
122
+ logger.info("Running model prediction.")
123
+ indx = model.predict(image_check).argmax()
124
+ name = name_disease.get(indx, "Unknown disease")
125
+ status = result.get(indx, "unknown condition")
126
+ recom = recommend.get(indx, "no recommendation available")
127
+ logger.info(f"Disease prediction successful: {name}, Status: {status}, Recommendation: {recom}")
128
+ detailed_response = self.generate_disease_response(name, status, recom)
129
+ return detailed_response, name, status, recom
130
+ except Exception as e:
131
+ logger.error(f"Error during disease prediction: {e}")
132
+ return "Error during prediction.", None, None, None
133
+
134
+ def generate_disease_response(self, disease_name, status, recommendation):
135
+ """
136
+ Generate a detailed response about the detected disease.
137
+
138
+ Args:
139
+ disease_name (str): Name of the detected disease.
140
+ status (str): Status of the disease (e.g., critical or no issue).
141
+ recommendation (str): Recommended action.
142
+
143
+ Returns:
144
+ str: Detailed response generated by Llama 3.2 model.
145
+ """
146
+ logger.info(f"Generating detailed response for disease: {disease_name}")
147
+ prompt = (
148
+ f"The disease detected is {disease_name}, classified as {status}. "
149
+ f"Recommended action: {recommendation}. "
150
+ f"Here is some information about {disease_name}: causes, symptoms, and treatment methods "
151
+ "to effectively manage this condition on a poultry farm."
152
+ )
153
+ return prompt
154
+
155
+ def log_enquiry(self, enquiry_type, content, response, user_id, enquiries_collection):
156
+ """
157
+ Log a farmer's enquiry in the database.
158
+
159
+ Args:
160
+ enquiry_type (str): Type of the enquiry ('image' or 'text').
161
+ content (str): The content of the enquiry.
162
+ response (str): The response given by the system.
163
+ user_id (str): The ID of the user making the enquiry.
164
+ enquiries_collection (MongoClient): Collection to store farmer enquiries.
165
+ """
166
+ enquiry = {
167
+ "user_id": user_id,
168
+ "enquiry_type": enquiry_type,
169
+ "content": content,
170
+ "response": response,
171
+ "timestamp": datetime.utcnow()
172
+ }
173
+ logger.info(f"Logging enquiry: {enquiry}")
174
+ enquiries_collection.insert_one(enquiry)
175
+
176
+ def authenticate_user(self, username, password, users_collection):
177
+ """
178
+ Authenticate a user with username and password.
179
+
180
+ Args:
181
+ username (str): Username of the user.
182
+ password (str): Password of the user.
183
+ users_collection (MongoClient): Collection to store user credentials.
184
+
185
+ Returns:
186
+ dict: User information if authentication is successful, None otherwise.
187
+ """
188
+ logger.info(f"Authenticating user: {username}")
189
+ user = users_collection.find_one({"username": username})
190
+ if user and check_password_hash(user['password'], password):
191
+ logger.info("Authentication successful.")
192
+ return user
193
+ logger.warning("Authentication failed.")
194
+ return None
195
+
196
+ def register_user(self, username, password, users_collection):
197
+ """
198
+ Register a new user with username and password.
199
+
200
+ Args:
201
+ username (str): Username of the new user.
202
+ password (str): Password of the new user.
203
+ users_collection (MongoClient): Collection to store user credentials.
204
+
205
+ Returns:
206
+ bool: True if registration is successful, False otherwise.
207
+ """
208
+ logger.info(f"Registering user: {username}")
209
+ if users_collection.find_one({"username": username}):
210
+ logger.warning("Username already exists.")
211
+ return False
212
+ hashed_password = generate_password_hash(password)
213
+ users_collection.insert_one({"username": username, "password": hashed_password})
214
+ logger.info("User registration successful.")
215
+ return True