Tumo505 commited on
Commit
e412a40
Β·
1 Parent(s): d4303a2

Add multi-file upload support with automatic WFDB pair detection

Browse files
Files changed (1) hide show
  1. app.py +51 -10
app.py CHANGED
@@ -11,6 +11,7 @@ import numpy as np
11
  import plotly.graph_objects as go
12
  from huggingface_hub import hf_hub_download
13
  import tempfile
 
14
  from pathlib import Path
15
 
16
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
@@ -310,7 +311,7 @@ except Exception as e:
310
  traceback.print_exc()
311
 
312
  def predict_ecg(file_obj):
313
- """Main prediction function"""
314
 
315
  if model is None:
316
  return (
@@ -320,11 +321,47 @@ def predict_ecg(file_obj):
320
  )
321
 
322
  try:
323
- # Read file
324
- if isinstance(file_obj, str):
325
- file_path = file_obj
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  else:
327
- file_path = file_obj.name if hasattr(file_obj, 'name') else str(file_obj)
 
 
 
 
328
 
329
  # Load ECG using universal loader
330
  print(f"Loading file: {file_path}")
@@ -494,13 +531,15 @@ with gr.Blocks(
494
  gr.Markdown("""
495
  ### Upload Your ECG
496
 
 
 
497
  **Clinical & Standardized Formats:**
498
  - `.dcm` – DICOM (medical imaging, PACS systems)
499
  - `.scp` – SCP-ECG (European interoperability standard)
500
  - `.xml` – HL7 aECG / FDA XML (clinical trials, regulatory)
501
 
502
- ** Research & PhysioNet Formats:**
503
- - `.hea` + `.dat` – WFDB (MIT-BIH, PhysioNet) **Requires BOTH files**
504
  - `.edf` – European Data Format (multi-channel biosignals)
505
 
506
  **Generic / Export Formats:**
@@ -509,6 +548,7 @@ with gr.Blocks(
509
  - `.mat` – MATLAB format
510
  - `.h5 / .hdf5` – HDF5 (efficient large-scale datasets)
511
  - `.raw / .bin` – Binary ECG data
 
512
 
513
  **Architecture Auto-Conversion:**
514
  - Multi-lead (12 leads): Used directly
@@ -519,14 +559,15 @@ with gr.Blocks(
519
 
520
  ---
521
 
522
- **WFDB Note:** `.hea` and `.dat` must be in the same directory. If they're separate, please upload them as a ZIP archive or both files together if the interface allows multi-file selection.
523
  """)
524
 
525
  file_input = gr.File(
526
- label="ECG File",
 
527
  file_types=[".csv", ".txt", ".tsv", ".npy", ".hea", ".dat",
528
  ".dcm", ".mat", ".h5", ".hdf5", ".edf", ".xml",
529
- ".raw", ".bin", ".bat", ".ecg"],
530
  type="filepath"
531
  )
532
 
 
11
  import plotly.graph_objects as go
12
  from huggingface_hub import hf_hub_download
13
  import tempfile
14
+ import shutil
15
  from pathlib import Path
16
 
17
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
311
  traceback.print_exc()
312
 
313
  def predict_ecg(file_obj):
314
+ """Main prediction function - handles single or multiple files"""
315
 
316
  if model is None:
317
  return (
 
321
  )
322
 
323
  try:
324
+ # Handle multiple file uploads (list) or single file
325
+ file_path = None
326
+
327
+ if isinstance(file_obj, list):
328
+ # Multiple files uploaded
329
+ if not file_obj:
330
+ return ("**Error**: No files uploaded", None)
331
+
332
+ # Look for WFDB pairs (.hea + .dat)
333
+ files = [str(f.name) if hasattr(f, 'name') else str(f) for f in file_obj]
334
+ hea_files = [f for f in files if f.lower().endswith('.hea')]
335
+ dat_files = [f for f in files if f.lower().endswith('.dat')]
336
+
337
+ if hea_files and dat_files:
338
+ # WFDB pair detected - both files present
339
+ # Copy .dat file next to .hea file for WFDB to work
340
+ import shutil
341
+ hea_path = hea_files[0]
342
+ dat_path = dat_files[0]
343
+
344
+ # Get directory of .hea file
345
+ hea_dir = Path(hea_path).parent
346
+ dat_filename = Path(dat_path).name
347
+ target_dat_path = hea_dir / dat_filename
348
+
349
+ # Copy .dat file to same directory as .hea if not already there
350
+ if str(target_dat_path) != dat_path:
351
+ shutil.copy(dat_path, target_dat_path)
352
+
353
+ file_path = hea_path
354
+ print(f"WFDB pair detected: {hea_path} + {dat_path}")
355
+ else:
356
+ # No WFDB pair, use first file
357
+ file_path = str(file_obj[0].name) if hasattr(file_obj[0], 'name') else str(file_obj[0])
358
+ print(f"Multiple files uploaded, using first: {file_path}")
359
  else:
360
+ # Single file (backward compatible)
361
+ if isinstance(file_obj, str):
362
+ file_path = file_obj
363
+ else:
364
+ file_path = file_obj.name if hasattr(file_obj, 'name') else str(file_obj)
365
 
366
  # Load ECG using universal loader
367
  print(f"Loading file: {file_path}")
 
531
  gr.Markdown("""
532
  ### Upload Your ECG
533
 
534
+ **βœ… Multi-file upload supported!** Upload multiple files at once, especially for WFDB pairs.
535
+
536
  **Clinical & Standardized Formats:**
537
  - `.dcm` – DICOM (medical imaging, PACS systems)
538
  - `.scp` – SCP-ECG (European interoperability standard)
539
  - `.xml` – HL7 aECG / FDA XML (clinical trials, regulatory)
540
 
541
+ **Research & PhysioNet Formats:**
542
+ - `.hea` + `.dat` – WFDB (MIT-BIH, PhysioNet) **Upload both files together**
543
  - `.edf` – European Data Format (multi-channel biosignals)
544
 
545
  **Generic / Export Formats:**
 
548
  - `.mat` – MATLAB format
549
  - `.h5 / .hdf5` – HDF5 (efficient large-scale datasets)
550
  - `.raw / .bin` – Binary ECG data
551
+ - `.zip` – Archive with multiple files
552
 
553
  **Architecture Auto-Conversion:**
554
  - Multi-lead (12 leads): Used directly
 
559
 
560
  ---
561
 
562
+ **πŸ’‘ WFDB Tip:** Upload both `.hea` and `.dat` files together in one go. The system will automatically detect the pair and process them correctly!
563
  """)
564
 
565
  file_input = gr.File(
566
+ label="ECG File(s)",
567
+ file_count="multiple",
568
  file_types=[".csv", ".txt", ".tsv", ".npy", ".hea", ".dat",
569
  ".dcm", ".mat", ".h5", ".hdf5", ".edf", ".xml",
570
+ ".raw", ".bin", ".bat", ".ecg", ".zip"],
571
  type="filepath"
572
  )
573