Update app.py
Browse files
app.py
CHANGED
|
@@ -140,11 +140,45 @@ class VoiceSecuritySystem:
|
|
| 140 |
self.preprocessor = AudioPreprocessor()
|
| 141 |
self.models = {}
|
| 142 |
self.label_encoder = LabelEncoder()
|
|
|
|
|
|
|
| 143 |
self.model_info = {
|
| 144 |
-
"resnet18": {
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
}
|
| 149 |
self.load_models()
|
| 150 |
|
|
@@ -152,7 +186,7 @@ class VoiceSecuritySystem:
|
|
| 152 |
"""Load all pre-trained models"""
|
| 153 |
# This would load your actual trained models
|
| 154 |
# For demo purposes, we'll create placeholder models
|
| 155 |
-
num_classes =
|
| 156 |
|
| 157 |
# Initialize label encoder with dummy classes
|
| 158 |
dummy_classes = [f"user_{i+1}" for i in range(num_classes)]
|
|
@@ -172,9 +206,9 @@ class VoiceSecuritySystem:
|
|
| 172 |
# model.load_state_dict(torch.load(f"models/{model_name}.pth", map_location=self.device))
|
| 173 |
model.eval()
|
| 174 |
self.models[model_name] = model
|
| 175 |
-
print(f"Loaded {model_name} successfully")
|
| 176 |
except Exception as e:
|
| 177 |
-
print(f"Error loading {model_name}: {e}")
|
| 178 |
|
| 179 |
def predict_voice(self, audio_file, model_name, confidence_threshold):
|
| 180 |
"""Predict voice access using selected model"""
|
|
@@ -205,7 +239,7 @@ class VoiceSecuritySystem:
|
|
| 205 |
|
| 206 |
# Create visualization
|
| 207 |
viz_plot = self.create_prediction_visualization(probabilities.cpu().numpy()[0],
|
| 208 |
-
|
| 209 |
|
| 210 |
# Determine access decision
|
| 211 |
if confidence_score >= confidence_threshold:
|
|
@@ -217,12 +251,24 @@ class VoiceSecuritySystem:
|
|
| 217 |
message = f"Access denied - Low confidence"
|
| 218 |
security_status = f"β οΈ UNAUTHORIZED ACCESS ATTEMPT"
|
| 219 |
|
|
|
|
| 220 |
detailed_info = f"""
|
| 221 |
-
|
| 222 |
-
**
|
| 223 |
-
**
|
| 224 |
-
**
|
| 225 |
-
**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
"""
|
| 227 |
|
| 228 |
return status, message, confidence_score, viz_plot, detailed_info
|
|
@@ -232,12 +278,12 @@ class VoiceSecuritySystem:
|
|
| 232 |
|
| 233 |
def create_prediction_visualization(self, probabilities, predicted_class, confidence):
|
| 234 |
"""Create visualization of prediction results"""
|
| 235 |
-
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(
|
| 236 |
|
| 237 |
-
#
|
| 238 |
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#F7DC6F', '#BB8FCE', '#85C1E9', '#F8C471', '#82E0AA', '#F1948A']
|
| 239 |
|
| 240 |
-
# Plot 1: Top 5 predictions
|
| 241 |
top_5_indices = np.argsort(probabilities)[-5:][::-1]
|
| 242 |
top_5_probs = probabilities[top_5_indices]
|
| 243 |
top_5_labels = [self.label_encoder.inverse_transform([i])[0] for i in top_5_indices]
|
|
@@ -245,21 +291,22 @@ class VoiceSecuritySystem:
|
|
| 245 |
bars = ax1.barh(range(len(top_5_labels)), top_5_probs, color=colors[:len(top_5_labels)])
|
| 246 |
ax1.set_yticks(range(len(top_5_labels)))
|
| 247 |
ax1.set_yticklabels(top_5_labels)
|
| 248 |
-
ax1.set_xlabel('Confidence Score')
|
| 249 |
-
ax1.set_title('Top 5 Predictions')
|
| 250 |
ax1.set_xlim(0, 1)
|
|
|
|
| 251 |
|
| 252 |
-
# Highlight the top prediction
|
| 253 |
-
bars[0].set_color('#
|
| 254 |
bars[0].set_edgecolor('#FF8C00')
|
| 255 |
-
bars[0].set_linewidth(
|
| 256 |
|
| 257 |
-
# Add value labels
|
| 258 |
for i, (bar, prob) in enumerate(zip(bars, top_5_probs)):
|
| 259 |
-
ax1.text(prob + 0.
|
| 260 |
-
|
| 261 |
|
| 262 |
-
# Plot 2:
|
| 263 |
theta = np.linspace(0, np.pi, 100)
|
| 264 |
r = np.ones_like(theta)
|
| 265 |
|
|
@@ -268,53 +315,57 @@ class VoiceSecuritySystem:
|
|
| 268 |
ax2.set_theta_direction(1)
|
| 269 |
ax2.set_ylim(0, 1)
|
| 270 |
|
| 271 |
-
#
|
| 272 |
if confidence < 0.3:
|
| 273 |
-
color = '#
|
| 274 |
-
status_text = 'LOW'
|
|
|
|
| 275 |
elif confidence < 0.7:
|
| 276 |
-
color = '#
|
| 277 |
-
status_text = 'MEDIUM'
|
|
|
|
| 278 |
else:
|
| 279 |
-
color = '#
|
| 280 |
-
status_text = 'HIGH'
|
|
|
|
| 281 |
|
| 282 |
-
# Draw gauge
|
| 283 |
-
ax2.fill_between(theta, 0, r, alpha=0.
|
| 284 |
confidence_theta = theta[int(confidence * len(theta))]
|
| 285 |
-
ax2.plot([confidence_theta, confidence_theta], [0, 1], color=color, linewidth=
|
| 286 |
ax2.fill_between(theta[:int(confidence * len(theta))], 0, r[:int(confidence * len(theta))],
|
| 287 |
-
|
| 288 |
|
| 289 |
-
ax2.set_title(f'Confidence
|
|
|
|
| 290 |
ax2.set_ylim(0, 1)
|
| 291 |
ax2.set_yticklabels([])
|
| 292 |
-
ax2.set_xticklabels(['Low', '', '', '
|
| 293 |
|
| 294 |
plt.tight_layout()
|
| 295 |
return fig
|
| 296 |
|
| 297 |
def create_empty_plot(self):
|
| 298 |
"""Create empty plot for error cases"""
|
| 299 |
-
fig, ax = plt.subplots(figsize=(
|
| 300 |
-
ax.text(0.5, 0.5, 'No Data Available
|
| 301 |
-
fontsize=
|
| 302 |
ax.set_xlim(0, 1)
|
| 303 |
ax.set_ylim(0, 1)
|
| 304 |
ax.axis('off')
|
| 305 |
return fig
|
| 306 |
|
| 307 |
def get_model_comparison(self):
|
| 308 |
-
"""Return model comparison information"""
|
| 309 |
comparison_data = []
|
| 310 |
for model_key, info in self.model_info.items():
|
| 311 |
-
# In actual deployment, you would load real metrics
|
| 312 |
comparison_data.append([
|
| 313 |
info['name'],
|
| 314 |
-
info['
|
| 315 |
-
|
| 316 |
-
|
| 317 |
-
|
|
|
|
| 318 |
])
|
| 319 |
return comparison_data
|
| 320 |
|
|
@@ -329,200 +380,226 @@ def get_model_info(model_name):
|
|
| 329 |
"""Get information about selected model"""
|
| 330 |
if model_name in voice_system.model_info:
|
| 331 |
info = voice_system.model_info[model_name]
|
| 332 |
-
return f"
|
| 333 |
return "Model information not available"
|
| 334 |
|
| 335 |
-
#
|
| 336 |
custom_css = """
|
| 337 |
.gradio-container {
|
| 338 |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
|
|
|
| 339 |
}
|
| 340 |
-
|
| 341 |
.gr-button-primary {
|
| 342 |
background: linear-gradient(45deg, #FF6B6B, #FF8E53) !important;
|
| 343 |
border: none !important;
|
|
|
|
|
|
|
|
|
|
| 344 |
}
|
| 345 |
-
|
| 346 |
.gr-button-secondary {
|
| 347 |
background: linear-gradient(45deg, #4ECDC4, #44A08D) !important;
|
| 348 |
border: none !important;
|
| 349 |
}
|
| 350 |
-
|
| 351 |
.gr-panel {
|
| 352 |
background: rgba(255, 255, 255, 0.95) !important;
|
| 353 |
-
backdrop-filter: blur(
|
| 354 |
-
border-radius:
|
| 355 |
-
border:
|
|
|
|
| 356 |
}
|
| 357 |
-
|
| 358 |
.gr-form {
|
| 359 |
background: transparent !important;
|
| 360 |
}
|
| 361 |
-
|
| 362 |
.gr-box {
|
| 363 |
-
border-radius:
|
| 364 |
border: 1px solid #E0E0E0 !important;
|
|
|
|
| 365 |
}
|
| 366 |
-
|
| 367 |
h1, h2, h3 {
|
| 368 |
color: #2C3E50 !important;
|
| 369 |
-
text-shadow:
|
| 370 |
}
|
| 371 |
-
|
| 372 |
-
|
| 373 |
-
padding: 10px;
|
| 374 |
-
border-radius:
|
| 375 |
-
|
| 376 |
font-weight: bold;
|
| 377 |
-
|
| 378 |
-
|
| 379 |
-
.access-granted {
|
| 380 |
-
background-color: #D5F4E6;
|
| 381 |
-
color: #27AE60;
|
| 382 |
-
border-left: 4px solid #27AE60;
|
| 383 |
-
}
|
| 384 |
-
|
| 385 |
-
.access-denied {
|
| 386 |
-
background-color: #FADBD8;
|
| 387 |
-
color: #E74C3C;
|
| 388 |
-
border-left: 4px solid #E74C3C;
|
| 389 |
}
|
| 390 |
"""
|
| 391 |
|
| 392 |
-
# Create Gradio interface
|
| 393 |
-
with gr.Blocks(css=custom_css, title="π Voice Recognition Security System") as app:
|
| 394 |
gr.HTML("""
|
| 395 |
-
<div style="text-align: center; padding:
|
| 396 |
-
<h1 style="margin: 0; font-size:
|
| 397 |
-
<p style="margin:
|
|
|
|
|
|
|
|
|
|
| 398 |
</div>
|
| 399 |
""")
|
| 400 |
|
| 401 |
with gr.Row():
|
| 402 |
with gr.Column(scale=1):
|
| 403 |
-
gr.HTML("<h2>π― Authentication Panel</h2>")
|
| 404 |
|
| 405 |
-
# Audio input
|
| 406 |
audio_input = gr.Audio(
|
| 407 |
-
label="π€ Upload Voice Sample",
|
| 408 |
type="filepath",
|
| 409 |
elem_id="audio_input"
|
| 410 |
)
|
| 411 |
|
| 412 |
-
# Model selection
|
| 413 |
model_selector = gr.Dropdown(
|
| 414 |
choices=[
|
| 415 |
-
("ResNet-18 (
|
| 416 |
-
("ResNet-50 (
|
| 417 |
-
("EfficientNet-B0 (
|
| 418 |
-
("MobileNet-V2 (
|
| 419 |
],
|
| 420 |
value="resnet18",
|
| 421 |
-
label="π€ Select AI Model",
|
| 422 |
-
info="
|
| 423 |
)
|
| 424 |
|
| 425 |
-
#
|
| 426 |
confidence_slider = gr.Slider(
|
| 427 |
minimum=0.1,
|
| 428 |
maximum=1.0,
|
| 429 |
-
value=0.
|
| 430 |
step=0.05,
|
| 431 |
-
label="ποΈ Security Threshold",
|
| 432 |
-
info="Higher values = More secure but
|
| 433 |
)
|
| 434 |
|
| 435 |
-
#
|
| 436 |
process_btn = gr.Button(
|
| 437 |
-
"π
|
| 438 |
variant="primary",
|
| 439 |
size="lg"
|
| 440 |
)
|
| 441 |
|
| 442 |
-
#
|
| 443 |
model_info_display = gr.Markdown(
|
| 444 |
get_model_info("resnet18"),
|
| 445 |
-
label="π Model
|
| 446 |
)
|
| 447 |
|
| 448 |
with gr.Column(scale=2):
|
| 449 |
-
gr.HTML("<h2>π Authentication Results</h2>")
|
| 450 |
|
| 451 |
with gr.Row():
|
| 452 |
with gr.Column():
|
| 453 |
-
#
|
| 454 |
status_output = gr.Textbox(
|
| 455 |
-
label="π¦ Access
|
| 456 |
interactive=False,
|
| 457 |
elem_id="status_output"
|
| 458 |
)
|
| 459 |
|
| 460 |
-
#
|
| 461 |
message_output = gr.Textbox(
|
| 462 |
-
label="π¬ System
|
| 463 |
interactive=False
|
| 464 |
)
|
| 465 |
|
| 466 |
-
#
|
| 467 |
confidence_output = gr.Number(
|
| 468 |
-
label="π Confidence Score",
|
| 469 |
interactive=False,
|
| 470 |
precision=3
|
| 471 |
)
|
| 472 |
|
| 473 |
with gr.Column():
|
| 474 |
-
#
|
| 475 |
detailed_info = gr.Markdown(
|
| 476 |
-
label="π
|
| 477 |
)
|
| 478 |
|
| 479 |
-
#
|
| 480 |
plot_output = gr.Plot(
|
| 481 |
-
label="π Prediction Visualization",
|
| 482 |
elem_id="plot_output"
|
| 483 |
)
|
| 484 |
|
| 485 |
-
#
|
| 486 |
with gr.Row():
|
| 487 |
-
gr.HTML("<h2>βοΈ Model Comparison</h2>")
|
| 488 |
|
| 489 |
with gr.Row():
|
| 490 |
comparison_table = gr.Dataframe(
|
| 491 |
-
headers=["Model", "
|
| 492 |
value=voice_system.get_model_comparison(),
|
| 493 |
-
label="π Performance Metrics",
|
| 494 |
interactive=False
|
| 495 |
)
|
| 496 |
|
| 497 |
-
#
|
| 498 |
with gr.Row():
|
| 499 |
with gr.Column():
|
| 500 |
gr.HTML("""
|
| 501 |
-
<div style="background: linear-gradient(45deg, #FFF3E0, #FFE0B2); padding:
|
| 502 |
-
<h3>π‘οΈ Security Features</h3>
|
| 503 |
-
<ul>
|
| 504 |
-
<li><strong
|
| 505 |
-
<li><strong
|
| 506 |
-
<li><strong
|
| 507 |
-
<li><strong
|
|
|
|
|
|
|
| 508 |
</ul>
|
| 509 |
</div>
|
| 510 |
""")
|
| 511 |
|
| 512 |
with gr.Column():
|
| 513 |
gr.HTML("""
|
| 514 |
-
<div style="background: linear-gradient(45deg, #E8F5E8, #C8E6C9); padding:
|
| 515 |
-
<h3>π
|
| 516 |
-
<ol>
|
| 517 |
-
<li><strong
|
| 518 |
-
<li><strong
|
| 519 |
-
<li><strong
|
| 520 |
-
<li><strong
|
| 521 |
-
<li><strong
|
| 522 |
</ol>
|
|
|
|
|
|
|
|
|
|
| 523 |
</div>
|
| 524 |
""")
|
| 525 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 526 |
# Event handlers
|
| 527 |
model_selector.change(
|
| 528 |
fn=get_model_info,
|
|
@@ -536,14 +613,15 @@ with gr.Blocks(css=custom_css, title="π Voice Recognition Security System") a
|
|
| 536 |
outputs=[status_output, message_output, confidence_output, plot_output, detailed_info]
|
| 537 |
)
|
| 538 |
|
| 539 |
-
#
|
| 540 |
gr.HTML("""
|
| 541 |
-
<div style="text-align: center; padding:
|
| 542 |
-
<
|
| 543 |
-
<p
|
| 544 |
</div>
|
| 545 |
""")
|
| 546 |
|
|
|
|
| 547 |
# Launch configuration
|
| 548 |
if __name__ == "__main__":
|
| 549 |
app.launch(
|
|
|
|
| 140 |
self.preprocessor = AudioPreprocessor()
|
| 141 |
self.models = {}
|
| 142 |
self.label_encoder = LabelEncoder()
|
| 143 |
+
|
| 144 |
+
# Updated model info with actual training results
|
| 145 |
self.model_info = {
|
| 146 |
+
"resnet18": {
|
| 147 |
+
"name": "ResNet-18 π CHAMPION",
|
| 148 |
+
"description": "π₯ BEST PERFORMING MODEL - Perfect 100% accuracy with 11.3M parameters (4.9M trainable). Exceptional security with 0.06% FAR and 0% FRR. Ideal for high-security applications requiring zero false rejections.",
|
| 149 |
+
"accuracy": "100.00%",
|
| 150 |
+
"far": "0.0006",
|
| 151 |
+
"frr": "0.0000",
|
| 152 |
+
"parameters": "11.3M total (4.9M trainable)",
|
| 153 |
+
"status": "π CHAMPION"
|
| 154 |
+
},
|
| 155 |
+
"resnet50": {
|
| 156 |
+
"name": "ResNet-50 π₯ HIGH PERFORMER",
|
| 157 |
+
"description": "π₯ EXCELLENT ACCURACY - 99.94% accuracy with 24.6M parameters (16.0M trainable). Near-perfect performance with robust feature extraction. Best for applications requiring high accuracy with acceptable computational overhead.",
|
| 158 |
+
"accuracy": "99.94%",
|
| 159 |
+
"far": "0.0006",
|
| 160 |
+
"frr": "0.0000",
|
| 161 |
+
"parameters": "24.6M total (16.0M trainable)",
|
| 162 |
+
"status": "π₯ RUNNER-UP"
|
| 163 |
+
},
|
| 164 |
+
"efficientnet_b0": {
|
| 165 |
+
"name": "EfficientNet-B0 β‘ EFFICIENT",
|
| 166 |
+
"description": "β‘ MOBILE OPTIMIZED - 99.76% accuracy with only 4.7M parameters (3.8M trainable). Excellent efficiency-accuracy trade-off. Perfect for mobile deployment with minimal computational requirements.",
|
| 167 |
+
"accuracy": "99.76%",
|
| 168 |
+
"far": "0.0030",
|
| 169 |
+
"frr": "0.0000",
|
| 170 |
+
"parameters": "4.7M total (3.8M trainable)",
|
| 171 |
+
"status": "β‘ EFFICIENT"
|
| 172 |
+
},
|
| 173 |
+
"mobilenet_v2": {
|
| 174 |
+
"name": "MobileNet-V2 π± LIGHTWEIGHT",
|
| 175 |
+
"description": "π± ULTRA-LIGHTWEIGHT - 99.76% accuracy with just 2.9M parameters (1.1M trainable). Smallest model with excellent performance. Ideal for edge devices and real-time applications with limited resources.",
|
| 176 |
+
"accuracy": "99.76%",
|
| 177 |
+
"far": "0.0012",
|
| 178 |
+
"frr": "0.0000",
|
| 179 |
+
"parameters": "2.9M total (1.1M trainable)",
|
| 180 |
+
"status": "π± COMPACT"
|
| 181 |
+
}
|
| 182 |
}
|
| 183 |
self.load_models()
|
| 184 |
|
|
|
|
| 186 |
"""Load all pre-trained models"""
|
| 187 |
# This would load your actual trained models
|
| 188 |
# For demo purposes, we'll create placeholder models
|
| 189 |
+
num_classes = 26 # Based on your training output (26 users)
|
| 190 |
|
| 191 |
# Initialize label encoder with dummy classes
|
| 192 |
dummy_classes = [f"user_{i+1}" for i in range(num_classes)]
|
|
|
|
| 206 |
# model.load_state_dict(torch.load(f"models/{model_name}.pth", map_location=self.device))
|
| 207 |
model.eval()
|
| 208 |
self.models[model_name] = model
|
| 209 |
+
print(f"β
Loaded {model_name} successfully")
|
| 210 |
except Exception as e:
|
| 211 |
+
print(f"β Error loading {model_name}: {e}")
|
| 212 |
|
| 213 |
def predict_voice(self, audio_file, model_name, confidence_threshold):
|
| 214 |
"""Predict voice access using selected model"""
|
|
|
|
| 239 |
|
| 240 |
# Create visualization
|
| 241 |
viz_plot = self.create_prediction_visualization(probabilities.cpu().numpy()[0],
|
| 242 |
+
predicted_class, confidence_score)
|
| 243 |
|
| 244 |
# Determine access decision
|
| 245 |
if confidence_score >= confidence_threshold:
|
|
|
|
| 251 |
message = f"Access denied - Low confidence"
|
| 252 |
security_status = f"β οΈ UNAUTHORIZED ACCESS ATTEMPT"
|
| 253 |
|
| 254 |
+
model_stats = self.model_info[model_name]
|
| 255 |
detailed_info = f"""
|
| 256 |
+
## π€ Model Performance
|
| 257 |
+
**Model Used:** {model_stats['name']}
|
| 258 |
+
**Training Accuracy:** {model_stats['accuracy']}
|
| 259 |
+
**Model Size:** {model_stats['parameters']}
|
| 260 |
+
**Status:** {model_stats['status']}
|
| 261 |
+
|
| 262 |
+
## π Prediction Results
|
| 263 |
+
**Predicted User:** {predicted_class}
|
| 264 |
+
**Confidence Score:** {confidence_score:.3f}
|
| 265 |
+
**Security Threshold:** {confidence_threshold}
|
| 266 |
+
**Decision:** {'β
GRANT ACCESS' if confidence_score >= confidence_threshold else 'β DENY ACCESS'}
|
| 267 |
+
|
| 268 |
+
## π‘οΈ Security Metrics
|
| 269 |
+
**False Accept Rate (FAR):** {model_stats['far']}
|
| 270 |
+
**False Reject Rate (FRR):** {model_stats['frr']}
|
| 271 |
+
**Security Level:** {'π HIGH' if confidence_score >= 0.8 else 'π MEDIUM' if confidence_score >= 0.5 else 'β οΈ LOW'}
|
| 272 |
"""
|
| 273 |
|
| 274 |
return status, message, confidence_score, viz_plot, detailed_info
|
|
|
|
| 278 |
|
| 279 |
def create_prediction_visualization(self, probabilities, predicted_class, confidence):
|
| 280 |
"""Create visualization of prediction results"""
|
| 281 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
|
| 282 |
|
| 283 |
+
# Enhanced color scheme
|
| 284 |
colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#F7DC6F', '#BB8FCE', '#85C1E9', '#F8C471', '#82E0AA', '#F1948A']
|
| 285 |
|
| 286 |
+
# Plot 1: Top 5 predictions with enhanced styling
|
| 287 |
top_5_indices = np.argsort(probabilities)[-5:][::-1]
|
| 288 |
top_5_probs = probabilities[top_5_indices]
|
| 289 |
top_5_labels = [self.label_encoder.inverse_transform([i])[0] for i in top_5_indices]
|
|
|
|
| 291 |
bars = ax1.barh(range(len(top_5_labels)), top_5_probs, color=colors[:len(top_5_labels)])
|
| 292 |
ax1.set_yticks(range(len(top_5_labels)))
|
| 293 |
ax1.set_yticklabels(top_5_labels)
|
| 294 |
+
ax1.set_xlabel('Confidence Score', fontweight='bold')
|
| 295 |
+
ax1.set_title('π― Top 5 User Predictions', fontweight='bold', fontsize=12)
|
| 296 |
ax1.set_xlim(0, 1)
|
| 297 |
+
ax1.grid(axis='x', alpha=0.3)
|
| 298 |
|
| 299 |
+
# Highlight the top prediction with gold color
|
| 300 |
+
bars[0].set_color('#FFD700')
|
| 301 |
bars[0].set_edgecolor('#FF8C00')
|
| 302 |
+
bars[0].set_linewidth(3)
|
| 303 |
|
| 304 |
+
# Add value labels with better formatting
|
| 305 |
for i, (bar, prob) in enumerate(zip(bars, top_5_probs)):
|
| 306 |
+
ax1.text(prob + 0.02, bar.get_y() + bar.get_height()/2,
|
| 307 |
+
f'{prob:.3f}', va='center', fontweight='bold', fontsize=10)
|
| 308 |
|
| 309 |
+
# Plot 2: Enhanced confidence gauge
|
| 310 |
theta = np.linspace(0, np.pi, 100)
|
| 311 |
r = np.ones_like(theta)
|
| 312 |
|
|
|
|
| 315 |
ax2.set_theta_direction(1)
|
| 316 |
ax2.set_ylim(0, 1)
|
| 317 |
|
| 318 |
+
# Enhanced color segments based on confidence levels
|
| 319 |
if confidence < 0.3:
|
| 320 |
+
color = '#FF4757' # Red
|
| 321 |
+
status_text = 'β οΈ LOW'
|
| 322 |
+
risk_level = 'HIGH RISK'
|
| 323 |
elif confidence < 0.7:
|
| 324 |
+
color = '#FFA726' # Orange
|
| 325 |
+
status_text = 'π‘ MEDIUM'
|
| 326 |
+
risk_level = 'MODERATE RISK'
|
| 327 |
else:
|
| 328 |
+
color = '#66BB6A' # Green
|
| 329 |
+
status_text = 'β
HIGH'
|
| 330 |
+
risk_level = 'LOW RISK'
|
| 331 |
|
| 332 |
+
# Draw enhanced gauge
|
| 333 |
+
ax2.fill_between(theta, 0, r, alpha=0.2, color='lightgray')
|
| 334 |
confidence_theta = theta[int(confidence * len(theta))]
|
| 335 |
+
ax2.plot([confidence_theta, confidence_theta], [0, 1], color=color, linewidth=10)
|
| 336 |
ax2.fill_between(theta[:int(confidence * len(theta))], 0, r[:int(confidence * len(theta))],
|
| 337 |
+
alpha=0.8, color=color)
|
| 338 |
|
| 339 |
+
ax2.set_title(f'ποΈ Confidence Level\n{confidence:.3f} - {status_text}\n{risk_level}',
|
| 340 |
+
pad=30, fontweight='bold')
|
| 341 |
ax2.set_ylim(0, 1)
|
| 342 |
ax2.set_yticklabels([])
|
| 343 |
+
ax2.set_xticklabels(['π΄ Low', '', 'π‘ Med', '', 'π’ High'], fontweight='bold')
|
| 344 |
|
| 345 |
plt.tight_layout()
|
| 346 |
return fig
|
| 347 |
|
| 348 |
def create_empty_plot(self):
|
| 349 |
"""Create empty plot for error cases"""
|
| 350 |
+
fig, ax = plt.subplots(figsize=(10, 6))
|
| 351 |
+
ax.text(0.5, 0.5, 'π No Data Available\nPlease upload an audio file',
|
| 352 |
+
ha='center', va='center', fontsize=18, color='gray', fontweight='bold')
|
| 353 |
ax.set_xlim(0, 1)
|
| 354 |
ax.set_ylim(0, 1)
|
| 355 |
ax.axis('off')
|
| 356 |
return fig
|
| 357 |
|
| 358 |
def get_model_comparison(self):
|
| 359 |
+
"""Return model comparison information with actual training results"""
|
| 360 |
comparison_data = []
|
| 361 |
for model_key, info in self.model_info.items():
|
|
|
|
| 362 |
comparison_data.append([
|
| 363 |
info['name'],
|
| 364 |
+
info['accuracy'],
|
| 365 |
+
info['far'],
|
| 366 |
+
info['frr'],
|
| 367 |
+
info['parameters'],
|
| 368 |
+
info['status']
|
| 369 |
])
|
| 370 |
return comparison_data
|
| 371 |
|
|
|
|
| 380 |
"""Get information about selected model"""
|
| 381 |
if model_name in voice_system.model_info:
|
| 382 |
info = voice_system.model_info[model_name]
|
| 383 |
+
return f"## {info['name']}\n\n{info['description']}\n\n**π Key Stats:**\n- Accuracy: {info['accuracy']}\n- Parameters: {info['parameters']}\n- FAR: {info['far']} | FRR: {info['frr']}"
|
| 384 |
return "Model information not available"
|
| 385 |
|
| 386 |
+
# Enhanced custom CSS
|
| 387 |
custom_css = """
|
| 388 |
.gradio-container {
|
| 389 |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
| 390 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
|
| 391 |
}
|
|
|
|
| 392 |
.gr-button-primary {
|
| 393 |
background: linear-gradient(45deg, #FF6B6B, #FF8E53) !important;
|
| 394 |
border: none !important;
|
| 395 |
+
font-weight: bold !important;
|
| 396 |
+
text-transform: uppercase !important;
|
| 397 |
+
letter-spacing: 1px !important;
|
| 398 |
}
|
|
|
|
| 399 |
.gr-button-secondary {
|
| 400 |
background: linear-gradient(45deg, #4ECDC4, #44A08D) !important;
|
| 401 |
border: none !important;
|
| 402 |
}
|
|
|
|
| 403 |
.gr-panel {
|
| 404 |
background: rgba(255, 255, 255, 0.95) !important;
|
| 405 |
+
backdrop-filter: blur(15px) !important;
|
| 406 |
+
border-radius: 20px !important;
|
| 407 |
+
border: 2px solid rgba(255, 255, 255, 0.3) !important;
|
| 408 |
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1) !important;
|
| 409 |
}
|
|
|
|
| 410 |
.gr-form {
|
| 411 |
background: transparent !important;
|
| 412 |
}
|
|
|
|
| 413 |
.gr-box {
|
| 414 |
+
border-radius: 15px !important;
|
| 415 |
border: 1px solid #E0E0E0 !important;
|
| 416 |
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05) !important;
|
| 417 |
}
|
|
|
|
| 418 |
h1, h2, h3 {
|
| 419 |
color: #2C3E50 !important;
|
| 420 |
+
text-shadow: 2px 2px 4px rgba(0,0,0,0.1) !important;
|
| 421 |
}
|
| 422 |
+
.champion-badge {
|
| 423 |
+
background: linear-gradient(45deg, #FFD700, #FFA500);
|
| 424 |
+
padding: 5px 10px;
|
| 425 |
+
border-radius: 20px;
|
| 426 |
+
color: #333;
|
| 427 |
font-weight: bold;
|
| 428 |
+
display: inline-block;
|
| 429 |
+
margin: 5px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 430 |
}
|
| 431 |
"""
|
| 432 |
|
| 433 |
+
# Create enhanced Gradio interface
|
| 434 |
+
with gr.Blocks(css=custom_css, title="π Voice Recognition Security System - Trained Results") as app:
|
| 435 |
gr.HTML("""
|
| 436 |
+
<div style="text-align: center; padding: 30px; background: linear-gradient(45deg, #667eea, #764ba2); color: white; border-radius: 20px; margin-bottom: 25px; box-shadow: 0 10px 30px rgba(0,0,0,0.3);">
|
| 437 |
+
<h1 style="margin: 0; font-size: 3em; text-shadow: 3px 3px 6px rgba(0,0,0,0.4);">π Voice Recognition Security System</h1>
|
| 438 |
+
<p style="margin: 15px 0 10px 0; font-size: 1.3em; opacity: 0.95;">Advanced AI-powered voice authentication with 4 deep learning models</p>
|
| 439 |
+
<div style="background: rgba(255,255,255,0.2); padding: 10px; border-radius: 10px; margin-top: 15px;">
|
| 440 |
+
<p style="margin: 0; font-size: 1.1em; font-weight: bold;">π Training Complete: 26 Users | 1,693 Samples | Best Accuracy: 100%</p>
|
| 441 |
+
</div>
|
| 442 |
</div>
|
| 443 |
""")
|
| 444 |
|
| 445 |
with gr.Row():
|
| 446 |
with gr.Column(scale=1):
|
| 447 |
+
gr.HTML("<h2>π― Authentication Control Panel</h2>")
|
| 448 |
|
| 449 |
+
# Audio input with enhanced styling
|
| 450 |
audio_input = gr.Audio(
|
| 451 |
+
label="π€ Upload Voice Sample (WAV, MP3, FLAC supported)",
|
| 452 |
type="filepath",
|
| 453 |
elem_id="audio_input"
|
| 454 |
)
|
| 455 |
|
| 456 |
+
# Model selection with performance indicators
|
| 457 |
model_selector = gr.Dropdown(
|
| 458 |
choices=[
|
| 459 |
+
("π ResNet-18 - CHAMPION (100% Accuracy)", "resnet18"),
|
| 460 |
+
("π₯ ResNet-50 - HIGH PERFORMER (99.94% Accuracy)", "resnet50"),
|
| 461 |
+
("β‘ EfficientNet-B0 - EFFICIENT (99.76% Accuracy)", "efficientnet_b0"),
|
| 462 |
+
("π± MobileNet-V2 - LIGHTWEIGHT (99.76% Accuracy)", "mobilenet_v2")
|
| 463 |
],
|
| 464 |
value="resnet18",
|
| 465 |
+
label="π€ Select AI Model (Ranked by Performance)",
|
| 466 |
+
info="All models trained on 26 users with augmented dataset"
|
| 467 |
)
|
| 468 |
|
| 469 |
+
# Enhanced confidence threshold
|
| 470 |
confidence_slider = gr.Slider(
|
| 471 |
minimum=0.1,
|
| 472 |
maximum=1.0,
|
| 473 |
+
value=0.8,
|
| 474 |
step=0.05,
|
| 475 |
+
label="ποΈ Security Threshold (Recommended: 0.8 for high security)",
|
| 476 |
+
info="Higher values = More secure but may increase false rejections"
|
| 477 |
)
|
| 478 |
|
| 479 |
+
# Enhanced process button
|
| 480 |
process_btn = gr.Button(
|
| 481 |
+
"π AUTHENTICATE VOICE",
|
| 482 |
variant="primary",
|
| 483 |
size="lg"
|
| 484 |
)
|
| 485 |
|
| 486 |
+
# Enhanced model info display
|
| 487 |
model_info_display = gr.Markdown(
|
| 488 |
get_model_info("resnet18"),
|
| 489 |
+
label="π Model Performance Details"
|
| 490 |
)
|
| 491 |
|
| 492 |
with gr.Column(scale=2):
|
| 493 |
+
gr.HTML("<h2>π Authentication Results & Analysis</h2>")
|
| 494 |
|
| 495 |
with gr.Row():
|
| 496 |
with gr.Column():
|
| 497 |
+
# Enhanced status display
|
| 498 |
status_output = gr.Textbox(
|
| 499 |
+
label="π¦ Access Decision",
|
| 500 |
interactive=False,
|
| 501 |
elem_id="status_output"
|
| 502 |
)
|
| 503 |
|
| 504 |
+
# Enhanced message display
|
| 505 |
message_output = gr.Textbox(
|
| 506 |
+
label="π¬ System Response",
|
| 507 |
interactive=False
|
| 508 |
)
|
| 509 |
|
| 510 |
+
# Enhanced confidence display
|
| 511 |
confidence_output = gr.Number(
|
| 512 |
+
label="π Confidence Score (0.000-1.000)",
|
| 513 |
interactive=False,
|
| 514 |
precision=3
|
| 515 |
)
|
| 516 |
|
| 517 |
with gr.Column():
|
| 518 |
+
# Enhanced detailed information
|
| 519 |
detailed_info = gr.Markdown(
|
| 520 |
+
label="π Comprehensive Analysis Report"
|
| 521 |
)
|
| 522 |
|
| 523 |
+
# Enhanced visualization plot
|
| 524 |
plot_output = gr.Plot(
|
| 525 |
+
label="π Prediction Visualization & Confidence Analysis",
|
| 526 |
elem_id="plot_output"
|
| 527 |
)
|
| 528 |
|
| 529 |
+
# Enhanced model comparison section
|
| 530 |
with gr.Row():
|
| 531 |
+
gr.HTML("<h2>βοΈ Model Performance Comparison (Training Results)</h2>")
|
| 532 |
|
| 533 |
with gr.Row():
|
| 534 |
comparison_table = gr.Dataframe(
|
| 535 |
+
headers=["Model", "Accuracy", "FAR (False Accept)", "FRR (False Reject)", "Parameters", "Status"],
|
| 536 |
value=voice_system.get_model_comparison(),
|
| 537 |
+
label="π Actual Training Performance Metrics",
|
| 538 |
interactive=False
|
| 539 |
)
|
| 540 |
|
| 541 |
+
# Enhanced information sections
|
| 542 |
with gr.Row():
|
| 543 |
with gr.Column():
|
| 544 |
gr.HTML("""
|
| 545 |
+
<div style="background: linear-gradient(45deg, #FFF3E0, #FFE0B2); padding: 25px; border-radius: 15px; border-left: 6px solid #FF9800; box-shadow: 0 6px 20px rgba(0,0,0,0.1);">
|
| 546 |
+
<h3>π‘οΈ Advanced Security Features</h3>
|
| 547 |
+
<ul style="line-height: 1.8;">
|
| 548 |
+
<li><strong>π Champion Model:</strong> ResNet-18 achieved perfect 100% accuracy</li>
|
| 549 |
+
<li><strong>π Multi-Model Architecture:</strong> 4 state-of-the-art models to choose from</li>
|
| 550 |
+
<li><strong>π― Zero False Rejections:</strong> All models achieved 0% FRR</li>
|
| 551 |
+
<li><strong>β‘ Real-Time Processing:</strong> Optimized for fast authentication</li>
|
| 552 |
+
<li><strong>π Detailed Analytics:</strong> Comprehensive prediction visualization</li>
|
| 553 |
+
<li><strong>π Adjustable Security:</strong> Customizable confidence thresholds</li>
|
| 554 |
</ul>
|
| 555 |
</div>
|
| 556 |
""")
|
| 557 |
|
| 558 |
with gr.Column():
|
| 559 |
gr.HTML("""
|
| 560 |
+
<div style="background: linear-gradient(45deg, #E8F5E8, #C8E6C9); padding: 25px; border-radius: 15px; border-left: 6px solid #4CAF50; box-shadow: 0 6px 20px rgba(0,0,0,0.1);">
|
| 561 |
+
<h3>π Usage Instructions</h3>
|
| 562 |
+
<ol style="line-height: 1.8;">
|
| 563 |
+
<li><strong>π€ Upload Audio:</strong> Record or upload voice sample (3 seconds optimal)</li>
|
| 564 |
+
<li><strong>π€ Select Model:</strong> Choose from our trained models (ResNet-18 recommended)</li>
|
| 565 |
+
<li><strong>ποΈ Set Threshold:</strong> Adjust security level (0.8 recommended for high security)</li>
|
| 566 |
+
<li><strong>π Authenticate:</strong> Click to process and analyze your voice</li>
|
| 567 |
+
<li><strong>π Review Results:</strong> Check detailed analysis and confidence metrics</li>
|
| 568 |
</ol>
|
| 569 |
+
<div style="background: rgba(76, 175, 80, 0.1); padding: 10px; border-radius: 8px; margin-top: 15px;">
|
| 570 |
+
<strong>π‘ Tip:</strong> ResNet-18 offers perfect accuracy with optimal performance!
|
| 571 |
+
</div>
|
| 572 |
</div>
|
| 573 |
""")
|
| 574 |
|
| 575 |
+
# Training details section
|
| 576 |
+
with gr.Row():
|
| 577 |
+
gr.HTML("""
|
| 578 |
+
<div style="background: linear-gradient(45deg, #E3F2FD, #BBDEFB); padding: 25px; border-radius: 15px; border-left: 6px solid #2196F3; box-shadow: 0 6px 20px rgba(0,0,0,0.1);">
|
| 579 |
+
<h3>π Training Details & Achievements</h3>
|
| 580 |
+
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; margin-top: 15px;">
|
| 581 |
+
<div>
|
| 582 |
+
<h4>π Dataset Information</h4>
|
| 583 |
+
<ul>
|
| 584 |
+
<li><strong>Users:</strong> 26 unique speakers</li>
|
| 585 |
+
<li><strong>Samples:</strong> 1,693 base samples</li>
|
| 586 |
+
<li><strong>Augmentation:</strong> 3x factor for training</li>
|
| 587 |
+
<li><strong>GPU:</strong> Tesla T4 (14.7 GB)</li>
|
| 588 |
+
</ul>
|
| 589 |
+
</div>
|
| 590 |
+
<div>
|
| 591 |
+
<h4>π Best Model Achievements</h4>
|
| 592 |
+
<ul>
|
| 593 |
+
<li><strong>ResNet-18:</strong> 100% Perfect Accuracy π₯</li>
|
| 594 |
+
<li><strong>Parameters:</strong> 11.3M (4.9M trainable)</li>
|
| 595 |
+
<li><strong>Training Time:</strong> 20 epochs (~14 minutes)</li>
|
| 596 |
+
<li><strong>Security Score:</strong> 0.9997</li>
|
| 597 |
+
</ul>
|
| 598 |
+
</div>
|
| 599 |
+
</div>
|
| 600 |
+
</div>
|
| 601 |
+
""")
|
| 602 |
+
|
| 603 |
# Event handlers
|
| 604 |
model_selector.change(
|
| 605 |
fn=get_model_info,
|
|
|
|
| 613 |
outputs=[status_output, message_output, confidence_output, plot_output, detailed_info]
|
| 614 |
)
|
| 615 |
|
| 616 |
+
# Enhanced footer
|
| 617 |
gr.HTML("""
|
| 618 |
+
<div style="text-align: center; padding: 25px; margin-top: 40px; background: linear-gradient(45deg, #37474F, #455A64); color: white; border-radius: 15px; box-shadow: 0 8px 25px rgba(0,0,0,0.2);">
|
| 619 |
+
<h4>Developed with PyTorch & Gradio</h4>
|
| 620 |
+
<p>© 2025 - Voice Security System. All rights reserved.</p>
|
| 621 |
</div>
|
| 622 |
""")
|
| 623 |
|
| 624 |
+
|
| 625 |
# Launch configuration
|
| 626 |
if __name__ == "__main__":
|
| 627 |
app.launch(
|