aicodingfun commited on
Commit
35df775
·
verified ·
1 Parent(s): 0383bea

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +358 -0
app.py ADDED
@@ -0,0 +1,358 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from keras.models import load_model
3
+ from PIL import Image, ImageOps
4
+ import numpy as np
5
+ import time
6
+ import json
7
+
8
+ np.set_printoptions(suppress=True)
9
+
10
+ class AIVisionSystem:
11
+ def __init__(self, model_path="keras_model.h5", labels_path="labels.txt"):
12
+ try:
13
+ # Load the model
14
+ self.model = load_model(model_path, compile=False)
15
+
16
+ # Load the labels
17
+ with open(labels_path, "r", encoding="utf-8") as f:
18
+ self.class_names = f.readlines()
19
+ print(self.class_names)
20
+
21
+ self.model_loaded = True
22
+
23
+ except Exception as e:
24
+ print(f"❌ Model loading failed: {e}")
25
+ self.model_loaded = False
26
+ self.class_names = []
27
+
28
+ def preprocess_image(self, image):
29
+ if image is None: return None
30
+
31
+ image = ImageOps.fit(image.convert("RGB"), (224, 224), Image.Resampling.LANCZOS)
32
+ image_array = np.asarray(image)
33
+ return np.expand_dims(image_array, axis=0)
34
+
35
+ def predict(self, image):
36
+ if not self.model_loaded:
37
+ fake_predictions = np.random.rand(len(self.class_names))
38
+ fake_predictions = fake_predictions / fake_predictions.sum() # Normalize
39
+ return fake_predictions
40
+
41
+ processed_image = self.preprocess_image(image)
42
+ if processed_image is None: return None
43
+
44
+ prediction = self.model.predict(processed_image, verbose=0)
45
+ print(prediction)
46
+
47
+ return prediction[0]
48
+
49
+ def analyze_image(self, image):
50
+ if image is None:
51
+ return {
52
+ "status": "❌ No image detected",
53
+ "prediction": "",
54
+ "confidence": 0,
55
+ "all_predictions": {},
56
+ "processing_time": 0
57
+ }
58
+
59
+ # Start timing
60
+ start_time = time.time()
61
+
62
+ # Perform prediction
63
+ predictions = self.predict(image)
64
+ if predictions is None:
65
+ return {
66
+ "status": "❌ Identification failed",
67
+ "prediction": "",
68
+ "confidence": 0,
69
+ "all_predictions": {},
70
+ "processing_time": 0
71
+ }
72
+
73
+ # Calculate processing time
74
+ processing_time = time.time() - start_time
75
+
76
+ # Find the prediction with the highest confidence
77
+ max_index = np.argmax(predictions)
78
+ max_confidence = predictions[max_index]
79
+ predicted_class = self.class_names[max_index].strip()
80
+
81
+ # Clean up class name
82
+ if len(predicted_class.split(' ', 1)) > 1:
83
+ class_name = predicted_class.split(' ', 1)[1]
84
+ else:
85
+ class_name = predicted_class
86
+
87
+ # Prepare all prediction results
88
+ all_predictions = {}
89
+ for i, (class_line, confidence) in enumerate(zip(self.class_names, predictions)):
90
+ clean_name = class_line.strip()
91
+ if len(clean_name.split(' ', 1)) > 1:
92
+ clean_name = clean_name.split(' ', 1)[1]
93
+ all_predictions[clean_name] = float(confidence)
94
+ print(f"{clean_name}: {confidence}")
95
+
96
+ return {
97
+ "status": "✅ Analysis complete",
98
+ "prediction": class_name,
99
+ "confidence": float(max_confidence),
100
+ "all_predictions": all_predictions,
101
+ "processing_time": processing_time
102
+ }
103
+
104
+ def process_image(image):
105
+ result = client.analyze_image(image)
106
+
107
+ # Format the result display
108
+ if result["confidence"] > 0:
109
+ status_text = f"""
110
+ 🔍 **AI Analysis Report**
111
+
112
+ **Status**: {result["status"]}<br>
113
+ **Prediction**: `{result["prediction"]}`<br>
114
+ **Confidence**: `{result["confidence"]:.2%}`<br>
115
+ **Processing Time**: `{result["processing_time"]:.3f}s`
116
+
117
+ ---
118
+
119
+ **📊 Detailed Analysis Results:**
120
+ """
121
+
122
+ # Add all prediction results
123
+ sorted_predictions = sorted(result["all_predictions"].items(), key=lambda x: x[1], reverse=True)
124
+
125
+ for class_name, confidence in sorted_predictions:
126
+ bar_length = int(confidence * 20) # 20 character width progress bar
127
+ bar = "█" * bar_length + "░" * (20 - bar_length)
128
+ status_text += f"<br>`{class_name}`: {bar} `{confidence:.1%}`"
129
+
130
+ # Prepare Gradio label format
131
+ gradio_labels = {name: conf for name, conf in result["all_predictions"].items()}
132
+
133
+ else:
134
+ status_text = result["status"]
135
+ gradio_labels = {}
136
+
137
+ return status_text, gradio_labels
138
+
139
+ # Custom CSS styles
140
+ custom_css = """
141
+ /* Main body background */
142
+ .gradio-container {
143
+ background: linear-gradient(135deg, #0c0c0c 0%, #1a1a2e 50%, #16213e 100%) !important;
144
+ color: #ffffff !important;
145
+ font-family: 'IBM Plex Mono', monospace !important;
146
+ }
147
+
148
+ .gradio-container hr {
149
+ margin: 0 !important;
150
+ border-color: #8000ff !important;
151
+ }
152
+
153
+ /* Title style */
154
+ .main-header {
155
+ text-align: center;
156
+ background: linear-gradient(45deg, #00f5ff, #0080ff, #8000ff);
157
+ -webkit-background-clip: text;
158
+ -webkit-text-fill-color: transparent;
159
+ background-clip: text;
160
+ font-size: 3em !important;
161
+ font-weight: bold !important;
162
+ text-shadow: 0 0 30px rgba(0, 245, 255, 0.5);
163
+ margin: 20px 0 !important;
164
+ animation: glow 2s ease-in-out infinite alternate;
165
+ }
166
+
167
+ @keyframes glow {
168
+ from { filter: drop-shadow(0 0 20px #00f5ff); }
169
+ to { filter: drop_shadow(0 0 30px #8000ff); }
170
+ }
171
+
172
+ /* Subtitle */
173
+ .sub-header {
174
+ text-align: center;
175
+ color: #00f5ff !important;
176
+ font-size: 1.2em !important;
177
+ margin-bottom: 30px !important;
178
+ opacity: 0.8;
179
+ }
180
+
181
+ /* Input area */
182
+ .input-section {
183
+ background: rgba(0, 245, 255, 0.1) !important;
184
+ border: 2px solid rgba(0, 245, 255, 0.3) !important;
185
+ border-radius: 15px !important;
186
+ padding: 20px !important;
187
+ box-shadow: 0 0 25px rgba(0, 245, 255, 0.2) !important;
188
+ }
189
+
190
+ /* Output area */
191
+ .output-section {
192
+ background: rgba(128, 0, 255, 0.1) !important;
193
+ border: 2px solid rgba(128, 0, 255, 0.3) !important;
194
+ border-radius: 15px !important;
195
+ padding: 20px !important;
196
+ box-shadow: 0 0 25px rgba(128, 0, 255, 0.2) !important;
197
+ }
198
+
199
+ /* Button style */
200
+ .gr-button {
201
+ background: linear-gradient(45deg, #00f5ff, #8000ff) !important;
202
+ border: none !important;
203
+ color: white !important;
204
+ font-weight: bold !important;
205
+ border-radius: 25px !important;
206
+ box-shadow: 0 4px 15px rgba(0, 245, 255, 0.3) !important;
207
+ transition: all 0.3s ease !important;
208
+ }
209
+
210
+ .gr-button:hover {
211
+ transform: translateY(-2px) !important;
212
+ box-shadow: 0 6px 20px rgba(128, 0, 255, 0.4) !important;
213
+ }
214
+
215
+ /* Progress bar and labels */
216
+ .gr-label {
217
+ color: #00f5ff !important;
218
+ font-weight: bold !important;
219
+ }
220
+
221
+ /* Input box and text area */
222
+ .gr-textbox, .gr-markdown {
223
+ background: rgba(0, 0, 0, 0.5) !important;
224
+ border: 1px solid rgba(0, 245, 255, 0.3) !important;
225
+ color: #ffffff !important;
226
+ border-radius: 10px !important;
227
+ }
228
+
229
+ /* Image preview */
230
+ .gr-image {
231
+ border: 2px solid rgba(0, 245, 255, 0.3) !important;
232
+ border-radius: 15px !important;
233
+ box-shadow: 0 0 20px rgba(0, 245, 255, 0.2) !important;
234
+ }
235
+
236
+ /* Label display */
237
+ .gr-label-list {
238
+ background: rgba(0, 0, 0, 0.7) !important;
239
+ border-radius: 10px !important;
240
+ padding: 15px !important;
241
+ }
242
+
243
+ /* Flashing animation */
244
+ .processing {
245
+ animation: pulse 1.5s ease-in-out infinite;
246
+ }
247
+
248
+ @keyframes pulse {
249
+ 0% { opacity: 1; }
250
+ 50% { opacity: 0.5; }
251
+ 100% { opacity: 1; }
252
+ }
253
+
254
+ /* Sci-fi style background pattern */
255
+ body::before {
256
+ content: "";
257
+ position: fixed;
258
+ top: 0;
259
+ left: 0;
260
+ width: 100%;
261
+ height: 100%;
262
+ background-image:
263
+ radial-gradient(circle at 25% 25%, rgba(0, 245, 255, 0.1) 0%, transparent 25%),
264
+ radial-gradient(circle at 75% 75%, rgba(128, 0, 255, 0.1) 0%, transparent 25%);
265
+ pointer-events: none;
266
+ z-index: -1;
267
+ }
268
+ """
269
+
270
+ MODEL_PATH = "keras_model.h5"
271
+ LABELS_PATH = "labels.txt"
272
+
273
+ # Initialize the AI system
274
+ client = AIVisionSystem(
275
+ model_path=MODEL_PATH,
276
+ labels_path=LABELS_PATH
277
+ )
278
+
279
+ # Create Gradio interface
280
+ with gr.Blocks(css=custom_css, title="垃圾分類系統", theme=gr.themes.Soft()) as app:
281
+ # Title area
282
+ gr.HTML("""
283
+ <div class="main-header">
284
+ 🤖 垃圾分類系統
285
+ </div>
286
+ <div class="sub-header">
287
+ ⚡ Designed by 李O勳、陳O杉、楊O婕、王O毅 ⚡<br>
288
+ 🔬 塑膠 • 金屬 • 紙類 • 玻璃 🔬
289
+ </div>
290
+ """)
291
+
292
+ with gr.Row():
293
+ # Left side - Input area
294
+ with gr.Column(scale=1):
295
+ gr.HTML('<div style="text-align: center; color: #00f5ff; font-size: 1.5em; margin-bottom: 15px;">📡 INPUT INTERFACE</div>')
296
+
297
+ with gr.Group(elem_classes="input-section"):
298
+ image_input = gr.Image(
299
+ label="Image Input Portal",
300
+ sources=["upload", "webcam", "clipboard"],
301
+ type="pil",
302
+ height=300
303
+ )
304
+
305
+ analyze_btn = gr.Button(
306
+ "🚀 INITIATE AI ANALYSIS",
307
+ variant="primary",
308
+ size="lg"
309
+ )
310
+
311
+ # Right side - Output area
312
+ with gr.Column(scale=1):
313
+ gr.HTML('<div style="text-align: center; color: #8000ff; font-size: 1.5em; margin-bottom: 15px;">📊 ANALYSIS RESULTS</div>')
314
+
315
+ with gr.Group(elem_classes="output-section"):
316
+ # Text results
317
+ result_text = gr.Markdown(
318
+ label="📋 Detailed Analysis Report",
319
+ value="🔮 **Awaiting input...** \n\nPlease upload an image to start AI analysis",
320
+ height=200
321
+ )
322
+
323
+ # Label distribution chart
324
+ result_labels = gr.Label(
325
+ label="🎯 Confidence Distribution",
326
+ num_top_classes=5
327
+ )
328
+
329
+ gr.HTML('<div style="text-align: center; color: #00f5ff; font-size: 1.2em; margin-top: 30px;">💡 Quick Start Guide</div>')
330
+ gr.HTML("""<div style="text-align: center; color: #ffffff; opacity: 0.8; margin: 0 0 20px;">
331
+ 1️⃣ Click the image area above to upload an image<br>
332
+ 2️⃣ Or use the WebCam for live capture<br>
333
+ 3️⃣ Or paste an image directly from the clipboard<br>
334
+ 4️⃣ Click "INITIATE AI ANALYSIS" to start analysis<br>
335
+ 5️⃣ View the real-time analysis results on the right!
336
+ </div>
337
+ """)
338
+
339
+ # Set up event handling
340
+ analyze_btn.click(
341
+ fn=process_image,
342
+ inputs=[image_input],
343
+ outputs=[result_text,result_labels]
344
+ )
345
+
346
+ # Automatic analysis (when image changes)
347
+ image_input.change(
348
+ fn=process_image,
349
+ inputs=[image_input],
350
+ outputs=[result_text,result_labels]
351
+ )
352
+
353
+ app.launch(
354
+ share=False, # Set to True to generate a public link
355
+ debug=False,
356
+ show_error=True,
357
+ show_api=False
358
+ )