Neylton commited on
Commit
123e837
Β·
verified Β·
1 Parent(s): 7a2319c

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +519 -0
app.py ADDED
@@ -0,0 +1,519 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ ACCEPTIN - Telecom Site Quality Classification App
4
+ AI-powered telecom site inspection using ConvNeXt transfer learning
5
+ """
6
+
7
+ import streamlit as st
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from PIL import Image
11
+ import numpy as np
12
+ import plotly.graph_objects as go
13
+ import plotly.express as px
14
+ from plotly.subplots import make_subplots
15
+ import pandas as pd
16
+ import sys
17
+ import os
18
+ import time
19
+ from io import BytesIO
20
+ import base64
21
+
22
+ # Add utils to path
23
+ sys.path.append('utils')
24
+ from model_utils import load_model, TelecomClassifier
25
+ from data_utils import get_inference_transform, prepare_image_for_inference, check_data_directory
26
+
27
+ # Page Configuration
28
+ st.set_page_config(
29
+ page_title="πŸ“‘ ACCEPTIN - Telecom Site Inspector",
30
+ page_icon="πŸ“‘",
31
+ layout="wide",
32
+ initial_sidebar_state="expanded"
33
+ )
34
+
35
+ # Custom CSS for Beautiful UI
36
+ st.markdown("""
37
+ <style>
38
+ .main-header {
39
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
40
+ padding: 2rem;
41
+ border-radius: 15px;
42
+ text-align: center;
43
+ color: white;
44
+ margin-bottom: 2rem;
45
+ box-shadow: 0 8px 32px rgba(0,0,0,0.1);
46
+ }
47
+
48
+ .main-header h1 {
49
+ font-size: 3rem;
50
+ margin: 0;
51
+ font-weight: bold;
52
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
53
+ }
54
+
55
+ .main-header p {
56
+ font-size: 1.2rem;
57
+ margin: 0.5rem 0 0 0;
58
+ opacity: 0.9;
59
+ }
60
+
61
+ .upload-section {
62
+ background: linear-gradient(135deg, #56ab2f 0%, #a8e6cf 100%);
63
+ color: white;
64
+ padding: 20px;
65
+ border-radius: 15px;
66
+ text-align: center;
67
+ margin-bottom: 20px;
68
+ box-shadow: 0 6px 20px rgba(86, 171, 47, 0.3);
69
+ }
70
+
71
+ .result-good {
72
+ background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
73
+ color: white;
74
+ padding: 20px;
75
+ border-radius: 15px;
76
+ text-align: center;
77
+ margin: 20px 0;
78
+ box-shadow: 0 6px 20px rgba(40, 167, 69, 0.3);
79
+ }
80
+
81
+ .result-bad {
82
+ background: linear-gradient(135deg, #dc3545 0%, #e83e8c 100%);
83
+ color: white;
84
+ padding: 20px;
85
+ border-radius: 15px;
86
+ text-align: center;
87
+ margin: 20px 0;
88
+ box-shadow: 0 6px 20px rgba(220, 53, 69, 0.3);
89
+ }
90
+
91
+ .metric-card {
92
+ background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
93
+ padding: 15px;
94
+ border-radius: 10px;
95
+ text-align: center;
96
+ color: white;
97
+ margin: 10px 0;
98
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
99
+ }
100
+
101
+ .info-card {
102
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
103
+ color: white;
104
+ padding: 20px;
105
+ border-radius: 15px;
106
+ margin: 15px 0;
107
+ box-shadow: 0 8px 32px rgba(0,0,0,0.1);
108
+ }
109
+
110
+ .stButton > button {
111
+ background: linear-gradient(45deg, #667eea, #764ba2);
112
+ color: white;
113
+ border: none;
114
+ border-radius: 10px;
115
+ padding: 12px 24px;
116
+ font-weight: bold;
117
+ font-size: 1.1rem;
118
+ transition: all 0.3s ease;
119
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
120
+ width: 100%;
121
+ }
122
+
123
+ .stButton > button:hover {
124
+ transform: translateY(-2px);
125
+ box-shadow: 0 6px 20px rgba(0,0,0,0.3);
126
+ }
127
+
128
+ .sidebar .stSelectbox > div > div {
129
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
130
+ color: white;
131
+ }
132
+ </style>
133
+ """, unsafe_allow_html=True)
134
+
135
+ @st.cache_resource
136
+ def load_telecom_model():
137
+ """Load the trained telecom classification model"""
138
+ model_path = 'models/telecom_classifier.pth'
139
+
140
+ if not os.path.exists(model_path):
141
+ return None, "Model not found. Please train the model first."
142
+
143
+ try:
144
+ model, model_info = load_model(model_path, device='cpu')
145
+ return model, model_info
146
+ except Exception as e:
147
+ return None, f"Error loading model: {str(e)}"
148
+
149
+ def get_prediction(image, model, transform):
150
+ """Get prediction from the model"""
151
+ try:
152
+ # Prepare image
153
+ input_tensor = prepare_image_for_inference(image, transform)
154
+
155
+ # Get prediction
156
+ with torch.no_grad():
157
+ model.eval()
158
+ outputs = model(input_tensor)
159
+ probabilities = F.softmax(outputs, dim=1)
160
+ confidence, predicted = torch.max(probabilities, 1)
161
+
162
+ # Convert to numpy
163
+ predicted_class = predicted.item()
164
+ confidence_score = confidence.item()
165
+ all_probs = probabilities.squeeze().cpu().numpy()
166
+
167
+ return predicted_class, confidence_score, all_probs
168
+
169
+ except Exception as e:
170
+ st.error(f"Error during prediction: {str(e)}")
171
+ return None, None, None
172
+
173
+ def create_confidence_chart(probabilities, class_names):
174
+ """Create confidence chart using Plotly"""
175
+ fig = go.Figure(data=[
176
+ go.Bar(
177
+ x=class_names,
178
+ y=probabilities,
179
+ marker_color=['#dc3545', '#28a745'],
180
+ text=[f'{p:.1%}' for p in probabilities],
181
+ textposition='auto',
182
+ )
183
+ ])
184
+
185
+ fig.update_layout(
186
+ title="Classification Confidence",
187
+ xaxis_title="Site Quality",
188
+ yaxis_title="Confidence",
189
+ yaxis=dict(range=[0, 1]),
190
+ showlegend=False,
191
+ height=400,
192
+ template="plotly_white"
193
+ )
194
+
195
+ return fig
196
+
197
+ def create_quality_metrics_chart(predicted_class, confidence):
198
+ """Create quality metrics visualization"""
199
+ if predicted_class == 1: # Good
200
+ quality_score = confidence * 100
201
+ color = '#28a745'
202
+ status = 'ACCEPTED'
203
+ else: # Bad
204
+ quality_score = (1 - confidence) * 100
205
+ color = '#dc3545'
206
+ status = 'REJECTED'
207
+
208
+ fig = go.Figure(go.Indicator(
209
+ mode="gauge+number+delta",
210
+ value=quality_score,
211
+ domain={'x': [0, 1], 'y': [0, 1]},
212
+ title={'text': f"Quality Score<br><span style='font-size:0.8em;color:{color}'>{status}</span>"},
213
+ delta={'reference': 80},
214
+ gauge={
215
+ 'axis': {'range': [None, 100]},
216
+ 'bar': {'color': color},
217
+ 'steps': [
218
+ {'range': [0, 50], 'color': "lightgray"},
219
+ {'range': [50, 80], 'color': "yellow"},
220
+ {'range': [80, 100], 'color': "lightgreen"}
221
+ ],
222
+ 'threshold': {
223
+ 'line': {'color': "red", 'width': 4},
224
+ 'thickness': 0.75,
225
+ 'value': 90
226
+ }
227
+ }
228
+ ))
229
+
230
+ fig.update_layout(height=400)
231
+ return fig
232
+
233
+ def analyze_site_quality(predicted_class, confidence):
234
+ """Analyze site quality and provide detailed feedback"""
235
+ class_names = ['Bad', 'Good']
236
+ predicted_label = class_names[predicted_class]
237
+
238
+ if predicted_class == 1: # Good site
239
+ analysis = {
240
+ 'status': 'ACCEPTED βœ…',
241
+ 'color': 'result-good',
242
+ 'icon': 'βœ…',
243
+ 'message': 'Site installation meets quality standards',
244
+ 'details': [
245
+ 'βœ… Cable assembly appears properly organized',
246
+ 'βœ… Equipment installation looks correct',
247
+ 'βœ… Overall site organization is acceptable',
248
+ 'βœ… No obvious safety violations detected'
249
+ ],
250
+ 'recommendations': [
251
+ 'πŸ” Verify all labels are clearly readable',
252
+ 'πŸ”§ Double-check all card installations',
253
+ 'πŸ“‹ Complete final inspection checklist',
254
+ 'πŸ“Έ Document final installation state'
255
+ ]
256
+ }
257
+ else: # Bad site
258
+ analysis = {
259
+ 'status': 'REJECTED ❌',
260
+ 'color': 'result-bad',
261
+ 'icon': '❌',
262
+ 'message': 'Site installation requires attention',
263
+ 'details': [
264
+ '❌ Cable organization may need improvement',
265
+ '❌ Equipment installation issues detected',
266
+ '❌ Site organization below standards',
267
+ '❌ Potential safety or quality concerns'
268
+ ],
269
+ 'recommendations': [
270
+ 'πŸ”§ Reorganize cable routing and bundling',
271
+ 'πŸ” Check all card installations and seating',
272
+ '🏷️ Verify all labels are present and readable',
273
+ '⚠️ Address any safety violations',
274
+ 'πŸ“‹ Complete corrective actions before acceptance'
275
+ ]
276
+ }
277
+
278
+ analysis['confidence'] = confidence
279
+ analysis['predicted_label'] = predicted_label
280
+
281
+ return analysis
282
+
283
+ def display_inspection_checklist():
284
+ """Display telecom site inspection checklist"""
285
+ st.markdown("""
286
+ <div class="info-card">
287
+ <h3>πŸ“‹ Telecom Site Inspection Checklist</h3>
288
+ <p>Use this checklist to ensure comprehensive site evaluation:</p>
289
+ </div>
290
+ """, unsafe_allow_html=True)
291
+
292
+ checklist_items = {
293
+ "Cable Assembly": [
294
+ "Cables properly routed and bundled",
295
+ "No loose or hanging cables",
296
+ "Proper cable management systems used",
297
+ "Cable routing follows standards"
298
+ ],
299
+ "Card Installation": [
300
+ "All required cards present",
301
+ "Cards properly seated and secured",
302
+ "No missing or damaged cards",
303
+ "Card configurations correct"
304
+ ],
305
+ "Labeling": [
306
+ "All equipment properly labeled",
307
+ "Labels clearly readable",
308
+ "Label placement follows standards",
309
+ "No missing identification tags"
310
+ ],
311
+ "Safety & Organization": [
312
+ "Safety covers properly installed",
313
+ "Grounding connections secure",
314
+ "Warning signs present where required",
315
+ "Overall rack organization acceptable"
316
+ ]
317
+ }
318
+
319
+ for category, items in checklist_items.items():
320
+ st.subheader(f"πŸ” {category}")
321
+ for item in items:
322
+ st.write(f"β€’ {item}")
323
+
324
+ def main():
325
+ """Main application function"""
326
+ # Header
327
+ st.markdown("""
328
+ <div class="main-header">
329
+ <h1>πŸ“‘ ACCEPTIN</h1>
330
+ <p>AI-Powered Telecom Site Quality Inspector</p>
331
+ </div>
332
+ """, unsafe_allow_html=True)
333
+
334
+ # Sidebar
335
+ st.sidebar.title("πŸ› οΈ Controls")
336
+
337
+ # Load model
338
+ model, model_info = load_telecom_model()
339
+
340
+ if model is None:
341
+ st.error(f"❌ {model_info}")
342
+ st.info("Please train the model first using: `python train_telecom.py`")
343
+ return
344
+
345
+ # Model info in sidebar
346
+ st.sidebar.success("βœ… Model loaded successfully")
347
+ if isinstance(model_info, dict):
348
+ st.sidebar.write(f"**Accuracy:** {model_info.get('best_acc', 'Unknown')}")
349
+ st.sidebar.write(f"**Architecture:** ConvNeXt Large")
350
+ st.sidebar.write(f"**Task:** Binary Classification")
351
+
352
+ # Main content
353
+ col1, col2 = st.columns([1, 1])
354
+
355
+ with col1:
356
+ st.markdown("""
357
+ <div class="upload-section">
358
+ <h3>πŸ“€ Upload Telecom Site Image</h3>
359
+ <p>Upload an image of the telecom site for quality inspection</p>
360
+ </div>
361
+ """, unsafe_allow_html=True)
362
+
363
+ uploaded_file = st.file_uploader(
364
+ "Choose an image...",
365
+ type=['jpg', 'jpeg', 'png', 'bmp', 'tiff'],
366
+ help="Upload a clear image of the telecom site installation"
367
+ )
368
+
369
+ if uploaded_file is not None:
370
+ # Display uploaded image
371
+ image = Image.open(uploaded_file)
372
+ st.image(image, caption="Uploaded Image", use_column_width=True)
373
+
374
+ # Automatic analysis - no button needed
375
+ with st.spinner("Analyzing site quality..."):
376
+ # Get prediction
377
+ transform = get_inference_transform()
378
+ predicted_class, confidence, probabilities = get_prediction(
379
+ image, model, transform
380
+ )
381
+
382
+ if predicted_class is not None:
383
+ # Store results in session state
384
+ st.session_state.prediction_results = {
385
+ 'predicted_class': predicted_class,
386
+ 'confidence': confidence,
387
+ 'probabilities': probabilities,
388
+ 'analysis': analyze_site_quality(predicted_class, confidence)
389
+ }
390
+
391
+ st.success("βœ… Analysis complete!")
392
+
393
+ with col2:
394
+ if hasattr(st.session_state, 'prediction_results'):
395
+ results = st.session_state.prediction_results
396
+ analysis = results['analysis']
397
+
398
+ # Display main result
399
+ st.markdown(f"""
400
+ <div class="{analysis['color']}">
401
+ <h2>{analysis['icon']} {analysis['status']}</h2>
402
+ <h3>{analysis['message']}</h3>
403
+ <p><strong>Confidence:</strong> {analysis['confidence']:.1%}</p>
404
+ </div>
405
+ """, unsafe_allow_html=True)
406
+
407
+ # Confidence chart
408
+ st.plotly_chart(
409
+ create_confidence_chart(
410
+ results['probabilities'],
411
+ ['Bad', 'Good']
412
+ ),
413
+ use_container_width=True
414
+ )
415
+
416
+ # Quality metrics
417
+ st.plotly_chart(
418
+ create_quality_metrics_chart(
419
+ results['predicted_class'],
420
+ results['confidence']
421
+ ),
422
+ use_container_width=True
423
+ )
424
+
425
+ # Detailed analysis section
426
+ if hasattr(st.session_state, 'prediction_results'):
427
+ st.markdown("---")
428
+ st.header("πŸ“Š Detailed Analysis")
429
+
430
+ analysis = st.session_state.prediction_results['analysis']
431
+
432
+ col1, col2 = st.columns([1, 1])
433
+
434
+ with col1:
435
+ st.subheader("πŸ” Quality Assessment")
436
+ for detail in analysis['details']:
437
+ st.write(detail)
438
+
439
+ with col2:
440
+ st.subheader("πŸ’‘ Recommendations")
441
+ for recommendation in analysis['recommendations']:
442
+ st.write(recommendation)
443
+
444
+ # Tabs for additional features
445
+ st.markdown("---")
446
+ tab1, tab2, tab3 = st.tabs(["πŸ“‹ Inspection Checklist", "πŸ“ˆ Training Data", "ℹ️ About"])
447
+
448
+ with tab1:
449
+ display_inspection_checklist()
450
+
451
+ with tab2:
452
+ st.header("πŸ“ˆ Training Data Overview")
453
+
454
+ # Check data directory
455
+ data_counts = check_data_directory('data')
456
+
457
+ if data_counts:
458
+ # Create DataFrame for visualization
459
+ data_list = []
460
+ for split, counts in data_counts.items():
461
+ for class_name, count in counts.items():
462
+ data_list.append({
463
+ 'Split': split.title(),
464
+ 'Class': class_name.title(),
465
+ 'Count': count
466
+ })
467
+
468
+ df = pd.DataFrame(data_list)
469
+
470
+ # Create bar chart
471
+ fig = px.bar(
472
+ df,
473
+ x='Class',
474
+ y='Count',
475
+ color='Split',
476
+ title='Training Data Distribution',
477
+ barmode='group'
478
+ )
479
+ st.plotly_chart(fig, use_container_width=True)
480
+
481
+ # Display summary table
482
+ st.subheader("πŸ“Š Data Summary")
483
+ st.dataframe(df.pivot(index='Class', columns='Split', values='Count'))
484
+ else:
485
+ st.info("No training data found. Please prepare your dataset in the `data/` directory.")
486
+
487
+ with tab3:
488
+ st.header("ℹ️ About ACCEPTIN")
489
+ st.markdown("""
490
+ **ACCEPTIN** is an AI-powered telecom site quality inspection system that uses computer vision
491
+ to automatically classify telecom installations as "good" or "bad" based on visual criteria.
492
+
493
+ ### 🎯 Key Features:
494
+ - **Transfer Learning**: Leverages pre-trained ConvNeXt model (197M parameters)
495
+ - **Binary Classification**: Classifies sites as good/bad with confidence scores
496
+ - **Quality Assessment**: Evaluates cable assembly, card installation, and labeling
497
+ - **Real-time Analysis**: Instant feedback on site quality
498
+
499
+ ### πŸ”§ Technical Details:
500
+ - **Model**: ConvNeXt Large with custom classification head
501
+ - **Training**: Transfer learning from food detection model
502
+ - **Input**: 224x224 RGB images
503
+ - **Output**: Binary classification with confidence scores
504
+
505
+ ### πŸ“Š Quality Criteria:
506
+ - Cable assembly and routing
507
+ - Card installation and labeling
508
+ - General organization and safety
509
+ - Compliance with telecom standards
510
+
511
+ ### πŸš€ Usage:
512
+ 1. Upload telecom site image
513
+ 2. Click "Analyze Site Quality"
514
+ 3. Review results and recommendations
515
+ 4. Use inspection checklist for verification
516
+ """)
517
+
518
+ if __name__ == "__main__":
519
+ main()