Nanny7 commited on
Commit
ecde677
·
1 Parent(s): 4544986

Package model repo: add README/inference, remove Space app files

Browse files
Files changed (5) hide show
  1. HF_SPACE_APP.py +0 -203
  2. README.md +48 -0
  3. app.py +0 -10
  4. inference.py +51 -0
  5. requirements.txt +1 -3
HF_SPACE_APP.py DELETED
@@ -1,203 +0,0 @@
1
- """
2
- Hugging Face Space - Waste Classification Demo
3
- Fast API-only inference, no local model loading.
4
- """
5
-
6
- import gradio as gr
7
- import os
8
- import requests
9
- import io
10
- from PIL import Image
11
-
12
- # Configuration
13
- MODEL_ID = "Ayushman0502/waste-classifier"
14
- HF_TOKEN = os.getenv("HF_TOKEN", "")
15
- API_URL = f"https://api-inference.huggingface.co/models/{MODEL_ID}"
16
-
17
- # Class labels
18
- CLASS_DISPLAY = {
19
- 'dry_waste': '♻️ Dry Waste',
20
- 'other_waste': '🔶 Other Waste',
21
- 'wet_waste': '🍃 Wet Waste',
22
- }
23
- CLASS_ACTIONS = {
24
- 'dry_waste': 'Can be recycled → Paper, plastic, metal recovery',
25
- 'other_waste': 'Needs special handling → Hazardous / e-waste processing',
26
- 'wet_waste': 'Compostable → Organic composting / biogas generation',
27
- }
28
-
29
- print("✅ Waste Classifier Space Ready")
30
-
31
-
32
- def predict_waste(image):
33
- """Classify waste via Hugging Face Inference API."""
34
- try:
35
- # Convert image to bytes
36
- img_bytes = io.BytesIO()
37
- image.save(img_bytes, format='JPEG')
38
- img_bytes.seek(0)
39
-
40
- # Call API
41
- headers = {"Authorization": f"Bearer {HF_TOKEN}"} if HF_TOKEN else {}
42
- response = requests.post(
43
- API_URL,
44
- headers=headers,
45
- data=img_bytes.getvalue(),
46
- timeout=20
47
- )
48
-
49
- if response.status_code != 200:
50
- msg = response.text if response.text else f"Status {response.status_code}"
51
- if "loading" in msg.lower():
52
- return "⏳ Model loading (first use). Retry in 30s.", None
53
- return f"❌ Error: {msg[:100]}", None
54
-
55
- # Parse response
56
- preds = response.json()
57
- if not isinstance(preds, list):
58
- return f"❌ Unexpected response format", None
59
-
60
- # Extract best prediction
61
- best = max(preds, key=lambda x: x.get('score', 0)) if preds else None
62
- if not best:
63
- return "❌ No predictions", None
64
-
65
- class_name = best['label'].lower()
66
- score = best['score'] * 100
67
-
68
- # Format output
69
- text = f"**{CLASS_DISPLAY.get(class_name, class_name)}**\n"
70
- text += f"Confidence: **{score:.1f}%**\n"
71
- text += f"Action: {CLASS_ACTIONS.get(class_name, 'N/A')}\n\n"
72
- text += "**All Scores:**\n"
73
-
74
- results = {}
75
- for p in preds:
76
- label = p['label'].lower()
77
- perc = p['score'] * 100
78
- results[CLASS_DISPLAY.get(label, label)] = round(perc, 1)
79
- text += f"{CLASS_DISPLAY.get(label, label)}: {perc:.1f}%\n"
80
-
81
- return text, results
82
-
83
- except requests.exceptions.Timeout:
84
- return "⏳ API timeout. Retry in 30s.", None
85
- except Exception as e:
86
- return f"❌ Error: {str(e)[:50]}", None
87
-
88
-
89
- # Create custom HTML for better styling
90
- HEADER_HTML = """
91
- <div style="text-align: center; margin-bottom: 30px;">
92
- <h1 style="color: #2c3e50; margin-bottom: 10px;">🌿 Waste Classification AI</h1>
93
- <p style="color: #7f8c8d; font-size: 16px;">
94
- Upload an image of waste to classify it as Dry, Wet, or Other waste
95
- </p>
96
- <p style="color: #95a5a6; font-size: 14px;">
97
- Powered by EfficientNetB0 • Supporting Circular Economy
98
- </p>
99
- </div>
100
- """
101
-
102
- FOOTER_HTML = """
103
- <div style="text-align: center; margin-top: 30px; padding-top: 20px; border-top: 1px solid #ecf0f1;">
104
- <p style="color: #7f8c8d; font-size: 13px;">
105
- 🔗 <a href="https://huggingface.co/Ayushman0502/waste-classifier" target="_blank">View Model Card</a> •
106
- <a href="https://github.com/ayushmansingh0502-hub/ML_MODEL" target="_blank">GitHub Repository</a>
107
- </p>
108
- <p style="color: #95a5a6; font-size: 12px;">
109
- For questions or feedback, please open an issue on GitHub
110
- </p>
111
- </div>
112
- """
113
-
114
- # Create Gradio interface with custom CSS
115
- with gr.Blocks(
116
- title="Waste Classifier",
117
- theme=gr.themes.Soft(),
118
- css="""
119
- .output-image {
120
- max-width: 400px;
121
- margin-left: auto;
122
- margin-right: auto;
123
- }
124
- """
125
- ) as demo:
126
- # Header
127
- gr.HTML(HEADER_HTML)
128
-
129
- # Main content
130
- with gr.Row():
131
- with gr.Column(scale=1):
132
- gr.Markdown("### 📸 Step 1: Upload Image")
133
- image_input = gr.Image(
134
- label="Upload or Drag & Drop a Waste Image",
135
- type="pil",
136
- sources=["upload", "webcam"],
137
- )
138
-
139
- with gr.Row():
140
- clear_btn = gr.ClearButton(image_input, value="Clear Image")
141
- submit_btn = gr.Button("🔍 Classify Waste", variant="primary", size="lg")
142
-
143
- with gr.Column(scale=1):
144
- gr.Markdown("### 📊 Step 2: View Results")
145
- output_text = gr.Textbox(
146
- label="Classification Result",
147
- lines=12,
148
- interactive=False,
149
- show_label=True,
150
- )
151
-
152
- # Chart for predictions
153
- gr.Markdown("### 📈 Confidence Distribution")
154
- chart = gr.BarChart(
155
- label="Confidence Scores",
156
- x="Waste Type",
157
- y="Confidence (%)",
158
- show_label=True,
159
- every=0.5,
160
- )
161
-
162
- # Example images section
163
- gr.Markdown("---\n### 💡 Tips for Best Results\n"
164
- "- Use clear, well-lit images\n"
165
- "- Avoid blurry or partially visible items\n"
166
- "- Single waste items work best\n"
167
- "- Try different angles if unsure")
168
-
169
- # Example gallery
170
- examples_html = """
171
- <div style="padding: 20px; background: #f8f9fa; border-radius: 10px; margin: 20px 0;">
172
- <h4 style="margin-top: 0;">📸 Example Categories</h4>
173
- <p><strong>♻️ Dry Waste:</strong> Paper, cardboard, plastic bottles, cans, books, packaging</p>
174
- <p><strong>🍃 Wet Waste:</strong> Food scraps, fruit peels, leaves, grass, cooked food</p>
175
- <p><strong>🔶 Other Waste:</strong> Electronics, batteries, broken glass, chemicals</p>
176
- </div>
177
- """
178
- gr.HTML(examples_html)
179
-
180
- # Footer
181
- gr.HTML(FOOTER_HTML)
182
-
183
- # Connect button to prediction
184
- def on_submit(image):
185
- if image is None:
186
- return "Upload an image first.", None
187
-
188
- text, results = predict_waste(image)
189
-
190
- # Format chart data
191
- chart_data = [{"Waste Type": k.split()[-1], "Confidence (%)": v} for k, v in (results.items() if results else [])]
192
-
193
- return text, chart_data if chart_data else None
194
-
195
- submit_btn.click(
196
- on_submit,
197
- inputs=[image_input],
198
- outputs=[output_text, chart]
199
- )
200
-
201
-
202
- if __name__ == "__main__":
203
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ language: en
3
+ license: apache-2.0
4
+ library_name: tensorflow
5
+ pipeline_tag: image-classification
6
+ tags:
7
+ - waste-classification
8
+ - efficientnet
9
+ - recycling
10
+ - sustainability
11
+ ---
12
+
13
+ # Waste Classifier (EfficientNetB0)
14
+
15
+ Image classification model for waste segregation into three classes:
16
+ - dry_waste
17
+ - wet_waste
18
+ - other_waste
19
+
20
+ ## Model Files
21
+ - waste_classifier.keras: TensorFlow Keras model artifact
22
+ - inference.py: Local inference utility
23
+ - requirements.txt: Python dependencies for local inference
24
+
25
+ ## Quick Start
26
+
27
+ ```python
28
+ from inference import predict
29
+
30
+ result = predict("sample.jpg")
31
+ print(result)
32
+ ```
33
+
34
+ ## Output Format
35
+
36
+ ```json
37
+ {
38
+ "class": "dry_waste",
39
+ "display_name": "♻️ Dry Waste",
40
+ "confidence": 92.5,
41
+ "action": "Can be recycled → Paper, plastic, metal recovery",
42
+ "all_predictions": {
43
+ "dry_waste": 92.5,
44
+ "other_waste": 4.1,
45
+ "wet_waste": 3.4
46
+ }
47
+ }
48
+ ```
app.py DELETED
@@ -1,10 +0,0 @@
1
- """Hugging Face Space entrypoint.
2
-
3
- Spaces with Gradio SDK look for app.py at repository root.
4
- """
5
-
6
- from HF_SPACE_APP import demo
7
-
8
-
9
- if __name__ == "__main__":
10
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
 
 
 
 
 
inference.py ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Local inference helper for waste classification model."""
2
+
3
+ import os
4
+ import numpy as np
5
+ import tensorflow as tf
6
+ from tensorflow.keras.preprocessing import image
7
+ from tensorflow.keras.applications.efficientnet import preprocess_input
8
+
9
+ IMG_SIZE = 224
10
+ MODEL_PATH = os.path.join(os.getcwd(), "waste_classifier.keras")
11
+
12
+ CLASS_NAMES = ["dry_waste", "other_waste", "wet_waste"]
13
+ CLASS_DISPLAY = {
14
+ "dry_waste": "♻️ Dry Waste",
15
+ "other_waste": "🔶 Other Waste",
16
+ "wet_waste": "🍃 Wet Waste",
17
+ }
18
+ CLASS_ACTIONS = {
19
+ "dry_waste": "Can be recycled → Paper, plastic, metal recovery",
20
+ "other_waste": "Needs special handling → Hazardous / e-waste processing",
21
+ "wet_waste": "Compostable → Organic composting / biogas generation",
22
+ }
23
+
24
+ model = tf.keras.models.load_model(MODEL_PATH)
25
+
26
+
27
+ def predict(image_path: str):
28
+ """Predict waste class for an image path."""
29
+ img = image.load_img(image_path, target_size=(IMG_SIZE, IMG_SIZE))
30
+ img_array = image.img_to_array(img)
31
+ img_array = np.expand_dims(img_array, axis=0)
32
+ img_array = preprocess_input(img_array)
33
+
34
+ predictions = model.predict(img_array, verbose=0)[0]
35
+
36
+ index = int(np.argmax(predictions))
37
+ class_name = CLASS_NAMES[index]
38
+ confidence = float(predictions[index] * 100)
39
+
40
+ all_predictions = {
41
+ CLASS_NAMES[i]: round(float(predictions[i] * 100), 1)
42
+ for i in range(len(CLASS_NAMES))
43
+ }
44
+
45
+ return {
46
+ "class": class_name,
47
+ "display_name": CLASS_DISPLAY.get(class_name, class_name),
48
+ "confidence": round(confidence, 1),
49
+ "action": CLASS_ACTIONS.get(class_name, ""),
50
+ "all_predictions": all_predictions,
51
+ }
requirements.txt CHANGED
@@ -1,5 +1,3 @@
1
- gradio==5.23.1
2
  numpy==1.26.4
3
  pillow==10.4.0
4
- huggingface-hub==0.29.3
5
- requests
 
1
+ tensorflow-cpu==2.15.1
2
  numpy==1.26.4
3
  pillow==10.4.0