greenarcade commited on
Commit
c44bb3e
·
verified ·
1 Parent(s): ad4eb17

Upload Cough Health Analyzer application files

Browse files
Files changed (4) hide show
  1. README.md +87 -12
  2. app.py +275 -0
  3. cough_classification_model.pkl +3 -0
  4. requirements.txt +9 -0
README.md CHANGED
@@ -1,12 +1,87 @@
1
- ---
2
- title: Cough Health Analyzer
3
- emoji: 😻
4
- colorFrom: blue
5
- colorTo: gray
6
- sdk: gradio
7
- sdk_version: 5.25.2
8
- app_file: app.py
9
- pinned: false
10
- ---
11
-
12
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Cough Health Analyzer
2
+
3
+ A Gradio web application for analyzing cough audio to classify health status as 'healthy', 'COVID-19', or 'symptomatic'.
4
+
5
+ ## Features
6
+
7
+ - **Upload Audio**: Upload audio files containing coughs for analysis
8
+ - **Record Audio**: Record coughs directly in the browser for analysis
9
+ - **Live Cough Detection**: Stream audio in real-time to detect and analyze coughs
10
+ - **API Access**: Make API calls to the model for integration with other applications
11
+
12
+ ## Installation
13
+
14
+ 1. Clone this repository:
15
+ ```bash
16
+ git clone <repository-url>
17
+ cd <repository-directory>
18
+ ```
19
+
20
+ 2. Install the required dependencies:
21
+ ```bash
22
+ pip install -r requirements-gradio.txt
23
+ ```
24
+
25
+ 3. Run the application:
26
+ ```bash
27
+ python app.py
28
+ ```
29
+
30
+ The application will be available at http://localhost:7860 by default.
31
+
32
+ ## Deploying to Hugging Face Spaces
33
+
34
+ To deploy this application to Hugging Face Spaces:
35
+
36
+ 1. Create a new Space on [Hugging Face](https://huggingface.co/spaces)
37
+ 2. Choose "Gradio" as the SDK
38
+ 3. Upload the following files to your Space:
39
+ - `app.py`
40
+ - `cough_classification_model.pkl`
41
+ - `requirements-gradio.txt` (rename to `requirements.txt`)
42
+
43
+ The Space will automatically build and deploy your application.
44
+
45
+ ## Using the API
46
+
47
+ You can access the model via API calls. Here's an example using Python:
48
+
49
+ ```python
50
+ import requests
51
+ import json
52
+
53
+ # For file upload
54
+ files = {'audio': open('your_audio_file.wav', 'rb')}
55
+ response = requests.post('YOUR_GRADIO_URL/api/predict', files=files)
56
+ result = json.loads(response.content)
57
+ print(result)
58
+ ```
59
+
60
+ Replace `YOUR_GRADIO_URL` with the URL of your deployed Gradio app.
61
+
62
+ ## Model Information
63
+
64
+ The model is a Random Forest classifier trained on audio features extracted from cough recordings. It classifies coughs into three categories:
65
+
66
+ - **Healthy**: Normal coughs from healthy individuals
67
+ - **COVID-19**: Coughs from individuals with COVID-19
68
+ - **Symptomatic**: Coughs from individuals with respiratory symptoms but not COVID-19
69
+
70
+ ## Live Audio Streaming and Cough Detection
71
+
72
+ The application includes a feature for streaming live audio and detecting coughs in real-time. When a cough is detected, it is automatically analyzed by the model.
73
+
74
+ This feature is useful for:
75
+ - Continuous health monitoring
76
+ - Automated cough counting and analysis
77
+ - Real-time health status updates
78
+
79
+ ## Limitations
80
+
81
+ - The model's accuracy depends on the quality of the audio recording
82
+ - Background noise can affect cough detection and classification
83
+ - The model should not be used as a substitute for professional medical diagnosis
84
+
85
+ ## License
86
+
87
+ [Specify your license here]
app.py ADDED
@@ -0,0 +1,275 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import pickle
3
+ import numpy as np
4
+ import pandas as pd
5
+ import librosa
6
+ import gradio as gr
7
+ from scipy.io import wavfile
8
+ import soundfile as sf
9
+ import tempfile
10
+ import time
11
+
12
+ # Load the model
13
+ def load_model(model_path='cough_classification_model.pkl'):
14
+ with open(model_path, 'rb') as f:
15
+ components = pickle.load(f)
16
+
17
+ return components
18
+
19
+ # Extract features from audio
20
+ def extract_all_features(audio_path, sample_rate=None):
21
+ """Extract comprehensive set of audio features"""
22
+ # Load audio file
23
+ y, sr = librosa.load(audio_path, sr=sample_rate)
24
+
25
+ # Basic features
26
+ features = {}
27
+
28
+ # Duration
29
+ features['duration'] = librosa.get_duration(y=y, sr=sr)
30
+
31
+ # RMS Energy
32
+ features['rms_mean'] = np.mean(librosa.feature.rms(y=y)[0])
33
+ features['rms_std'] = np.std(librosa.feature.rms(y=y)[0])
34
+
35
+ # Zero Crossing Rate
36
+ zcr = librosa.feature.zero_crossing_rate(y)[0]
37
+ features['zcr_mean'] = np.mean(zcr)
38
+ features['zcr_std'] = np.std(zcr)
39
+
40
+ # Spectral Features
41
+ # Spectral Centroid
42
+ centroid = librosa.feature.spectral_centroid(y=y, sr=sr)[0]
43
+ features['spectral_centroid_mean'] = np.mean(centroid)
44
+ features['spectral_centroid_std'] = np.std(centroid)
45
+
46
+ # Spectral Bandwidth
47
+ bandwidth = librosa.feature.spectral_bandwidth(y=y, sr=sr)[0]
48
+ features['spectral_bandwidth_mean'] = np.mean(bandwidth)
49
+ features['spectral_bandwidth_std'] = np.std(bandwidth)
50
+
51
+ # Spectral Contrast
52
+ contrast = librosa.feature.spectral_contrast(y=y, sr=sr)
53
+ features['spectral_contrast_mean'] = np.mean(contrast)
54
+ features['spectral_contrast_std'] = np.std(contrast)
55
+
56
+ # Spectral Rolloff
57
+ rolloff = librosa.feature.spectral_rolloff(y=y, sr=sr)[0]
58
+ features['rolloff_mean'] = np.mean(rolloff)
59
+ features['rolloff_std'] = np.std(rolloff)
60
+
61
+ # MFCCs
62
+ mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
63
+ for i in range(13):
64
+ features[f'mfcc{i+1}_mean'] = np.mean(mfccs[i])
65
+ features[f'mfcc{i+1}_std'] = np.std(mfccs[i])
66
+
67
+ # Chroma Features
68
+ chroma = librosa.feature.chroma_stft(y=y, sr=sr)
69
+ features['chroma_mean'] = np.mean(chroma)
70
+ features['chroma_std'] = np.std(chroma)
71
+
72
+ return features
73
+
74
+ # Function to segment cough from audio
75
+ def segment_cough(x, fs, cough_padding=0.2, min_cough_len=0.2, th_l_multiplier=0.1, th_h_multiplier=2):
76
+ """Segment coughs from audio using a hysteresis comparator on the signal power"""
77
+ cough_mask = np.array([False]*len(x))
78
+
79
+ # Define hysteresis thresholds
80
+ rms = np.sqrt(np.mean(np.square(x)))
81
+ seg_th_l = th_l_multiplier * rms
82
+ seg_th_h = th_h_multiplier * rms
83
+
84
+ # Segment coughs
85
+ coughSegments = []
86
+ padding = round(fs*cough_padding)
87
+ min_cough_samples = round(fs*min_cough_len)
88
+ cough_start = 0
89
+ cough_end = 0
90
+ cough_in_progress = False
91
+ tolerance = round(0.01*fs)
92
+ below_th_counter = 0
93
+
94
+ for i, sample in enumerate(x**2):
95
+ if cough_in_progress:
96
+ if sample < seg_th_l:
97
+ below_th_counter += 1
98
+ if below_th_counter > tolerance:
99
+ cough_end = i+padding if (i+padding < len(x)) else len(x)-1
100
+ cough_in_progress = False
101
+ if (cough_end+1-cough_start-2*padding > min_cough_samples):
102
+ coughSegments.append(x[cough_start:cough_end+1])
103
+ cough_mask[cough_start:cough_end+1] = True
104
+ elif i == (len(x)-1):
105
+ cough_end = i
106
+ cough_in_progress = False
107
+ if (cough_end+1-cough_start-2*padding > min_cough_samples):
108
+ coughSegments.append(x[cough_start:cough_end+1])
109
+ else:
110
+ below_th_counter = 0
111
+ else:
112
+ if sample > seg_th_h:
113
+ cough_start = i-padding if (i-padding >= 0) else 0
114
+ cough_in_progress = True
115
+
116
+ return coughSegments, cough_mask
117
+
118
+ # Prediction function for uploaded audio
119
+ def predict_cough_health(audio_path, model_components=None):
120
+ """Predict cough health status from audio file"""
121
+ if model_components is None:
122
+ model_components = load_model()
123
+
124
+ model = model_components['model']
125
+ scaler = model_components['scaler']
126
+ label_encoder = model_components['label_encoder']
127
+ feature_names = model_components['feature_names']
128
+
129
+ # Extract features
130
+ features = extract_all_features(audio_path)
131
+
132
+ # Convert to DataFrame with correct feature order
133
+ features_df = pd.DataFrame([features])
134
+ features_df = features_df[feature_names]
135
+
136
+ # Scale features
137
+ features_scaled = scaler.transform(features_df)
138
+
139
+ # Predict
140
+ prediction_idx = model.predict(features_scaled)[0]
141
+ prediction = label_encoder.inverse_transform([prediction_idx])[0]
142
+
143
+ # Get probabilities
144
+ probs = model.predict_proba(features_scaled)[0]
145
+ class_probs = {label_encoder.inverse_transform([i])[0]: float(prob) for i, prob in enumerate(probs)}
146
+
147
+ return prediction, class_probs
148
+
149
+ # Function to process uploaded audio file
150
+ def process_audio_file(audio_file):
151
+ """Process uploaded audio file and return prediction"""
152
+ model_components = load_model()
153
+ prediction, probabilities = predict_cough_health(audio_file, model_components)
154
+
155
+ # Format the output
156
+ result = f"Prediction: {prediction}\n\nProbabilities:\n"
157
+ for cls, prob in probabilities.items():
158
+ result += f"{cls}: {prob:.4f}\n"
159
+
160
+ return result
161
+
162
+ # Function to process recorded audio
163
+ def process_recorded_audio(audio_array, sample_rate):
164
+ """Process recorded audio and return prediction"""
165
+ # Save the recorded audio to a temporary file
166
+ with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_audio:
167
+ temp_filename = temp_audio.name
168
+ sf.write(temp_filename, audio_array, sample_rate)
169
+
170
+ model_components = load_model()
171
+ prediction, probabilities = predict_cough_health(temp_filename, model_components)
172
+
173
+ # Clean up the temporary file
174
+ os.unlink(temp_filename)
175
+
176
+ # Format the output
177
+ result = f"Prediction: {prediction}\n\nProbabilities:\n"
178
+ for cls, prob in probabilities.items():
179
+ result += f"{cls}: {prob:.4f}\n"
180
+
181
+ return result
182
+
183
+ # Function to detect coughs in live audio stream
184
+ def detect_coughs_in_stream(audio_array, sample_rate):
185
+ """Detect coughs in live audio stream and analyze them"""
186
+ # Save the audio chunk to a temporary file
187
+ with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as temp_audio:
188
+ temp_filename = temp_audio.name
189
+ sf.write(temp_filename, audio_array, sample_rate)
190
+
191
+ # Load the audio for processing
192
+ audio, sr = librosa.load(temp_filename, sr=None)
193
+
194
+ # Segment coughs
195
+ cough_segments, cough_mask = segment_cough(audio, sr)
196
+
197
+ # Clean up the temporary file
198
+ os.unlink(temp_filename)
199
+
200
+ if len(cough_segments) > 0:
201
+ # Save the first detected cough segment to a temporary file
202
+ with tempfile.NamedTemporaryFile(suffix='.wav', delete=False) as cough_file:
203
+ cough_filename = cough_file.name
204
+ sf.write(cough_filename, cough_segments[0], sr)
205
+
206
+ # Analyze the cough
207
+ model_components = load_model()
208
+ prediction, probabilities = predict_cough_health(cough_filename, model_components)
209
+
210
+ # Clean up the temporary file
211
+ os.unlink(cough_filename)
212
+
213
+ # Format the output
214
+ result = f"Cough detected! Prediction: {prediction}\n\nProbabilities:\n"
215
+ for cls, prob in probabilities.items():
216
+ result += f"{cls}: {prob:.4f}\n"
217
+
218
+ return result
219
+ else:
220
+ return "No cough detected in this audio segment."
221
+
222
+ # Create Gradio interface
223
+ def create_interface():
224
+ model_components = load_model()
225
+
226
+ with gr.Blocks(title="Cough Health Analyzer") as demo:
227
+ gr.Markdown("# Cough Health Analyzer")
228
+ gr.Markdown("Upload an audio file containing a cough or record a cough to analyze its health status.")
229
+
230
+ with gr.Tab("Upload Audio"):
231
+ with gr.Row():
232
+ audio_input = gr.Audio(type="filepath", label="Upload Audio File")
233
+ output_text = gr.Textbox(label="Prediction Result")
234
+
235
+ analyze_btn = gr.Button("Analyze Cough")
236
+ analyze_btn.click(fn=process_audio_file, inputs=audio_input, outputs=output_text)
237
+
238
+ with gr.Tab("Record Audio"):
239
+ with gr.Row():
240
+ audio_recorder = gr.Audio(type="numpy", source="microphone", label="Record Audio")
241
+ record_output = gr.Textbox(label="Prediction Result")
242
+
243
+ record_btn = gr.Button("Analyze Recording")
244
+ record_btn.click(fn=process_recorded_audio, inputs=[audio_recorder], outputs=record_output)
245
+
246
+ with gr.Tab("Live Cough Detection"):
247
+ gr.Markdown("This tab continuously monitors audio for coughs and analyzes them when detected.")
248
+
249
+ with gr.Row():
250
+ live_audio = gr.Audio(type="numpy", source="microphone", streaming=True, label="Live Audio Stream")
251
+ live_output = gr.Textbox(label="Detection Result")
252
+
253
+ live_audio.stream(fn=detect_coughs_in_stream, outputs=live_output)
254
+
255
+ gr.Markdown("## API Usage")
256
+ gr.Markdown("""
257
+ This Gradio app can be accessed via API calls. Example Python code:
258
+ ```python
259
+ import requests
260
+ import json
261
+
262
+ # For file upload
263
+ files = {'audio': open('your_audio_file.wav', 'rb')}
264
+ response = requests.post('YOUR_GRADIO_URL/api/predict', files=files)
265
+ result = json.loads(response.content)
266
+ print(result)
267
+ ```
268
+ """)
269
+
270
+ return demo
271
+
272
+ # Main function
273
+ if __name__ == "__main__":
274
+ demo = create_interface()
275
+ demo.launch(share=True)
cough_classification_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d90d35e153192af89b81065378070a09f8849b18642bdacc63e1b554e3c5e1b4
3
+ size 990656
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ gradio>=4.0.0
2
+ numpy>=1.26.0
3
+ pandas>=2.0.0
4
+ librosa>=0.11.0
5
+ scikit-learn>=1.4.0
6
+ scipy>=1.11.0
7
+ soundfile>=0.13.0
8
+ matplotlib>=3.10.0
9
+ seaborn>=0.13.0