Emmanuel Frimpong Asante commited on
Commit
e88e97b
·
1 Parent(s): f6bbd69

update space

Browse files
.idea/workspace.xml CHANGED
@@ -5,10 +5,8 @@
5
  </component>
6
  <component name="ChangeListManager">
7
  <list default="true" id="27c9ae1a-a6fa-4472-8bcd-a7087620894b" name="Changes" comment="update space">
8
- <change afterPath="$PROJECT_DIR$/models/auth.h5" afterDir="false" />
9
  <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
10
- <change beforePath="$PROJECT_DIR$/models/Final_Chicken_disease_model.h5" beforeDir="false" afterPath="$PROJECT_DIR$/models/diseases.h5" afterDir="false" />
11
- <change beforePath="$PROJECT_DIR$/services/convert_model.py" beforeDir="false" afterPath="$PROJECT_DIR$/services/convert_model.py" afterDir="false" />
12
  <change beforePath="$PROJECT_DIR$/services/disease_detection_service.py" beforeDir="false" afterPath="$PROJECT_DIR$/services/disease_detection_service.py" afterDir="false" />
13
  </list>
14
  <option name="SHOW_DIALOG" value="false" />
@@ -131,14 +129,6 @@
131
  <workItem from="1730397485849" duration="22781000" />
132
  <workItem from="1730454506390" duration="12672000" />
133
  </task>
134
- <task id="LOCAL-00076" summary="update space">
135
- <option name="closed" value="true" />
136
- <created>1730402280098</created>
137
- <option name="number" value="00076" />
138
- <option name="presentableId" value="LOCAL-00076" />
139
- <option name="project" value="LOCAL" />
140
- <updated>1730402280098</updated>
141
- </task>
142
  <task id="LOCAL-00077" summary="update space">
143
  <option name="closed" value="true" />
144
  <created>1730402500058</created>
@@ -523,7 +513,15 @@
523
  <option name="project" value="LOCAL" />
524
  <updated>1730490013545</updated>
525
  </task>
526
- <option name="localTasksCounter" value="125" />
 
 
 
 
 
 
 
 
527
  <servers />
528
  </component>
529
  <component name="TypeScriptGeneratedFilesManager">
 
5
  </component>
6
  <component name="ChangeListManager">
7
  <list default="true" id="27c9ae1a-a6fa-4472-8bcd-a7087620894b" name="Changes" comment="update space">
 
8
  <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
9
+ <change beforePath="$PROJECT_DIR$/services/convert_model.py" beforeDir="false" />
 
10
  <change beforePath="$PROJECT_DIR$/services/disease_detection_service.py" beforeDir="false" afterPath="$PROJECT_DIR$/services/disease_detection_service.py" afterDir="false" />
11
  </list>
12
  <option name="SHOW_DIALOG" value="false" />
 
129
  <workItem from="1730397485849" duration="22781000" />
130
  <workItem from="1730454506390" duration="12672000" />
131
  </task>
 
 
 
 
 
 
 
 
132
  <task id="LOCAL-00077" summary="update space">
133
  <option name="closed" value="true" />
134
  <created>1730402500058</created>
 
513
  <option name="project" value="LOCAL" />
514
  <updated>1730490013545</updated>
515
  </task>
516
+ <task id="LOCAL-00125" summary="update space">
517
+ <option name="closed" value="true" />
518
+ <created>1730491745530</created>
519
+ <option name="number" value="00125" />
520
+ <option name="presentableId" value="LOCAL-00125" />
521
+ <option name="project" value="LOCAL" />
522
+ <updated>1730491745530</updated>
523
+ </task>
524
+ <option name="localTasksCounter" value="126" />
525
  <servers />
526
  </component>
527
  <component name="TypeScriptGeneratedFilesManager">
services/convert_model.py DELETED
@@ -1,12 +0,0 @@
1
- # convert_model.py
2
-
3
- import tensorflow as tf
4
-
5
- MODEL_PATH = "models/diseases.h5"
6
- NEW_MODEL_PATH = "models/Final_Chicken_disease_model"
7
-
8
- # Load the .h5 model
9
- model = tf.keras.models.load_model(MODEL_PATH)
10
-
11
- # Save it in the SavedModel format
12
- model.save(NEW_MODEL_PATH)
 
 
 
 
 
 
 
 
 
 
 
 
 
services/disease_detection_service.py CHANGED
@@ -4,6 +4,7 @@ import os
4
  import logging
5
  import threading
6
  import tensorflow as tf
 
7
  import cv2
8
  import numpy as np
9
  from keras.models import load_model
@@ -19,6 +20,7 @@ logger = logging.getLogger(__name__)
19
  # Load Hugging Face API token for secure model access
20
  HF_TOKEN = os.environ.get('HF_Token')
21
  if HF_TOKEN:
 
22
  login(token=HF_TOKEN, add_to_git_credential=True)
23
  logger.info("Hugging Face login successful.")
24
  else:
@@ -32,8 +34,12 @@ logger.info("Configuration loaded from config.ini.")
32
  # Configure TensorFlow for GPU and mixed precision if supported
33
  gpu_devices = tf.config.list_physical_devices('GPU')
34
  if gpu_devices:
 
35
  for gpu in gpu_devices:
 
36
  tf.config.experimental.set_memory_growth(gpu, True)
 
 
37
  if tf.config.experimental.get_device_details(gpu_devices[0]).get('compute_capability', (0, 0))[0] >= 7:
38
  from tensorflow.keras import mixed_precision
39
  policy = mixed_precision.Policy('mixed_float16')
@@ -42,36 +48,38 @@ if gpu_devices:
42
  else:
43
  logger.info("No GPU detected, using CPU without mixed precision.")
44
 
 
 
 
 
45
  # Global model variables and threading event for synchronization
46
  disease_model, auth_model = None, None
47
  llama_model, llama_tokenizer = None, None
48
  model_loading_event = threading.Event()
49
 
50
- # Function to load the disease detection model
51
- def load_disease_model():
52
- """Load the disease detection model."""
53
  try:
54
- model_path = config.get('MODELS', 'DISEASE_MODEL_PATH', fallback="models/diseases.h5")
55
- device = tf.config.list_logical_devices('GPU')[0] if gpu_devices else tf.config.list_logical_devices('CPU')[0]
56
- with tf.device(device.name):
57
- model = load_model(model_path, compile=True)
58
- logger.info(f"Disease detection model loaded successfully on {device.name}.")
59
  return model
60
  except Exception as e:
61
- logger.error("Error loading disease detection model", exc_info=True)
62
- raise RuntimeError("Failed to load disease detection model") from e
 
 
 
 
 
 
63
 
64
  # Function to load the authentication model
65
  def load_auth_model():
66
- """Load the authentication model to verify poultry images."""
67
- try:
68
- auth_model_path = config.get('MODELS', 'AUTH_MODEL_PATH', fallback="models/auth.h5")
69
- auth_model = load_model(auth_model_path, compile=True)
70
- logger.info("Authentication model loaded successfully.")
71
- return auth_model
72
- except Exception as e:
73
- logger.error("Error loading authentication model", exc_info=True)
74
- raise RuntimeError("Failed to load authentication model") from e
75
 
76
  # Function to load the Llama 3.2 model for language generation
77
  def load_llama_model():
@@ -81,8 +89,11 @@ def load_llama_model():
81
  logger.info("Loading Llama 3.2 model and tokenizer using PyTorch-compatible model.")
82
  model_name = "meta-llama/Llama-3.2-1B"
83
 
 
84
  llama_tokenizer = AutoTokenizer.from_pretrained(model_name)
85
- llama_model = AutoModelForCausalLM.from_pretrained(model_name)
 
 
86
 
87
  # Add a padding token if it's missing
88
  if llama_tokenizer.pad_token is None:
@@ -91,11 +102,11 @@ def load_llama_model():
91
  llama_model.resize_token_embeddings(len(llama_tokenizer))
92
 
93
  logger.info("Llama model and tokenizer loaded successfully.")
94
- model_loading_event.set()
95
  return llama_model, llama_tokenizer
96
  except Exception as e:
97
  logger.error("Failed to load Llama model", exc_info=True)
98
- model_loading_event.set()
99
  raise RuntimeError("Failed to load the Llama 3.2 model. Verify compatibility.")
100
 
101
  # Disease mappings and recommended treatments
@@ -108,79 +119,133 @@ recommendations = {
108
  3: 'Administer antibiotics as prescribed by a veterinarian and ensure biosecurity.'
109
  }
110
 
111
-
112
  class PoultryFarmBot:
113
  def __init__(self, disease_model, auth_model):
114
  self.disease_model = disease_model
115
  self.auth_model = auth_model
116
- logging.basicConfig(level=logging.INFO)
117
  self.logger = logging.getLogger(__name__)
 
118
 
119
  def preprocess_image(self, image: np.ndarray) -> np.ndarray:
120
  """Preprocess the input image for model prediction."""
121
  try:
 
 
122
  image = cv2.resize(image, (224, 224))
123
- return image / 255.0 # Normalize
 
 
 
 
124
  except Exception as e:
125
  self.logger.error("Error in image preprocessing", exc_info=True)
126
  raise ValueError("Invalid image format or empty image provided.")
127
 
128
  def generate_detailed_response(self, disease_name: str, status: str, recommendation: str) -> str:
129
  """Generate detailed response using Llama model based on prediction."""
 
130
  prompt = (
131
  f"The detected disease is {disease_name}, classified as {status}. "
132
  f"Suggested action: {recommendation}. "
133
  f"Here is additional information on {disease_name}: causes, symptoms, and effective management."
134
  )
 
 
135
  response = self.llama_response(prompt)
 
 
136
  return response.replace(prompt, "").strip()
137
 
138
  def predict_disease(self, image: np.ndarray):
139
  """Predict disease from preprocessed image and provide detailed results."""
140
  try:
 
 
141
  preprocessed_image = self.preprocess_image(image)
142
 
143
  # Use auth_model to verify the image is poultry-related
 
144
  is_poultry = self.auth_model.predict(preprocessed_image.reshape(1, 224, 224, 3)).argmax()
 
145
  if is_poultry != 0:
146
  self.logger.info("Image not recognized as poultry.")
147
- return "Unknown Image", "N/A", "N/A", "Image not recognized as poultry.", None
148
-
149
- # Predict disease if image is verified
 
 
 
 
 
 
 
150
  prediction = self.disease_model.predict(preprocessed_image.reshape(1, 224, 224, 3))
151
  predicted_class = prediction.argmax()
 
152
  disease_name = name_disease.get(predicted_class, "Unknown disease")
153
  disease_status = status_map.get(predicted_class, "Unknown status")
154
  recommendation = recommendations.get(predicted_class, "No recommendation available")
155
- confidence = prediction[0][predicted_class] * 100
156
  self.logger.info(f"Disease Prediction: {disease_name} with {confidence:.2f}% confidence.")
157
 
158
  # Generate a detailed response using Llama model
159
  detailed_response = self.generate_detailed_response(disease_name, disease_status, recommendation)
160
- return detailed_response, disease_name, disease_status, recommendation, confidence
 
 
 
 
 
 
 
161
  except Exception as e:
162
  self.logger.error("Error in disease prediction", exc_info=True)
163
- return "Prediction failed.", None, None, None, None
 
 
 
 
 
 
164
 
165
  def llama_response(self, prompt: str) -> str:
166
  """Generate a response from the Llama model based on a prompt."""
167
  try:
 
168
  max_length = min(len(prompt) + 50, 512)
169
- inputs = llama_tokenizer(prompt, return_tensors="tf", max_length=max_length, truncation=True, padding=True)
 
 
 
 
170
  outputs = llama_model.generate(inputs["input_ids"], max_length=max_length, do_sample=True, temperature=0.7, top_p=0.9)
171
- return llama_tokenizer.decode(outputs[0], skip_special_tokens=True)
 
 
 
 
172
  except Exception as e:
173
  logger.error("Error generating response from Llama model", exc_info=True)
174
  return "Error generating detailed response."
175
 
176
  def diagnose_and_respond(self, image: np.ndarray):
177
  """Diagnose disease and provide comprehensive response."""
 
 
178
  if image is None or image.size == 0:
179
- return "Provide a valid poultry fecal image.", None, None, None, None
 
 
 
 
 
 
 
 
180
  return self.predict_disease(image)
181
 
182
-
183
  # Load models upon service startup
 
184
  disease_model = load_disease_model()
185
  auth_model = load_auth_model()
186
  llama_model, llama_tokenizer = load_llama_model()
 
4
  import logging
5
  import threading
6
  import tensorflow as tf
7
+ import torch
8
  import cv2
9
  import numpy as np
10
  from keras.models import load_model
 
20
  # Load Hugging Face API token for secure model access
21
  HF_TOKEN = os.environ.get('HF_Token')
22
  if HF_TOKEN:
23
+ # Login to Hugging Face using the token from environment variables
24
  login(token=HF_TOKEN, add_to_git_credential=True)
25
  logger.info("Hugging Face login successful.")
26
  else:
 
34
  # Configure TensorFlow for GPU and mixed precision if supported
35
  gpu_devices = tf.config.list_physical_devices('GPU')
36
  if gpu_devices:
37
+ logger.info(f"Number of GPUs found: {len(gpu_devices)}")
38
  for gpu in gpu_devices:
39
+ # Enable memory growth to prevent TensorFlow from allocating all GPU memory at once
40
  tf.config.experimental.set_memory_growth(gpu, True)
41
+ logger.info(f"Enabled memory growth for GPU: {gpu.name}")
42
+ # Enable mixed precision if GPU has sufficient compute capability
43
  if tf.config.experimental.get_device_details(gpu_devices[0]).get('compute_capability', (0, 0))[0] >= 7:
44
  from tensorflow.keras import mixed_precision
45
  policy = mixed_precision.Policy('mixed_float16')
 
48
  else:
49
  logger.info("No GPU detected, using CPU without mixed precision.")
50
 
51
+ # Check if GPU is available for PyTorch
52
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
53
+ logger.info(f"Using device for PyTorch: {device}")
54
+
55
  # Global model variables and threading event for synchronization
56
  disease_model, auth_model = None, None
57
  llama_model, llama_tokenizer = None, None
58
  model_loading_event = threading.Event()
59
 
60
+ # Utility function to load models
61
+ def load_model_util(model_path, model_name):
62
+ """Load and compile a Keras model from the provided path."""
63
  try:
64
+ logger.info(f"Loading {model_name} from path: {model_path}")
65
+ model = load_model(model_path, compile=True)
66
+ logger.info(f"{model_name} loaded successfully.")
 
 
67
  return model
68
  except Exception as e:
69
+ logger.error(f"Error loading {model_name}", exc_info=True)
70
+ raise RuntimeError(f"Failed to load {model_name}") from e
71
+
72
+ # Function to load the disease detection model
73
+ def load_disease_model():
74
+ # Load the disease detection model from the configured path
75
+ model_path = config.get('MODELS', 'DISEASE_MODEL_PATH', fallback="models/diseases.h5")
76
+ return load_model_util(model_path, "Disease detection model")
77
 
78
  # Function to load the authentication model
79
  def load_auth_model():
80
+ # Load the authentication model from the configured path
81
+ auth_model_path = config.get('MODELS', 'AUTH_MODEL_PATH', fallback="models/auth.h5")
82
+ return load_model_util(auth_model_path, "Authentication model")
 
 
 
 
 
 
83
 
84
  # Function to load the Llama 3.2 model for language generation
85
  def load_llama_model():
 
89
  logger.info("Loading Llama 3.2 model and tokenizer using PyTorch-compatible model.")
90
  model_name = "meta-llama/Llama-3.2-1B"
91
 
92
+ # Load the tokenizer and model from Hugging Face
93
  llama_tokenizer = AutoTokenizer.from_pretrained(model_name)
94
+ logger.info("Tokenizer loaded successfully.")
95
+ llama_model = AutoModelForCausalLM.from_pretrained(model_name).to(device)
96
+ logger.info("Model loaded successfully.")
97
 
98
  # Add a padding token if it's missing
99
  if llama_tokenizer.pad_token is None:
 
102
  llama_model.resize_token_embeddings(len(llama_tokenizer))
103
 
104
  logger.info("Llama model and tokenizer loaded successfully.")
105
+ model_loading_event.set() # Signal that the model has been loaded
106
  return llama_model, llama_tokenizer
107
  except Exception as e:
108
  logger.error("Failed to load Llama model", exc_info=True)
109
+ model_loading_event.set() # Signal that model loading failed
110
  raise RuntimeError("Failed to load the Llama 3.2 model. Verify compatibility.")
111
 
112
  # Disease mappings and recommended treatments
 
119
  3: 'Administer antibiotics as prescribed by a veterinarian and ensure biosecurity.'
120
  }
121
 
 
122
  class PoultryFarmBot:
123
  def __init__(self, disease_model, auth_model):
124
  self.disease_model = disease_model
125
  self.auth_model = auth_model
 
126
  self.logger = logging.getLogger(__name__)
127
+ self.logger.info("PoultryFarmBot initialized with provided models.")
128
 
129
  def preprocess_image(self, image: np.ndarray) -> np.ndarray:
130
  """Preprocess the input image for model prediction."""
131
  try:
132
+ self.logger.info(f"Original image shape: {image.shape}")
133
+ # Resize the image to the required input size for the model
134
  image = cv2.resize(image, (224, 224))
135
+ self.logger.info(f"Image resized to: {image.shape}")
136
+ # Normalize pixel values to be between 0 and 1
137
+ image = image / 255.0
138
+ self.logger.info("Image normalized for model input.")
139
+ return image
140
  except Exception as e:
141
  self.logger.error("Error in image preprocessing", exc_info=True)
142
  raise ValueError("Invalid image format or empty image provided.")
143
 
144
  def generate_detailed_response(self, disease_name: str, status: str, recommendation: str) -> str:
145
  """Generate detailed response using Llama model based on prediction."""
146
+ # Create a prompt with detailed information about the disease
147
  prompt = (
148
  f"The detected disease is {disease_name}, classified as {status}. "
149
  f"Suggested action: {recommendation}. "
150
  f"Here is additional information on {disease_name}: causes, symptoms, and effective management."
151
  )
152
+ self.logger.info(f"Generated prompt for Llama model: {prompt}")
153
+ # Use the Llama model to generate a more detailed response
154
  response = self.llama_response(prompt)
155
+ self.logger.info("Generated detailed response from Llama model.")
156
+ # Remove the original prompt from the response and return only the generated text
157
  return response.replace(prompt, "").strip()
158
 
159
  def predict_disease(self, image: np.ndarray):
160
  """Predict disease from preprocessed image and provide detailed results."""
161
  try:
162
+ # Preprocess the image for prediction
163
+ self.logger.info("Starting image preprocessing for disease prediction.")
164
  preprocessed_image = self.preprocess_image(image)
165
 
166
  # Use auth_model to verify the image is poultry-related
167
+ self.logger.info("Verifying if the image is poultry-related.")
168
  is_poultry = self.auth_model.predict(preprocessed_image.reshape(1, 224, 224, 3)).argmax()
169
+ self.logger.info(f"Auth model prediction result: {is_poultry}")
170
  if is_poultry != 0:
171
  self.logger.info("Image not recognized as poultry.")
172
+ return {
173
+ "message": "Image not recognized as poultry.",
174
+ "disease_name": "N/A",
175
+ "status": "N/A",
176
+ "recommendation": "N/A",
177
+ "confidence": None
178
+ }
179
+
180
+ # Predict disease if image is verified as poultry
181
+ self.logger.info("Predicting disease from the image.")
182
  prediction = self.disease_model.predict(preprocessed_image.reshape(1, 224, 224, 3))
183
  predicted_class = prediction.argmax()
184
+ self.logger.info(f"Disease model prediction result: {predicted_class}")
185
  disease_name = name_disease.get(predicted_class, "Unknown disease")
186
  disease_status = status_map.get(predicted_class, "Unknown status")
187
  recommendation = recommendations.get(predicted_class, "No recommendation available")
188
+ confidence = float(prediction[0][predicted_class] * 100)
189
  self.logger.info(f"Disease Prediction: {disease_name} with {confidence:.2f}% confidence.")
190
 
191
  # Generate a detailed response using Llama model
192
  detailed_response = self.generate_detailed_response(disease_name, disease_status, recommendation)
193
+ self.logger.info("Generated detailed response for disease prediction.")
194
+ return {
195
+ "message": detailed_response,
196
+ "disease_name": disease_name,
197
+ "status": disease_status,
198
+ "recommendation": recommendation,
199
+ "confidence": confidence
200
+ }
201
  except Exception as e:
202
  self.logger.error("Error in disease prediction", exc_info=True)
203
+ return {
204
+ "message": "Prediction failed.",
205
+ "disease_name": None,
206
+ "status": None,
207
+ "recommendation": None,
208
+ "confidence": None
209
+ }
210
 
211
  def llama_response(self, prompt: str) -> str:
212
  """Generate a response from the Llama model based on a prompt."""
213
  try:
214
+ # Limit the maximum length of the generated response
215
  max_length = min(len(prompt) + 50, 512)
216
+ self.logger.info(f"Generating response with max length: {max_length}")
217
+ # Tokenize the input prompt
218
+ inputs = llama_tokenizer(prompt, return_tensors="pt", max_length=max_length, truncation=True, padding=True).to(device)
219
+ self.logger.info("Input prompt tokenized successfully.")
220
+ # Generate a response using the Llama model
221
  outputs = llama_model.generate(inputs["input_ids"], max_length=max_length, do_sample=True, temperature=0.7, top_p=0.9)
222
+ self.logger.info("Response generated by Llama model.")
223
+ # Decode the generated response into a readable string
224
+ response = llama_tokenizer.decode(outputs[0], skip_special_tokens=True)
225
+ self.logger.info("Response decoded successfully.")
226
+ return response
227
  except Exception as e:
228
  logger.error("Error generating response from Llama model", exc_info=True)
229
  return "Error generating detailed response."
230
 
231
  def diagnose_and_respond(self, image: np.ndarray):
232
  """Diagnose disease and provide comprehensive response."""
233
+ # Check if the provided image is valid
234
+ self.logger.info("Starting diagnosis process.")
235
  if image is None or image.size == 0:
236
+ self.logger.warning("Invalid image provided for diagnosis.")
237
+ return {
238
+ "message": "Provide a valid poultry fecal image.",
239
+ "disease_name": None,
240
+ "status": None,
241
+ "recommendation": None,
242
+ "confidence": None
243
+ }
244
+ # Predict disease from the provided image
245
  return self.predict_disease(image)
246
 
 
247
  # Load models upon service startup
248
+ logger.info("Loading models for disease detection service.")
249
  disease_model = load_disease_model()
250
  auth_model = load_auth_model()
251
  llama_model, llama_tokenizer = load_llama_model()