Spaces:
Sleeping
Sleeping
Add support for .hea (WFDB) and .bat file formats
Browse files- app.py +68 -14
- requirements.txt +1 -0
app.py
CHANGED
|
@@ -95,16 +95,66 @@ def predict_ecg(file_obj):
|
|
| 95 |
# Load ECG data - handle multiple formats
|
| 96 |
print(f"Loading file: {file_path}")
|
| 97 |
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
try:
|
| 103 |
-
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
except:
|
| 106 |
-
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
print(f"Loaded shape: {ecg.shape}")
|
| 110 |
|
|
@@ -270,15 +320,19 @@ with gr.Blocks(
|
|
| 270 |
### Upload Your ECG
|
| 271 |
|
| 272 |
**Supported Formats:**
|
| 273 |
-
- CSV / TSV / TXT
|
| 274 |
- NumPy .npy file
|
|
|
|
|
|
|
|
|
|
| 275 |
|
| 276 |
**Requirements:**
|
| 277 |
-
-
|
| 278 |
-
-
|
| 279 |
-
-
|
|
|
|
| 280 |
|
| 281 |
-
**Example Structure:**
|
| 282 |
```
|
| 283 |
lead_I, lead_II, ..., lead_aVF
|
| 284 |
0.123, 0.456, ..., 0.789
|
|
@@ -288,7 +342,7 @@ with gr.Blocks(
|
|
| 288 |
|
| 289 |
file_input = gr.File(
|
| 290 |
label="ECG File",
|
| 291 |
-
file_types=[".csv", ".txt", ".tsv", ".npy"],
|
| 292 |
type="filepath"
|
| 293 |
)
|
| 294 |
|
|
|
|
| 95 |
# Load ECG data - handle multiple formats
|
| 96 |
print(f"Loading file: {file_path}")
|
| 97 |
|
| 98 |
+
# Detect format by extension
|
| 99 |
+
if file_path.endswith('.hea'):
|
| 100 |
+
# WFDB (PhysioNet) format
|
| 101 |
+
print("Detected WFDB (.hea) format...")
|
| 102 |
try:
|
| 103 |
+
import wfdb
|
| 104 |
+
# Load the record (without extension)
|
| 105 |
+
record_path = file_path.replace('.hea', '')
|
| 106 |
+
record = wfdb.rdrecord(record_path)
|
| 107 |
+
ecg = record.p_signal # Get signal data
|
| 108 |
+
print(f"WFDB loaded: {ecg.shape}")
|
| 109 |
+
except ImportError:
|
| 110 |
+
return (
|
| 111 |
+
"**Error**: WFDB library not installed\n"
|
| 112 |
+
"Python-wfdb package required for .hea files",
|
| 113 |
+
None
|
| 114 |
+
)
|
| 115 |
+
except Exception as e:
|
| 116 |
+
return (f"**WFDB Error**: {str(e)}", None)
|
| 117 |
+
|
| 118 |
+
elif file_path.endswith('.bat'):
|
| 119 |
+
# BAT format (binary or text batch format)
|
| 120 |
+
print("Detected BAT format...")
|
| 121 |
+
try:
|
| 122 |
+
# Try reading as binary NumPy array first
|
| 123 |
+
ecg = np.fromfile(file_path, dtype=np.float32)
|
| 124 |
+
# Reshape if needed - assume 128 samples per lead or similar
|
| 125 |
+
if len(ecg) % 12 == 0:
|
| 126 |
+
ecg = ecg.reshape(12, -1)
|
| 127 |
+
else:
|
| 128 |
+
# Single lead, will be replicated later
|
| 129 |
+
ecg = ecg.reshape(1, -1)
|
| 130 |
+
print(f"BAT loaded: {ecg.shape}")
|
| 131 |
+
except:
|
| 132 |
+
try:
|
| 133 |
+
# Try text format
|
| 134 |
+
ecg = np.loadtxt(file_path)
|
| 135 |
+
if ecg.ndim == 1:
|
| 136 |
+
ecg = ecg.reshape(1, -1)
|
| 137 |
+
except Exception as e:
|
| 138 |
+
return (f"**BAT Error**: Could not parse file - {str(e)}", None)
|
| 139 |
+
|
| 140 |
+
else:
|
| 141 |
+
# Try standard text formats (CSV, space-separated, tab-separated, .npy)
|
| 142 |
+
try:
|
| 143 |
+
if file_path.endswith('.npy'):
|
| 144 |
+
ecg = np.load(file_path)
|
| 145 |
+
else:
|
| 146 |
+
# Try space-separated (UCR/ArrowHead format)
|
| 147 |
+
ecg = np.genfromtxt(file_path, delimiter=None)
|
| 148 |
except:
|
| 149 |
+
try:
|
| 150 |
+
# Try comma-separated
|
| 151 |
+
ecg = np.loadtxt(file_path, delimiter=',')
|
| 152 |
+
except:
|
| 153 |
+
try:
|
| 154 |
+
# Try tab-separated
|
| 155 |
+
ecg = np.loadtxt(file_path, delimiter='\t')
|
| 156 |
+
except Exception as e:
|
| 157 |
+
return (f"**File Error**: Could not parse file format - {str(e)}", None)
|
| 158 |
|
| 159 |
print(f"Loaded shape: {ecg.shape}")
|
| 160 |
|
|
|
|
| 320 |
### Upload Your ECG
|
| 321 |
|
| 322 |
**Supported Formats:**
|
| 323 |
+
- CSV / TSV / TXT (space, comma, or tab-separated)
|
| 324 |
- NumPy .npy file
|
| 325 |
+
- WFDB .hea (PhysioNet format)
|
| 326 |
+
- BAT (binary or batch ECG files)
|
| 327 |
+
- UCR/ArrowHead format (UCR5000, etc.)
|
| 328 |
|
| 329 |
**Requirements:**
|
| 330 |
+
- Multi-lead: (N leads, M samples)
|
| 331 |
+
- Single-lead: Will be replicated to 12 leads
|
| 332 |
+
- Sampling Rate: Any (will be normalized)
|
| 333 |
+
- Will auto-pad/trim to 5000 samples
|
| 334 |
|
| 335 |
+
**Example Structure (CSV/TXT):**
|
| 336 |
```
|
| 337 |
lead_I, lead_II, ..., lead_aVF
|
| 338 |
0.123, 0.456, ..., 0.789
|
|
|
|
| 342 |
|
| 343 |
file_input = gr.File(
|
| 344 |
label="ECG File",
|
| 345 |
+
file_types=[".csv", ".txt", ".tsv", ".npy", ".hea", ".bat"],
|
| 346 |
type="filepath"
|
| 347 |
)
|
| 348 |
|
requirements.txt
CHANGED
|
@@ -6,3 +6,4 @@ numpy>=1.24.0
|
|
| 6 |
scipy>=1.10.0
|
| 7 |
plotly>=5.17.0
|
| 8 |
huggingface-hub>=0.19.0
|
|
|
|
|
|
| 6 |
scipy>=1.10.0
|
| 7 |
plotly>=5.17.0
|
| 8 |
huggingface-hub>=0.19.0
|
| 9 |
+
wfdb>=4.0.0
|