HMWCS commited on
Commit
f0a45ec
·
1 Parent(s): 010e055

feat: initial dev branch

Browse files
Files changed (2) hide show
  1. app.py +13 -9
  2. classifier.py +79 -6
app.py CHANGED
@@ -14,7 +14,6 @@ import os
14
  from classifier import GarbageClassifier
15
  from config import Config
16
 
17
-
18
  # Initialize classifier
19
  config = Config()
20
  classifier = GarbageClassifier(config)
@@ -30,14 +29,14 @@ def classify_garbage_impl(image):
30
  Actual classification implementation
31
  """
32
  if image is None:
33
- return "Please upload an image", "No image provided"
34
 
35
  try:
36
- classification, full_response = classifier.classify_image(image)
37
- return classification, full_response
 
38
  except Exception as e:
39
- return "Error", f"Classification failed: {str(e)}"
40
-
41
 
42
  # Apply GPU decorator based on environment
43
  if HF_SPACES:
@@ -78,6 +77,11 @@ with gr.Blocks(title="Garbage Classification System") as demo:
78
  placeholder="Upload an image and click classify",
79
  )
80
 
 
 
 
 
 
81
  full_response_output = gr.Textbox(
82
  label="Detailed Analysis",
83
  placeholder="Detailed reasoning will appear here",
@@ -102,15 +106,15 @@ with gr.Blocks(title="Garbage Classification System") as demo:
102
  classify_btn.click(
103
  fn=classify_garbage,
104
  inputs=image_input,
105
- outputs=[classification_output, full_response_output],
106
  )
107
 
108
  # Auto-classify on image upload
109
  image_input.change(
110
  fn=classify_garbage,
111
  inputs=image_input,
112
- outputs=[classification_output, full_response_output],
113
  )
114
 
115
  if __name__ == "__main__":
116
- demo.launch()
 
14
  from classifier import GarbageClassifier
15
  from config import Config
16
 
 
17
  # Initialize classifier
18
  config = Config()
19
  classifier = GarbageClassifier(config)
 
29
  Actual classification implementation
30
  """
31
  if image is None:
32
+ return "Please upload an image", "No image provided", "N/A"
33
 
34
  try:
35
+ classification, full_response, confidence_score = classifier.classify_image(image)
36
+ confidence_display = f"{confidence_score}/10"
37
+ return classification, full_response, confidence_display
38
  except Exception as e:
39
+ return "Error", f"Classification failed: {str(e)}", "0/10"
 
40
 
41
  # Apply GPU decorator based on environment
42
  if HF_SPACES:
 
77
  placeholder="Upload an image and click classify",
78
  )
79
 
80
+ confidence_output = gr.Textbox(
81
+ label="Confidence Score",
82
+ placeholder="Confidence score will appear here",
83
+ )
84
+
85
  full_response_output = gr.Textbox(
86
  label="Detailed Analysis",
87
  placeholder="Detailed reasoning will appear here",
 
106
  classify_btn.click(
107
  fn=classify_garbage,
108
  inputs=image_input,
109
+ outputs=[classification_output, full_response_output, confidence_output]
110
  )
111
 
112
  # Auto-classify on image upload
113
  image_input.change(
114
  fn=classify_garbage,
115
  inputs=image_input,
116
+ outputs=[classification_output, full_response_output, confidence_output]
117
  )
118
 
119
  if __name__ == "__main__":
120
+ demo.launch()
classifier.py CHANGED
@@ -5,6 +5,7 @@ import logging
5
  from typing import Union, Tuple
6
  from config import Config
7
  from knowledge_base import GarbageClassificationKnowledge
 
8
 
9
 
10
  class GarbageClassifier:
@@ -86,7 +87,7 @@ class GarbageClassifier:
86
 
87
  return processed_image
88
 
89
- def classify_image(self, image: Union[str, Image.Image]) -> Tuple[str, str]:
90
  """
91
  Classify garbage in the image
92
 
@@ -94,7 +95,7 @@ class GarbageClassifier:
94
  image: PIL Image or path to image file
95
 
96
  Returns:
97
- Tuple of (classification_result, detailed_analysis)
98
  """
99
  if self.model is None or self.processor is None:
100
  raise RuntimeError("Model not loaded. Call load_model() first.")
@@ -126,7 +127,7 @@ class GarbageClassifier:
126
  {"type": "image", "image": processed_image},
127
  {
128
  "type": "text",
129
- "text": "Please classify what you see in this image. If it shows garbage/waste items, classify them according to the garbage classification standards. If it shows people, living things, or other non-waste items, classify it as 'Unable to classify' and explain why it's not garbage.",
130
  },
131
  ],
132
  },
@@ -158,14 +159,87 @@ class GarbageClassifier:
158
  # Extract reasoning from response
159
  reasoning = self._extract_reasoning(response)
160
 
161
- return classification, reasoning
 
 
 
162
 
163
  except Exception as e:
164
  self.logger.error(f"Error during classification: {str(e)}")
165
  import traceback
166
 
167
  traceback.print_exc()
168
- return "Error", f"Classification failed: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
  def _extract_classification(self, response: str) -> str:
171
  """Extract the main classification from the response"""
@@ -267,7 +341,6 @@ class GarbageClassifier:
267
 
268
  def _extract_reasoning(self, response: str) -> str:
269
  """Extract only the reasoning content, removing all formatting markers and classification info"""
270
- import re
271
 
272
  # Remove all formatting markers
273
  cleaned_response = response.replace("**Classification**:", "")
 
5
  from typing import Union, Tuple
6
  from config import Config
7
  from knowledge_base import GarbageClassificationKnowledge
8
+ import re
9
 
10
 
11
  class GarbageClassifier:
 
87
 
88
  return processed_image
89
 
90
+ def classify_image(self, image: Union[str, Image.Image]) -> Tuple[str, str, int]:
91
  """
92
  Classify garbage in the image
93
 
 
95
  image: PIL Image or path to image file
96
 
97
  Returns:
98
+ Tuple of (classification_result, detailed_analysis, confidence_score)
99
  """
100
  if self.model is None or self.processor is None:
101
  raise RuntimeError("Model not loaded. Call load_model() first.")
 
127
  {"type": "image", "image": processed_image},
128
  {
129
  "type": "text",
130
+ "text": "Please classify what you see in this image. If it shows garbage/waste items, classify them according to the garbage classification standards. If it shows people, living things, or other non-waste items, classify it as 'Unable to classify' and explain why it's not garbage. Also provide a confidence score from 1-10 indicating how certain you are about your classification.",
131
  },
132
  ],
133
  },
 
159
  # Extract reasoning from response
160
  reasoning = self._extract_reasoning(response)
161
 
162
+ # Extract confidence score from response
163
+ confidence_score = self._extract_confidence_score(response, classification)
164
+
165
+ return classification, reasoning, confidence_score
166
 
167
  except Exception as e:
168
  self.logger.error(f"Error during classification: {str(e)}")
169
  import traceback
170
 
171
  traceback.print_exc()
172
+ return "Error", f"Classification failed: {str(e)}", 0
173
+
174
+
175
+ def _calculate_confidence_heuristic(self, response_lower: str, classification: str) -> int:
176
+ """Calculate confidence based on response content and classification type"""
177
+ base_confidence = 5
178
+
179
+ # Confidence indicators (increase confidence)
180
+ high_confidence_words = ["clearly", "obviously", "definitely", "certainly", "exactly"]
181
+ medium_confidence_words = ["appears", "seems", "likely", "probably"]
182
+
183
+ # Uncertainty indicators (decrease confidence)
184
+ uncertainty_words = ["might", "could", "possibly", "maybe", "unclear", "difficult"]
185
+
186
+ # Adjust based on confidence words
187
+ for word in high_confidence_words:
188
+ if word in response_lower:
189
+ base_confidence += 2
190
+ break
191
+
192
+ for word in medium_confidence_words:
193
+ if word in response_lower:
194
+ base_confidence += 1
195
+ break
196
+
197
+ for word in uncertainty_words:
198
+ if word in response_lower:
199
+ base_confidence -= 2
200
+ break
201
+
202
+ # Classification-specific adjustments
203
+ if classification == "Unable to classify":
204
+ if any(indicator in response_lower for indicator in ["person", "people", "human", "living"]):
205
+ base_confidence += 1 # High confidence when clearly not waste
206
+ else:
207
+ base_confidence -= 1 # Lower confidence for unclear items
208
+
209
+ elif classification == "Error":
210
+ base_confidence = 1
211
+
212
+ else:
213
+ # Check for specific material mentions (increases confidence)
214
+ specific_materials = ["aluminum", "plastic", "glass", "metal", "cardboard", "paper"]
215
+ if any(material in response_lower for material in specific_materials):
216
+ base_confidence += 1
217
+
218
+ return min(max(base_confidence, 1), 10)
219
+
220
+ def _extract_confidence_score(self, response: str, classification: str) -> int:
221
+ """Extract confidence score from response or calculate based on classification"""
222
+ response_lower = response.lower()
223
+
224
+ # Look for explicit confidence scores in the response
225
+ confidence_patterns = [
226
+ r'confidence[:\s]*(\d+)',
227
+ r'confident[:\s]*(\d+)',
228
+ r'certainty[:\s]*(\d+)',
229
+ r'score[:\s]*(\d+)',
230
+ r'(\d+)/10',
231
+ r'(\d+)\s*out\s*of\s*10'
232
+ ]
233
+
234
+ for pattern in confidence_patterns:
235
+ match = re.search(pattern, response_lower)
236
+ if match:
237
+ score = int(match.group(1))
238
+ return min(max(score, 1), 10) # Clamp between 1-10
239
+
240
+ # If no explicit score found, calculate based on classification indicators
241
+ return self._calculate_confidence_heuristic(response_lower, classification)
242
+
243
 
244
  def _extract_classification(self, response: str) -> str:
245
  """Extract the main classification from the response"""
 
341
 
342
  def _extract_reasoning(self, response: str) -> str:
343
  """Extract only the reasoning content, removing all formatting markers and classification info"""
 
344
 
345
  # Remove all formatting markers
346
  cleaned_response = response.replace("**Classification**:", "")