mandipgoswami commited on
Commit
e3ad960
·
verified ·
1 Parent(s): 73c1877

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +141 -316
app.py CHANGED
@@ -7,11 +7,12 @@ from pathlib import Path
7
  import gradio as gr
8
  import librosa
9
  import matplotlib
 
10
  import matplotlib.pyplot as plt
11
  import numpy as np
12
- from transformers import pipeline
13
 
14
- matplotlib.use("Agg") # Non-interactive backend
 
15
 
16
  # Dataset metadata
17
  DATASET_INFO = {
@@ -24,7 +25,6 @@ DATASET_INFO = {
24
  "total_hours": round(50000 * 10.0 / 3600, 2),
25
  }
26
 
27
- # Anomaly subtypes mapping
28
  ANOMALY_SUBTYPES = {
29
  "fan": ["bearing_fault", "imbalance", "obstruction"],
30
  "pump": ["bearing_fault", "cavitation", "overheating"],
@@ -34,7 +34,6 @@ ANOMALY_SUBTYPES = {
34
  "valve": ["cavitation", "obstruction"],
35
  }
36
 
37
- # Placeholder model - replace with actual trained model
38
  MODEL_NAME = "YOUR_HF_USERNAME/AnomalyMachine-Classifier"
39
  model = None
40
 
@@ -43,19 +42,12 @@ def load_model():
43
  """Lazy load the audio classification model."""
44
  global model
45
  if model is None:
46
- try:
47
- model = pipeline(
48
- "audio-classification",
49
- model=MODEL_NAME,
50
- )
51
- except Exception as e:
52
- print(f"Warning: Could not load model {MODEL_NAME}: {e}")
53
- print("Using placeholder predictions for demo.")
54
- model = "placeholder"
55
  return model
56
 
57
 
58
- def create_mel_spectrogram(audio_path: str, title: str = "Mel Spectrogram") -> str:
59
  """Create a mel spectrogram visualization from audio file."""
60
  try:
61
  y, sr = librosa.load(audio_path, sr=22050, mono=True)
@@ -76,7 +68,6 @@ def create_mel_spectrogram(audio_path: str, title: str = "Mel Spectrogram") -> s
76
  plt.colorbar(img, ax=ax, format="%+2.0f dB")
77
  plt.tight_layout()
78
 
79
- # Save to temporary file
80
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
81
  plt.savefig(temp_file.name, dpi=100, bbox_inches="tight")
82
  plt.close()
@@ -86,14 +77,11 @@ def create_mel_spectrogram(audio_path: str, title: str = "Mel Spectrogram") -> s
86
  return None
87
 
88
 
89
- def get_reference_audio(machine_type: str) -> str:
90
  """Get path to reference normal audio for a machine type."""
91
  examples_dir = Path(__file__).parent / "examples"
92
- # Look for a normal example (naming convention: {machine}_normal_*.wav)
93
- ref_pattern = f"{machine_type}_*_normal_*.wav"
94
- ref_files = list(examples_dir.glob(ref_pattern))
95
  if not ref_files:
96
- # Fallback: use any example for this machine
97
  ref_files = list(examples_dir.glob(f"{machine_type}_*.wav"))
98
  return str(ref_files[0]) if ref_files else None
99
 
@@ -101,22 +89,19 @@ def get_reference_audio(machine_type: str) -> str:
101
  def predict_anomaly(audio_file, machine_type):
102
  """Predict if audio contains an anomaly."""
103
  if audio_file is None:
104
- return None, None, None, None, None
105
 
106
- # Load model
107
  model_instance = load_model()
108
 
109
- # Create spectrograms
110
  input_spec = create_mel_spectrogram(audio_file, f"Input Audio - {machine_type}")
111
  ref_audio = get_reference_audio(machine_type)
112
  ref_spec = None
113
  if ref_audio:
114
  ref_spec = create_mel_spectrogram(ref_audio, f"Reference Normal - {machine_type}")
115
 
116
- # Make prediction
117
  if model_instance == "placeholder":
118
- # Placeholder predictions for demo
119
  import random
 
120
  is_anomaly = random.random() > 0.5
121
  confidence = random.uniform(0.7, 0.95)
122
  if is_anomaly:
@@ -128,10 +113,8 @@ def predict_anomaly(audio_file, machine_type):
128
  label = "NORMAL"
129
  color = "green"
130
  else:
131
- # Real model prediction
132
  try:
133
  results = model_instance(audio_file)
134
- # Assuming model returns list of dicts with 'label' and 'score'
135
  top_result = results[0] if isinstance(results, list) else results
136
  label_str = top_result.get("label", "").lower()
137
  confidence = top_result.get("score", 0.5)
@@ -140,7 +123,6 @@ def predict_anomaly(audio_file, machine_type):
140
  if is_anomaly:
141
  label = "ANOMALY"
142
  color = "red"
143
- # Try to extract anomaly subtype from label
144
  anomaly_subtype = "unknown"
145
  for subtype in ANOMALY_SUBTYPES.get(machine_type, []):
146
  if subtype in label_str:
@@ -157,7 +139,6 @@ def predict_anomaly(audio_file, machine_type):
157
  confidence = 0.0
158
  anomaly_subtype = "none"
159
 
160
- # Format result HTML
161
  result_html = f"""
162
  <div style="text-align: center; padding: 20px;">
163
  <h2 style="color: {color}; font-size: 48px; margin: 20px 0;">
@@ -168,251 +149,32 @@ def predict_anomaly(audio_file, machine_type):
168
  </div>
169
  """
170
 
171
- return result_html, confidence, input_spec, ref_spec, audio_file
172
 
173
 
174
  def create_dataset_gallery():
175
- """Create gallery of example spectrograms for each machine type."""
176
  examples_dir = Path(__file__).parent / "examples"
177
  if not examples_dir.exists():
178
- return []
179
 
180
- gallery_items = []
 
 
181
  for machine in DATASET_INFO["machines"]:
182
- # Find normal and anomalous examples
183
  normal_files = list(examples_dir.glob(f"{machine}_*_normal_*.wav"))
184
  anomaly_files = list(examples_dir.glob(f"{machine}_*_anomalous_*.wav"))
185
 
186
- normal_spec = None
187
- anomaly_spec = None
188
-
189
  if normal_files:
190
- normal_spec = create_mel_spectrogram(str(normal_files[0]), f"{machine} - Normal")
 
 
191
  if anomaly_files:
192
- anomaly_spec = create_mel_spectrogram(str(anomaly_files[0]), f"{machine} - Anomaly")
193
-
194
- if normal_spec or anomaly_spec:
195
- gallery_items.append((normal_spec, anomaly_spec, machine))
196
-
197
- return gallery_items
198
-
199
-
200
- def build_explore_tab():
201
- """Build the dataset exploration tab."""
202
- gallery_items = create_dataset_gallery()
203
-
204
- # Populate galleries
205
- normal_images = [item[0] for item in gallery_items if item[0] and item[0] is not None]
206
- anomaly_images = [item[1] for item in gallery_items if item[1] and item[1] is not None]
207
-
208
- with gr.Row():
209
- with gr.Column():
210
- gr.Markdown("### Normal Examples")
211
- normal_gallery = gr.Gallery(
212
- label="Normal Machine Sounds",
213
- show_label=False,
214
- elem_id="normal_gallery",
215
- columns=2,
216
- rows=3,
217
- height="auto",
218
- value=normal_images if normal_images else None,
219
- )
220
- with gr.Column():
221
- gr.Markdown("### Anomaly Examples")
222
- anomaly_gallery = gr.Gallery(
223
- label="Anomalous Machine Sounds",
224
- show_label=False,
225
- elem_id="anomaly_gallery",
226
- columns=2,
227
- rows=3,
228
- height="auto",
229
- value=anomaly_images if anomaly_images else None,
230
- )
231
-
232
- # Dataset statistics
233
- with gr.Accordion("Dataset Statistics", open=False):
234
- stats_html = f"""
235
- <div style="padding: 20px;">
236
- <h3>AnomalyMachine-50K Dataset</h3>
237
- <ul style="font-size: 16px; line-height: 2;">
238
- <li><strong>Total Clips:</strong> {DATASET_INFO['total_clips']:,}</li>
239
- <li><strong>Total Duration:</strong> {DATASET_INFO['total_hours']} hours</li>
240
- <li><strong>Machine Types:</strong> {len(DATASET_INFO['machines'])}</li>
241
- <li><strong>Normal Ratio:</strong> {DATASET_INFO['normal_ratio']:.0%}</li>
242
- <li><strong>Anomalous Ratio:</strong> {DATASET_INFO['anomalous_ratio']:.0%}</li>
243
- <li><strong>Sample Rate:</strong> {DATASET_INFO['sample_rate']} Hz</li>
244
- <li><strong>Clip Duration:</strong> {DATASET_INFO['clip_duration_seconds']} seconds</li>
245
- </ul>
246
- <h4>Machine Breakdown:</h4>
247
- <ul>
248
- {''.join([f'<li>{m.replace("_", " ").title()}</li>' for m in DATASET_INFO['machines']])}
249
- </ul>
250
- </div>
251
- """
252
- gr.HTML(stats_html)
253
 
254
- # Download button
255
- dataset_url = "https://huggingface.co/datasets/AnomalyMachine-50K"
256
- gr.Markdown(f"""
257
- <div style="text-align: center; padding: 20px;">
258
- <a href="{dataset_url}" target="_blank">
259
- <button style="background-color: #007bff; color: white; padding: 15px 30px;
260
- font-size: 18px; border: none; border-radius: 5px; cursor: pointer;">
261
- 📥 Download Dataset
262
- </button>
263
- </a>
264
- </div>
265
- """)
266
-
267
- return normal_gallery, anomaly_gallery, normal_images, anomaly_images
268
-
269
-
270
- def build_detect_tab():
271
- """Build the anomaly detection tab."""
272
- with gr.Row():
273
- with gr.Column(scale=1):
274
- audio_input = gr.Audio(
275
- label="Upload Audio or Record",
276
- type="filepath",
277
- sources=["upload", "microphone"],
278
- )
279
- machine_dropdown = gr.Dropdown(
280
- choices=DATASET_INFO["machines"],
281
- label="Machine Type",
282
- value=DATASET_INFO["machines"][0],
283
- info="Select the type of machine in the audio",
284
- )
285
- predict_btn = gr.Button("Detect Anomaly", variant="primary", size="lg")
286
-
287
- with gr.Column(scale=2):
288
- result_html = gr.HTML(label="Prediction Result")
289
- confidence_bar = gr.Slider(
290
- minimum=0,
291
- maximum=1,
292
- value=0,
293
- label="Confidence Score",
294
- interactive=False,
295
- )
296
-
297
- with gr.Row():
298
- with gr.Column():
299
- input_spec = gr.Image(label="Input Audio Spectrogram")
300
- with gr.Column():
301
- ref_spec = gr.Image(label="Reference Normal Spectrogram")
302
-
303
- audio_output = gr.Audio(label="Processed Audio", visible=False)
304
-
305
- predict_btn.click(
306
- fn=predict_anomaly,
307
- inputs=[audio_input, machine_dropdown],
308
- outputs=[result_html, confidence_bar, input_spec, ref_spec, audio_output],
309
- )
310
-
311
- return (
312
- audio_input,
313
- machine_dropdown,
314
- predict_btn,
315
- result_html,
316
- confidence_bar,
317
- input_spec,
318
- ref_spec,
319
- audio_output,
320
- )
321
-
322
-
323
- def build_header():
324
- """Build the app header."""
325
- return gr.Markdown(
326
- """
327
- <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
328
- border-radius: 10px; margin-bottom: 20px;">
329
- <h1 style="color: white; margin: 0;">🏭 AnomalyMachine-50K</h1>
330
- <p style="color: rgba(255,255,255,0.9); font-size: 18px; margin: 10px 0;">
331
- Synthetic Industrial Machine Sound Anomaly Detection Dataset
332
- </p>
333
- <p style="color: rgba(255,255,255,0.8);">
334
- <a href="https://huggingface.co/datasets/AnomalyMachine-50K"
335
- style="color: white; text-decoration: underline;" target="_blank">
336
- View Dataset on Hugging Face →
337
- </a>
338
- </p>
339
- </div>
340
- """
341
- )
342
-
343
-
344
- def build_footer():
345
- """Build the app footer."""
346
- return gr.Markdown(
347
- """
348
- <div style="text-align: center; padding: 20px; margin-top: 40px; border-top: 1px solid #333;">
349
- <p style="color: #888; font-size: 14px;">
350
- License: <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank"
351
- style="color: #4a9eff;">CC-BY 4.0</a> |
352
- Dataset: <a href="https://huggingface.co/datasets/AnomalyMachine-50K" target="_blank"
353
- style="color: #4a9eff;">AnomalyMachine-50K</a> |
354
- GitHub: <a href="https://github.com/mandip42/anomaly-machine-50k" target="_blank"
355
- style="color: #4a9eff;">mandip42/anomaly-machine-50k</a>
356
- </p>
357
- </div>
358
- """
359
- )
360
-
361
-
362
- def build_how_it_works():
363
- """Build the 'How it works' accordion."""
364
- how_it_works_html = """
365
- <div style="padding: 20px; line-height: 1.8;">
366
- <h3>Signal Processing-Based Synthesis</h3>
367
- <p>
368
- The AnomalyMachine-50K dataset is generated entirely using deterministic signal processing
369
- techniques—no neural audio models are used. This ensures reproducibility, lightweight generation,
370
- and freedom from copyright concerns.
371
- </p>
372
-
373
- <h4>1. Base Machine Sound Generation</h4>
374
- <p>
375
- Each machine type has a dedicated synthesis model:
376
- </p>
377
- <ul>
378
- <li><strong>Fan:</strong> Broadband noise + rotating blade harmonics (50-200 Hz)</li>
379
- <li><strong>Pump:</strong> Low-frequency rumble (20-80 Hz) + rhythmic pressure pulses</li>
380
- <li><strong>Compressor:</strong> 60 Hz motor hum + harmonics with cyclic compression envelope</li>
381
- <li><strong>Conveyor Belt:</strong> Rhythmic tapping + friction noise</li>
382
- <li><strong>Electric Motor:</strong> Tonal fundamental (1200-3600 RPM) + harmonics + brush noise</li>
383
- <li><strong>Valve:</strong> Turbulent flow noise + actuation clicks</li>
384
- </ul>
385
-
386
- <h4>2. Operating Condition Modulation</h4>
387
- <p>
388
- Conditions (idle, normal_load, high_load) modulate amplitude and harmonic content.
389
- </p>
390
-
391
- <h4>3. Anomaly Injection</h4>
392
- <p>
393
- Anomalies are injected via signal transformations:
394
- </p>
395
- <ul>
396
- <li><strong>Bearing Fault:</strong> Periodic impulsive spikes</li>
397
- <li><strong>Imbalance:</strong> Sinusoidal amplitude modulation</li>
398
- <li><strong>Cavitation:</strong> Burst noise events</li>
399
- <li><strong>Overheating:</strong> Gradually increasing high-frequency noise</li>
400
- <li><strong>Obstruction:</strong> Intermittent amplitude drops + resonance shifts</li>
401
- </ul>
402
-
403
- <h4>4. Background Noise</h4>
404
- <p>
405
- Factory-floor ambience (pink noise + 60/120 Hz hum) is mixed at configurable SNR levels.
406
- </p>
407
-
408
- <p style="margin-top: 20px; font-style: italic;">
409
- All synthesis is deterministic and reproducible with a fixed random seed.
410
- </p>
411
- </div>
412
- """
413
- return gr.Accordion("How It Works", open=False).update(
414
- value=gr.HTML(how_it_works_html)
415
- )
416
 
417
 
418
  def main():
@@ -420,72 +182,135 @@ def main():
420
  theme = gr.themes.Monochrome(
421
  primary_hue="red",
422
  secondary_hue="gray",
423
- font=("Helvetica", "ui-sans-serif", "system-ui"),
424
  )
425
 
426
  with gr.Blocks(theme=theme, title="AnomalyMachine-50K Demo") as app:
427
- build_header()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
428
 
429
  with gr.Tabs():
430
  with gr.Tab("🔍 Detect Anomaly"):
431
  with gr.Accordion("How It Works", open=False):
432
- gr.HTML("""
433
- <div style="padding: 20px; line-height: 1.8;">
434
- <h3>Signal Processing-Based Synthesis</h3>
435
- <p>
436
- The AnomalyMachine-50K dataset is generated entirely using deterministic signal processing
437
- techniques—no neural audio models are used. This ensures reproducibility, lightweight generation,
438
- and freedom from copyright concerns.
439
- </p>
440
-
441
- <h4>1. Base Machine Sound Generation</h4>
442
- <p>
443
- Each machine type has a dedicated synthesis model:
444
- </p>
445
- <ul>
446
- <li><strong>Fan:</strong> Broadband noise + rotating blade harmonics (50-200 Hz)</li>
447
- <li><strong>Pump:</strong> Low-frequency rumble (20-80 Hz) + rhythmic pressure pulses</li>
448
- <li><strong>Compressor:</strong> 60 Hz motor hum + harmonics with cyclic compression envelope</li>
449
- <li><strong>Conveyor Belt:</strong> Rhythmic tapping + friction noise</li>
450
- <li><strong>Electric Motor:</strong> Tonal fundamental (1200-3600 RPM) + harmonics + brush noise</li>
451
- <li><strong>Valve:</strong> Turbulent flow noise + actuation clicks</li>
452
- </ul>
453
-
454
- <h4>2. Operating Condition Modulation</h4>
455
- <p>
456
- Conditions (idle, normal_load, high_load) modulate amplitude and harmonic content.
457
- </p>
458
-
459
- <h4>3. Anomaly Injection</h4>
460
- <p>
461
- Anomalies are injected via signal transformations:
462
- </p>
463
- <ul>
464
- <li><strong>Bearing Fault:</strong> Periodic impulsive spikes</li>
465
- <li><strong>Imbalance:</strong> Sinusoidal amplitude modulation</li>
466
- <li><strong>Cavitation:</strong> Burst noise events</li>
467
- <li><strong>Overheating:</strong> Gradually increasing high-frequency noise</li>
468
- <li><strong>Obstruction:</strong> Intermittent amplitude drops + resonance shifts</li>
469
- </ul>
470
-
471
- <h4>4. Background Noise</h4>
472
- <p>
473
- Factory-floor ambience (pink noise + 60/120 Hz hum) is mixed at configurable SNR levels.
474
- </p>
475
-
476
- <p style="margin-top: 20px; font-style: italic;">
477
- All synthesis is deterministic and reproducible with a fixed random seed.
478
- </p>
479
- </div>
480
  """)
481
- build_detect_tab()
482
 
483
- with gr.Tab("📊 Explore Dataset"):
484
- normal_gallery, anomaly_gallery, normal_images, anomaly_images = build_explore_tab()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
485
 
486
- build_footer()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
487
 
488
- app.launch(share=False, server_name="0.0.0.0", server_port=7860)
489
 
490
 
491
  if __name__ == "__main__":
 
7
  import gradio as gr
8
  import librosa
9
  import matplotlib
10
+ matplotlib.use("Agg")
11
  import matplotlib.pyplot as plt
12
  import numpy as np
 
13
 
14
+ # Transformers not needed - using placeholder predictions
15
+ TRANSFORMERS_AVAILABLE = False
16
 
17
  # Dataset metadata
18
  DATASET_INFO = {
 
25
  "total_hours": round(50000 * 10.0 / 3600, 2),
26
  }
27
 
 
28
  ANOMALY_SUBTYPES = {
29
  "fan": ["bearing_fault", "imbalance", "obstruction"],
30
  "pump": ["bearing_fault", "cavitation", "overheating"],
 
34
  "valve": ["cavitation", "obstruction"],
35
  }
36
 
 
37
  MODEL_NAME = "YOUR_HF_USERNAME/AnomalyMachine-Classifier"
38
  model = None
39
 
 
42
  """Lazy load the audio classification model."""
43
  global model
44
  if model is None:
45
+ # Using placeholder predictions (no model needed)
46
+ model = "placeholder"
 
 
 
 
 
 
 
47
  return model
48
 
49
 
50
+ def create_mel_spectrogram(audio_path: str, title: str = "Mel Spectrogram"):
51
  """Create a mel spectrogram visualization from audio file."""
52
  try:
53
  y, sr = librosa.load(audio_path, sr=22050, mono=True)
 
68
  plt.colorbar(img, ax=ax, format="%+2.0f dB")
69
  plt.tight_layout()
70
 
 
71
  temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
72
  plt.savefig(temp_file.name, dpi=100, bbox_inches="tight")
73
  plt.close()
 
77
  return None
78
 
79
 
80
+ def get_reference_audio(machine_type: str):
81
  """Get path to reference normal audio for a machine type."""
82
  examples_dir = Path(__file__).parent / "examples"
83
+ ref_files = list(examples_dir.glob(f"{machine_type}_*_normal_*.wav"))
 
 
84
  if not ref_files:
 
85
  ref_files = list(examples_dir.glob(f"{machine_type}_*.wav"))
86
  return str(ref_files[0]) if ref_files else None
87
 
 
89
  def predict_anomaly(audio_file, machine_type):
90
  """Predict if audio contains an anomaly."""
91
  if audio_file is None:
92
+ return None, None, None, None
93
 
 
94
  model_instance = load_model()
95
 
 
96
  input_spec = create_mel_spectrogram(audio_file, f"Input Audio - {machine_type}")
97
  ref_audio = get_reference_audio(machine_type)
98
  ref_spec = None
99
  if ref_audio:
100
  ref_spec = create_mel_spectrogram(ref_audio, f"Reference Normal - {machine_type}")
101
 
 
102
  if model_instance == "placeholder":
 
103
  import random
104
+ random.seed(hash(audio_file) % 1000)
105
  is_anomaly = random.random() > 0.5
106
  confidence = random.uniform(0.7, 0.95)
107
  if is_anomaly:
 
113
  label = "NORMAL"
114
  color = "green"
115
  else:
 
116
  try:
117
  results = model_instance(audio_file)
 
118
  top_result = results[0] if isinstance(results, list) else results
119
  label_str = top_result.get("label", "").lower()
120
  confidence = top_result.get("score", 0.5)
 
123
  if is_anomaly:
124
  label = "ANOMALY"
125
  color = "red"
 
126
  anomaly_subtype = "unknown"
127
  for subtype in ANOMALY_SUBTYPES.get(machine_type, []):
128
  if subtype in label_str:
 
139
  confidence = 0.0
140
  anomaly_subtype = "none"
141
 
 
142
  result_html = f"""
143
  <div style="text-align: center; padding: 20px;">
144
  <h2 style="color: {color}; font-size: 48px; margin: 20px 0;">
 
149
  </div>
150
  """
151
 
152
+ return result_html, confidence, input_spec, ref_spec
153
 
154
 
155
  def create_dataset_gallery():
156
+ """Create gallery of example spectrograms."""
157
  examples_dir = Path(__file__).parent / "examples"
158
  if not examples_dir.exists():
159
+ return [], []
160
 
161
+ normal_images = []
162
+ anomaly_images = []
163
+
164
  for machine in DATASET_INFO["machines"]:
 
165
  normal_files = list(examples_dir.glob(f"{machine}_*_normal_*.wav"))
166
  anomaly_files = list(examples_dir.glob(f"{machine}_*_anomalous_*.wav"))
167
 
 
 
 
168
  if normal_files:
169
+ spec = create_mel_spectrogram(str(normal_files[0]), f"{machine} - Normal")
170
+ if spec:
171
+ normal_images.append(spec)
172
  if anomaly_files:
173
+ spec = create_mel_spectrogram(str(anomaly_files[0]), f"{machine} - Anomaly")
174
+ if spec:
175
+ anomaly_images.append(spec)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
+ return normal_images, anomaly_images
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
 
179
 
180
  def main():
 
182
  theme = gr.themes.Monochrome(
183
  primary_hue="red",
184
  secondary_hue="gray",
 
185
  )
186
 
187
  with gr.Blocks(theme=theme, title="AnomalyMachine-50K Demo") as app:
188
+ gr.Markdown("""
189
+ <div style="text-align: center; padding: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
190
+ border-radius: 10px; margin-bottom: 20px;">
191
+ <h1 style="color: white; margin: 0;">🏭 AnomalyMachine-50K</h1>
192
+ <p style="color: rgba(255,255,255,0.9); font-size: 18px; margin: 10px 0;">
193
+ Synthetic Industrial Machine Sound Anomaly Detection Dataset
194
+ </p>
195
+ <p style="color: rgba(255,255,255,0.8);">
196
+ <a href="https://huggingface.co/datasets/AnomalyMachine-50K"
197
+ style="color: white; text-decoration: underline;" target="_blank">
198
+ View Dataset on Hugging Face →
199
+ </a>
200
+ </p>
201
+ </div>
202
+ """)
203
 
204
  with gr.Tabs():
205
  with gr.Tab("🔍 Detect Anomaly"):
206
  with gr.Accordion("How It Works", open=False):
207
+ gr.Markdown("""
208
+ The AnomalyMachine-50K dataset is generated using deterministic signal processing techniques.
209
+ Each machine type has a dedicated synthesis model, and anomalies are injected via signal transformations.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  """)
 
211
 
212
+ with gr.Row():
213
+ with gr.Column(scale=1):
214
+ audio_input = gr.Audio(
215
+ label="Upload Audio or Record",
216
+ type="filepath",
217
+ sources=["upload", "microphone"],
218
+ )
219
+ machine_dropdown = gr.Dropdown(
220
+ choices=DATASET_INFO["machines"],
221
+ label="Machine Type",
222
+ value=DATASET_INFO["machines"][0],
223
+ )
224
+ predict_btn = gr.Button("Detect Anomaly", variant="primary", size="lg")
225
+
226
+ with gr.Column(scale=2):
227
+ result_html = gr.HTML(label="Prediction Result")
228
+ confidence_bar = gr.Slider(
229
+ minimum=0,
230
+ maximum=1,
231
+ value=0,
232
+ label="Confidence Score",
233
+ interactive=False,
234
+ )
235
+
236
+ with gr.Row():
237
+ with gr.Column():
238
+ input_spec = gr.Image(label="Input Audio Spectrogram")
239
+ with gr.Column():
240
+ ref_spec = gr.Image(label="Reference Normal Spectrogram")
241
+
242
+ predict_btn.click(
243
+ fn=predict_anomaly,
244
+ inputs=[audio_input, machine_dropdown],
245
+ outputs=[result_html, confidence_bar, input_spec, ref_spec],
246
+ )
247
 
248
+ with gr.Tab("📊 Explore Dataset"):
249
+ normal_images, anomaly_images = create_dataset_gallery()
250
+
251
+ with gr.Row():
252
+ with gr.Column():
253
+ gr.Markdown("### Normal Examples")
254
+ normal_gallery = gr.Gallery(
255
+ value=normal_images if normal_images else None,
256
+ label="Normal Machine Sounds",
257
+ show_label=False,
258
+ columns=2,
259
+ rows=3,
260
+ height="auto",
261
+ )
262
+ with gr.Column():
263
+ gr.Markdown("### Anomaly Examples")
264
+ anomaly_gallery = gr.Gallery(
265
+ value=anomaly_images if anomaly_images else None,
266
+ label="Anomalous Machine Sounds",
267
+ show_label=False,
268
+ columns=2,
269
+ rows=3,
270
+ height="auto",
271
+ )
272
+
273
+ with gr.Accordion("Dataset Statistics", open=False):
274
+ stats_html = f"""
275
+ <div style="padding: 20px;">
276
+ <h3>AnomalyMachine-50K Dataset</h3>
277
+ <ul style="font-size: 16px; line-height: 2;">
278
+ <li><strong>Total Clips:</strong> {DATASET_INFO['total_clips']:,}</li>
279
+ <li><strong>Total Duration:</strong> {DATASET_INFO['total_hours']} hours</li>
280
+ <li><strong>Machine Types:</strong> {len(DATASET_INFO['machines'])}</li>
281
+ <li><strong>Normal Ratio:</strong> {DATASET_INFO['normal_ratio']:.0%}</li>
282
+ <li><strong>Anomalous Ratio:</strong> {DATASET_INFO['anomalous_ratio']:.0%}</li>
283
+ </ul>
284
+ </div>
285
+ """
286
+ gr.HTML(stats_html)
287
+
288
+ dataset_url = "https://huggingface.co/datasets/AnomalyMachine-50K"
289
+ gr.Markdown(f"""
290
+ <div style="text-align: center; padding: 20px;">
291
+ <a href="{dataset_url}" target="_blank">
292
+ <button style="background-color: #007bff; color: white; padding: 15px 30px;
293
+ font-size: 18px; border: none; border-radius: 5px; cursor: pointer;">
294
+ 📥 Download Dataset
295
+ </button>
296
+ </a>
297
+ </div>
298
+ """)
299
+
300
+ gr.Markdown("""
301
+ <div style="text-align: center; padding: 20px; margin-top: 40px; border-top: 1px solid #333;">
302
+ <p style="color: #888; font-size: 14px;">
303
+ License: <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank"
304
+ style="color: #4a9eff;">CC-BY 4.0</a> |
305
+ Dataset: <a href="https://huggingface.co/datasets/AnomalyMachine-50K" target="_blank"
306
+ style="color: #4a9eff;">AnomalyMachine-50K</a> |
307
+ GitHub: <a href="https://github.com/mandip42/anomaly-machine-50k" target="_blank"
308
+ style="color: #4a9eff;">mandip42/anomaly-machine-50k</a>
309
+ </p>
310
+ </div>
311
+ """)
312
 
313
+ app.launch()
314
 
315
 
316
  if __name__ == "__main__":