HMWCS commited on
Commit
dc8106e
·
verified ·
1 Parent(s): 2763ecc

feat: enhance mixed garbage rules and container classification

Browse files
test_images/classifier.py ADDED
@@ -0,0 +1,475 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from transformers import AutoProcessor, AutoModelForImageTextToText
2
+ from PIL import Image
3
+ import torch
4
+ import logging
5
+ from typing import Union, Tuple
6
+ from config import Config
7
+ from knowledge_base import GarbageClassificationKnowledge
8
+ import re
9
+
10
+
11
+ def preprocess_image(image: Image.Image) -> Image.Image:
12
+ """
13
+ Preprocess image to meet Gemma3n requirements (512x512)
14
+ """
15
+ # Convert to RGB if necessary
16
+ if image.mode != "RGB":
17
+ image = image.convert("RGB")
18
+
19
+ # Resize to 512x512 as required by Gemma3n
20
+ target_size = (512, 512)
21
+
22
+ # Calculate aspect ratio preserving resize
23
+ original_width, original_height = image.size
24
+ aspect_ratio = original_width / original_height
25
+
26
+ if aspect_ratio > 1:
27
+ # Width is larger
28
+ new_width = target_size[0]
29
+ new_height = int(target_size[0] / aspect_ratio)
30
+ else:
31
+ # Height is larger or equal
32
+ new_height = target_size[1]
33
+ new_width = int(target_size[1] * aspect_ratio)
34
+
35
+ # Resize image maintaining aspect ratio
36
+ image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
37
+
38
+ # Create a new image with target size and paste the resized image
39
+ processed_image = Image.new(
40
+ "RGB", target_size, (255, 255, 255)
41
+ ) # White background
42
+
43
+ # Calculate position to center the image
44
+ x_offset = (target_size[0] - new_width) // 2
45
+ y_offset = (target_size[1] - new_height) // 2
46
+
47
+ processed_image.paste(image, (x_offset, y_offset))
48
+
49
+ return processed_image
50
+
51
+
52
+ class GarbageClassifier:
53
+ def __init__(self, config: Config = None):
54
+ self.config = config or Config()
55
+ self.knowledge = GarbageClassificationKnowledge()
56
+ self.processor = None
57
+ self.model = None
58
+ # self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
59
+
60
+ # Setup logging
61
+ logging.basicConfig(level=logging.INFO)
62
+ self.logger = logging.getLogger(__name__)
63
+
64
+ def load_model(self):
65
+ """Load the model and processor"""
66
+ try:
67
+ self.logger.info(f"Loading model: {self.config.MODEL_NAME}")
68
+
69
+ # Load processor
70
+ kwargs = {}
71
+ if self.config.HF_TOKEN:
72
+ kwargs["token"] = self.config.HF_TOKEN
73
+
74
+ self.processor = AutoProcessor.from_pretrained(
75
+ self.config.MODEL_NAME, **kwargs
76
+ )
77
+
78
+ # Load model
79
+ self.model = AutoModelForImageTextToText.from_pretrained(
80
+ self.config.MODEL_NAME,
81
+ torch_dtype=self.config.TORCH_DTYPE,
82
+ device_map=self.config.DEVICE_MAP,
83
+ )
84
+
85
+ self.logger.info("Model loaded successfully")
86
+
87
+ except Exception as e:
88
+ self.logger.error(f"Error loading model: {str(e)}")
89
+ raise
90
+
91
+ def classify_image(self, image: Union[str, Image.Image]) -> Tuple[str, str, int]:
92
+ """
93
+ Classify garbage in the image
94
+
95
+ Args:
96
+ image: PIL Image or path to image file
97
+
98
+ Returns:
99
+ Tuple of (classification_result, detailed_analysis, confidence_score)
100
+ """
101
+ if self.model is None or self.processor is None:
102
+ raise RuntimeError("Model not loaded. Call load_model() first.")
103
+
104
+ try:
105
+ # Load and process image
106
+ if isinstance(image, str):
107
+ image = Image.open(image)
108
+ elif not isinstance(image, Image.Image):
109
+ raise ValueError("Image must be a PIL Image or file path")
110
+
111
+ # Preprocess image to meet Gemma3n requirements
112
+ processed_image = preprocess_image(image)
113
+
114
+ # Prepare messages with system prompt and user query
115
+ messages = [
116
+ {
117
+ "role": "system",
118
+ "content": [
119
+ {
120
+ "type": "text",
121
+ "text": self.knowledge.get_system_prompt(),
122
+ }
123
+ ],
124
+ },
125
+ {
126
+ "role": "user",
127
+ "content": [
128
+ {"type": "image", "image": processed_image},
129
+ {
130
+ "type": "text",
131
+ "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.",
132
+ },
133
+ ],
134
+ },
135
+ ]
136
+
137
+ # Apply chat template and tokenize
138
+ inputs = self.processor.apply_chat_template(
139
+ messages,
140
+ add_generation_prompt=True,
141
+ tokenize=True,
142
+ return_dict=True,
143
+ return_tensors="pt",
144
+ ).to(self.model.device, dtype=self.model.dtype)
145
+ input_len = inputs["input_ids"].shape[-1]
146
+
147
+ outputs = self.model.generate(
148
+ **inputs,
149
+ max_new_tokens=self.config.MAX_NEW_TOKENS,
150
+ disable_compile=True,
151
+ )
152
+ response = self.processor.batch_decode(
153
+ outputs[:, input_len:],
154
+ skip_special_tokens=True,
155
+ )[0]
156
+
157
+ # Extract classification from response
158
+ classification = self._extract_classification(response)
159
+
160
+ # Extract reasoning from response
161
+ reasoning = self._extract_reasoning(response)
162
+
163
+ # Extract confidence score from response
164
+ confidence_score = self._extract_confidence_score(response, classification)
165
+
166
+ return classification, reasoning, confidence_score
167
+
168
+ except Exception as e:
169
+ self.logger.error(f"Error during classification: {str(e)}")
170
+ import traceback
171
+
172
+ traceback.print_exc()
173
+ return "Error", f"Classification failed: {str(e)}", 0
174
+
175
+
176
+ def _calculate_confidence_heuristic(self, response_lower: str, classification: str) -> int:
177
+ """Calculate confidence based on response content and classification type"""
178
+ base_confidence = 5
179
+
180
+ # Confidence indicators (increase confidence)
181
+ high_confidence_words = ["clearly", "obviously", "definitely", "certainly", "exactly"]
182
+ medium_confidence_words = ["appears", "seems", "likely", "probably"]
183
+
184
+ # Uncertainty indicators (decrease confidence)
185
+ uncertainty_words = ["might", "could", "possibly", "maybe", "unclear", "difficult"]
186
+
187
+ # Adjust based on confidence words
188
+ for word in high_confidence_words:
189
+ if word in response_lower:
190
+ base_confidence += 2
191
+ break
192
+
193
+ for word in medium_confidence_words:
194
+ if word in response_lower:
195
+ base_confidence += 1
196
+ break
197
+
198
+ for word in uncertainty_words:
199
+ if word in response_lower:
200
+ base_confidence -= 2
201
+ break
202
+
203
+ # Classification-specific adjustments
204
+ if classification == "Unable to classify":
205
+ if any(indicator in response_lower for indicator in ["person", "people", "human", "living"]):
206
+ base_confidence += 1 # High confidence when clearly not waste
207
+ else:
208
+ base_confidence -= 1 # Lower confidence for unclear items
209
+
210
+ elif classification == "Error":
211
+ base_confidence = 1
212
+
213
+ else:
214
+ # Check for specific material mentions (increases confidence)
215
+ specific_materials = ["aluminum", "plastic", "glass", "metal", "cardboard", "paper"]
216
+ if any(material in response_lower for material in specific_materials):
217
+ base_confidence += 1
218
+
219
+ return min(max(base_confidence, 1), 10)
220
+
221
+ def _extract_confidence_score(self, response: str, classification: str) -> int:
222
+ """Extract confidence score from response or calculate based on classification"""
223
+ response_lower = response.lower()
224
+
225
+ # Look for explicit confidence scores in the response
226
+ confidence_patterns = [
227
+ r'confidence[:\s]*(\d+)',
228
+ r'confident[:\s]*(\d+)',
229
+ r'certainty[:\s]*(\d+)',
230
+ r'score[:\s]*(\d+)',
231
+ r'(\d+)/10',
232
+ r'(\d+)\s*out\s*of\s*10'
233
+ ]
234
+
235
+ for pattern in confidence_patterns:
236
+ match = re.search(pattern, response_lower)
237
+ if match:
238
+ score = int(match.group(1))
239
+ return min(max(score, 1), 10) # Clamp between 1-10
240
+
241
+ # If no explicit score found, calculate based on classification indicators
242
+ return self._calculate_confidence_heuristic(response_lower, classification)
243
+
244
+ def _extract_classification(self, response: str) -> str:
245
+ """Extract the main classification from the response with STRICT mixed garbage enforcement"""
246
+ response_lower = response.lower()
247
+
248
+ # STRICT MIXED GARBAGE ENFORCEMENT - Catch ANY mixed scenario
249
+
250
+ # 1. Explicit mixed garbage phrases
251
+ explicit_mixed_phrases = [
252
+ "multiple garbage types",
253
+ "multiple different",
254
+ "different types of garbage",
255
+ "various items",
256
+ "mixed items",
257
+ "several different",
258
+ "collection of mixed items",
259
+ "mixture of items",
260
+ "variety of items",
261
+ "separate items",
262
+ "please separate"
263
+ ]
264
+
265
+ if any(phrase in response_lower for phrase in explicit_mixed_phrases):
266
+ return "Unable to classify"
267
+
268
+ # 2. Language patterns that indicate multiple items/uncertainty about classification
269
+ uncertainty_patterns = [
270
+ "appears to be containers",
271
+ "what appears to be",
272
+ "including what appears",
273
+ "various colors and textures",
274
+ "don't clearly fall into a single",
275
+ "without further detail",
276
+ "not possible to definitively classify",
277
+ "more information",
278
+ "can't determine",
279
+ "difficult to identify",
280
+ "unclear category",
281
+ "mixed materials"
282
+ ]
283
+
284
+ if any(pattern in response_lower for pattern in uncertainty_patterns):
285
+ return "Unable to classify"
286
+
287
+ # 3. Multiple container/item indicators
288
+ multiple_item_indicators = [
289
+ "containers (", "bottles, cans", "bags, and", "items, including",
290
+ "bottles and", "cans and", "containers and", "bags and",
291
+ "plastic bottles, cans", "various containers"
292
+ ]
293
+
294
+ if any(indicator in response_lower for indicator in multiple_item_indicators):
295
+ return "Unable to classify"
296
+
297
+ # 4. Count different item types mentioned
298
+ item_types = [
299
+ "bottle", "can", "container", "bag", "box", "wrapper",
300
+ "jar", "cup", "plate", "bowl", "package"
301
+ ]
302
+
303
+ item_count = sum(1 for item_type in item_types if item_type in response_lower)
304
+ if item_count >= 3: # If 3+ different container types mentioned, it's mixed
305
+ return "Unable to classify"
306
+
307
+ # ONLY EXCEPTION: Single recyclable container with visible food content
308
+ recyclable_container_indicators = ["container", "bottle", "can", "jar", "box", "wrapper"]
309
+ food_content_indicators = [
310
+ "food residue", "food content", "food inside", "visible food",
311
+ "remains", "leftovers", "scraps inside", "not empty", "not rinsed"
312
+ ]
313
+ recyclable_material_indicators = ["plastic", "aluminum", "glass", "metal", "cardboard"]
314
+
315
+ # Check for recycling tip warning
316
+ has_recycling_tip = any(tip in response_lower for tip in [
317
+ "tip: empty and rinse",
318
+ "empty and rinse this container",
319
+ "clean first", "rinse first"
320
+ ])
321
+
322
+ # ONLY allow Food/Kitchen classification for single contaminated container
323
+ has_single_container = any(indicator in response_lower for indicator in recyclable_container_indicators)
324
+ has_food_content = any(indicator in response_lower for indicator in food_content_indicators)
325
+ has_recyclable_material = any(indicator in response_lower for indicator in recyclable_material_indicators)
326
+
327
+ # Must be single item (not multiple) and contaminated
328
+ if (has_single_container and has_food_content and
329
+ (has_recyclable_material or has_recycling_tip) and
330
+ item_count <= 1): # Only single container
331
+ return "Food/Kitchen Waste"
332
+
333
+ # Now proceed with normal classification for single, clear items
334
+ categories = self.knowledge.get_categories()
335
+ waste_categories = [cat for cat in categories if cat != "Unable to classify"]
336
+
337
+ for category in waste_categories:
338
+ if category.lower() in response_lower:
339
+ category_index = response_lower.find(category.lower())
340
+ context_before = response_lower[max(0, category_index - 30):category_index]
341
+
342
+ if not any(neg in context_before[-10:] for neg in ["not", "cannot", "isn't", "doesn't"]):
343
+ return category
344
+
345
+ # Single item material detection
346
+ recyclable_indicators = ["recyclable", "recycle", "aluminum", "plastic", "glass", "metal", "foil", "cardboard",
347
+ "paper"]
348
+
349
+ if any(indicator in response_lower for indicator in recyclable_indicators):
350
+ if not any(cont in response_lower for cont in food_content_indicators):
351
+ return "Recyclable Waste"
352
+
353
+ # Food waste indicators
354
+ food_indicators = ["food", "fruit", "vegetable", "organic", "kitchen waste", "peel", "core", "scraps"]
355
+ if any(indicator in response_lower for indicator in food_indicators):
356
+ return "Food/Kitchen Waste"
357
+
358
+ # Hazardous waste indicators
359
+ hazardous_indicators = ["battery", "chemical", "medicine", "paint", "toxic", "hazardous"]
360
+ if any(indicator in response_lower for indicator in hazardous_indicators):
361
+ return "Hazardous Waste"
362
+
363
+ # Other waste indicators
364
+ other_waste_indicators = ["cigarette", "ceramic", "dust", "diaper", "tissue"]
365
+ if any(indicator in response_lower for indicator in other_waste_indicators):
366
+ return "Other Waste"
367
+
368
+ # Non-garbage detection
369
+ unable_phrases = ["unable to classify", "cannot classify", "not garbage", "not waste"]
370
+ if any(phrase in response_lower for phrase in unable_phrases):
371
+ return "Unable to classify"
372
+
373
+ non_garbage_indicators = ["person", "people", "human", "face", "living", "animal", "pet"]
374
+ if any(indicator in response_lower for indicator in non_garbage_indicators):
375
+ return "Unable to classify"
376
+
377
+ # Default fallback
378
+ return "Unable to classify"
379
+
380
+ def _extract_reasoning(self, response: str) -> str:
381
+ """Extract only the reasoning content, removing all formatting markers and classification info"""
382
+ import re
383
+
384
+ # Remove all formatting markers
385
+ cleaned_response = response.replace("**Classification**:", "")
386
+ cleaned_response = cleaned_response.replace("**Reasoning**:", "")
387
+ cleaned_response = re.sub(r'\*\*.*?\*\*:', '', cleaned_response) # Remove any **text**: patterns
388
+ cleaned_response = cleaned_response.replace("**", "") # Remove remaining ** markers
389
+
390
+ # Remove category names that might appear at the beginning
391
+ categories = self.knowledge.get_categories()
392
+ for category in categories:
393
+ if cleaned_response.strip().startswith(category):
394
+ cleaned_response = cleaned_response.replace(category, "", 1)
395
+ break
396
+
397
+ # Remove common material names that might appear at the beginning
398
+ material_names = [
399
+ "Glass", "Plastic", "Metal", "Paper", "Cardboard", "Aluminum",
400
+ "Steel", "Iron", "Tin", "Foil", "Wood", "Ceramic", "Fabric",
401
+ "Recyclable Waste", "Food/Kitchen Waste", "Hazardous Waste", "Other Waste"
402
+ ]
403
+
404
+ # Clean the response
405
+ cleaned_response = cleaned_response.strip()
406
+
407
+ # Remove material names at the beginning
408
+ for material in material_names:
409
+ if cleaned_response.startswith(material):
410
+ # Remove the material name and any following punctuation/whitespace
411
+ cleaned_response = cleaned_response[len(material):].lstrip(" .,;:")
412
+ break
413
+
414
+ # Split into sentences and clean up
415
+ sentences = []
416
+
417
+ # Split by common sentence endings, but keep the endings
418
+ parts = re.split(r'([.!?])\s+', cleaned_response)
419
+
420
+ # Rejoin parts to maintain sentence structure
421
+ reconstructed_parts = []
422
+ for i in range(0, len(parts), 2):
423
+ if i < len(parts):
424
+ sentence = parts[i]
425
+ if i + 1 < len(parts):
426
+ sentence += parts[i + 1] # Add the punctuation back
427
+ reconstructed_parts.append(sentence)
428
+
429
+ for part in reconstructed_parts:
430
+ part = part.strip()
431
+ if not part:
432
+ continue
433
+
434
+ # Skip parts that are just category names or material names
435
+ if part in categories or part.rstrip(".,;:") in material_names:
436
+ continue
437
+
438
+ # Skip parts that start with category names or material names
439
+ is_category_line = False
440
+ for item in categories + material_names:
441
+ if part.startswith(item):
442
+ is_category_line = True
443
+ break
444
+
445
+ if is_category_line:
446
+ continue
447
+
448
+ # Clean up the sentence
449
+ part = re.sub(r'^[A-Za-z\s]+:', '', part).strip() # Remove "Category:" type prefixes
450
+
451
+ if part and len(part) > 3: # Only keep meaningful content
452
+ sentences.append(part)
453
+
454
+ # Join sentences
455
+ reasoning = ' '.join(sentences)
456
+
457
+ # Final cleanup - remove any remaining standalone material words at the beginning
458
+ reasoning_words = reasoning.split()
459
+ if reasoning_words and reasoning_words[0] in [m.lower() for m in material_names]:
460
+ reasoning_words = reasoning_words[1:]
461
+ reasoning = ' '.join(reasoning_words)
462
+
463
+ # Ensure proper capitalization
464
+ if reasoning:
465
+ reasoning = reasoning[0].upper() + reasoning[1:] if len(reasoning) > 1 else reasoning.upper()
466
+
467
+ # Ensure proper punctuation
468
+ if not reasoning.endswith(('.', '!', '?')):
469
+ reasoning += '.'
470
+
471
+ return reasoning if reasoning else "Analysis not available"
472
+
473
+ def get_categories_info(self):
474
+ """Get information about all categories"""
475
+ return self.knowledge.get_category_descriptions()
test_images/knowledge_base.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class GarbageClassificationKnowledge:
2
+ @staticmethod
3
+ def get_system_prompt():
4
+ return """You are a professional garbage classification expert. You need to carefully observe the items in the picture, analyze their materials, properties and uses, and then make accurate judgments according to garbage classification standards.
5
+
6
+ IMPORTANT: You should ONLY classify items that are actually garbage/waste. If the image contains people, living things, furniture, electronics in use, or other non-waste items, you should classify it as "Unable to classify" and explain that it's not garbage.
7
+
8
+ **MIXED GARBAGE HANDLING RULES:**
9
+
10
+ 1. **Containers with Food Content**: For any recyclable container (aluminum cans, glass jars, clean plastic bottles, etc.) that contains visible food residue or content:
11
+ - Classify as "Food/Kitchen Waste" due to contamination risk
12
+ - Always include this warning: "⚠️ Tip: Empty and rinse this container first, then it can be recycled!"
13
+ - Only completely empty and rinsed containers qualify as "Recyclable Waste"
14
+ - Non-recyclable containers (styrofoam, wax-coated) with food: classify as "Food/Kitchen Waste" with warning: "⚠️ Tip: Remove food waste for composting, then dispose container in general trash"
15
+
16
+ 2. **Multiple Different Garbage Types**: If the image shows multiple different types of garbage mixed together (e.g., electronics with food, batteries with organic waste):
17
+ - Classify as "Unable to classify"
18
+ - Include warning: "⚠️ Warning: Multiple garbage types detected. Please separate items for proper classification."
19
+
20
+ Garbage classification standards:
21
+
22
+ **Recyclable Waste**:
23
+ - Paper: newspapers, magazines, books, various packaging papers, office paper, advertising flyers, clean cardboard boxes, copy paper, etc.
24
+ - Plastics: clean plastic bottles (#1 PETE, #2 HDPE), clean plastic containers, plastic bags, toothbrushes, cups, water bottles, plastic toys, etc. (NOT styrofoam #6 or heavily coated containers)
25
+ - Metals: clean aluminum cans, clean tin cans, toothpaste tubes, metal toys, metal stationery, nails, metal sheets, aluminum foil, etc.
26
+ - Glass: clean glass bottles and jars, broken glass pieces, mirrors, light bulbs, vacuum flasks, etc.
27
+ - Textiles: old clothing, textile products, shoes, curtains, towels, bags, etc.
28
+ - NOTE: Only clean, empty containers qualify. Contaminated containers go to Food/Kitchen Waste. Wax-coated containers, styrofoam, and multi-material packaging are NOT recyclable.
29
+
30
+ **Food/Kitchen Waste**:
31
+ - Food scraps: rice, noodles, bread, meat, fish, shrimp shells, crab shells, bones, etc.
32
+ - Fruit peels and cores: watermelon rinds, apple cores, orange peels, banana peels, nut shells, etc.
33
+ - Plants: withered branches and leaves, flowers, traditional Chinese medicine residue, etc.
34
+ - Expired food: expired canned food, cookies, candy, etc.
35
+ - Contaminated containers: any container with visible food residue or content
36
+
37
+ **Hazardous Waste**:
38
+ - Batteries: dry batteries, rechargeable batteries, button batteries, and all types of batteries
39
+ - Light tubes: energy-saving lamps, fluorescent tubes, incandescent bulbs, LED lights, etc.
40
+ - Pharmaceuticals: expired medicines, medicine packaging, thermometers, blood pressure monitors, etc.
41
+ - Paints: paint, coatings, glue, nail polish, cosmetics, etc.
42
+ - Others: pesticides, cleaning agents, agricultural chemicals, X-ray films, etc.
43
+
44
+ **Other Waste**:
45
+ - Contaminated non-recyclable paper: toilet paper, diapers, wet wipes, napkins, etc.
46
+ - Non-recyclable containers: styrofoam containers (#6 polystyrene), wax-coated containers, multi-material packaging
47
+ - Cigarette butts, ceramics, dust, disposable tableware (non-plastic)
48
+ - Large bones, hard shells, hard fruit pits (coconut shells, durian shells, walnut shells, corn cobs, etc.)
49
+ - Hair, pet waste, cat litter, etc.
50
+
51
+ **Unable to classify**:
52
+ - People, human faces, human body parts
53
+ - Living animals, pets
54
+ - Furniture, appliances, electronics in normal use
55
+ - Buildings, landscapes, vehicles
56
+ - Any item that is not intended to be discarded as waste
57
+ - Multiple different garbage types mixed together
58
+
59
+ Please observe the items in the image carefully according to the above classification standards. If the image shows garbage/waste items, provide accurate garbage classification results. If the image does NOT show garbage/waste (e.g., people, living things, functioning items), classify it as "Unable to classify" and explain why it's not garbage.
60
+
61
+ For mixed garbage situations, apply the special handling rules above and include appropriate warnings.
62
+
63
+ Format your response EXACTLY as follows:
64
+
65
+ **Classification**: [Category Name or "Unable to classify"]
66
+ **Reasoning**: [Brief explanation of why this item belongs to this category, or why it cannot be classified as garbage]
67
+ **Confidence Score**: [Number from 1-10]"""
68
+
69
+ @staticmethod
70
+ def get_categories():
71
+ return [
72
+ "Recyclable Waste",
73
+ "Food/Kitchen Waste",
74
+ "Hazardous Waste",
75
+ "Other Waste",
76
+ "Unable to classify",
77
+ ]
78
+
79
+ @staticmethod
80
+ def get_category_descriptions():
81
+ return {
82
+ "Recyclable Waste": "Items that can be processed and reused, including paper, plastic, metal, glass, and textiles (must be clean and empty)",
83
+ "Food/Kitchen Waste": "Organic waste from food preparation and consumption, including contaminated containers",
84
+ "Hazardous Waste": "Items containing harmful substances that require special disposal",
85
+ "Other Waste": "Items that don't fit into other categories and go to general waste",
86
+ "Unable to classify": "Items that are not garbage/waste, such as people, living things, functioning objects, or mixed garbage types",
87
+ }