UdasriHasindu commited on
Commit
c1bc804
·
1 Parent(s): ac4efc7

doc: add complete documentation

Browse files
Files changed (1) hide show
  1. README.md +258 -29
README.md CHANGED
@@ -8,31 +8,101 @@ app_port: 7860
8
  pinned: false
9
  ---
10
 
11
- # Parkinson's Disease UPDRS Prediction API
12
 
13
- A FastAPI-based REST API that predicts a patient's **motor UPDRS score** (Unified Parkinson's Disease Rating Scale) from a voice recording.
14
 
15
- ## Endpoints
16
 
17
- | Method | Path | Description |
18
- |--------|------|-------------|
19
- | `GET` | `/` | Root welcome message |
20
- | `GET` | `/health` | Health check confirms models are loaded |
21
- | `POST` | `/analyze/voice` | Main prediction endpoint |
22
- | `POST` | `/analyze/test` | Debug echo endpoint |
23
 
24
- ## Usage — `/analyze/voice`
 
 
 
 
 
 
 
 
 
25
 
26
- Submit a `multipart/form-data` POST request with:
 
 
 
 
27
 
28
- | Field | Type | Description |
29
- |-------|------|-------------|
30
- | `age` | int | Age (11–119) |
31
- | `sex` | string | `male` or `female` |
32
- | `test_time` | float | Time since recruitment (days) |
33
- | `audio_file` | file | Voice recording (WAV, MP3, OGG, WebM) |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- ### Response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
  ```json
38
  {
@@ -40,18 +110,177 @@ Submit a `multipart/form-data` POST request with:
40
  }
41
  ```
42
 
43
- `prediction` is the estimated motor UPDRS score (float).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
- ## Voice Features Extracted
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
- The API uses **Praat** (via `parselmouth`) to extract 16 acoustic biomarkers:
48
- - **Jitter**: `Jitter(%)`, `Jitter(Abs)`, `Jitter:RAP`, `Jitter:PPQ5`, `Jitter:DDP`
49
- - **Shimmer**: `Shimmer`, `Shimmer(dB)`, `Shimmer:APQ3`, `Shimmer:APQ5`, `Shimmer:APQ11`, `Shimmer:DDA`
50
- - **Noise**: `NHR`, `HNR`
51
- - **Nonlinear**: `RPDE`, `DFA`, `PPE`
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
- ## Model
54
 
55
- - Hosted on HuggingFace: [`xplorers/parkinsons-updrs-model`](https://huggingface.co/xplorers/parkinsons-updrs-model)
56
- - Ensemble model (RandomForest + XGBoost + LightGBM via VotingRegressor)
57
- - Downloaded and cached in memory at startup
 
8
  pinned: false
9
  ---
10
 
11
+ # Parkinson's Disease Motor UPDRS Prediction API
12
 
13
+ A production-style FastAPI service that predicts **motor UPDRS score** from a voice sample and patient metadata.
14
 
15
+ The service:
16
 
17
+ - accepts audio uploads (`wav`, `mp3`, `ogg`, `webm`),
18
+ - converts them to WAV when needed,
19
+ - extracts clinical voice biomarkers using Praat,
20
+ - loads a trained ensemble model from Hugging Face,
21
+ - returns a numeric UPDRS motor prediction.
 
22
 
23
+ ---
24
+
25
+ ## 1) What this API does
26
+
27
+ Given:
28
+
29
+ - `age`
30
+ - `sex` (`male` or `female`)
31
+ - `test_time`
32
+ - `audio_file`
33
 
34
+ The API returns:
35
+
36
+ - `prediction` (float): estimated motor UPDRS score.
37
+
38
+ ---
39
 
40
+ ## 2) Project structure
41
+
42
+ ```text
43
+ UPDRS_API/
44
+ ├── main.py
45
+ ├── requirements.txt
46
+ ├── Dockerfile
47
+ ├── README.md
48
+ ├── routers/
49
+ │ └── analyze_router.py
50
+ ├── services/
51
+ │ └── voice_analyze_service.py
52
+ ├── ml/
53
+ │ └── model_predictor.py
54
+ ├── utils/
55
+ │ ├── file_handler.py
56
+ │ └── voice_data_extraction.py
57
+ └── schema/
58
+ └── patient_inputs.py
59
+ ```
60
+
61
+ ### Responsibilities
62
+
63
+ - **main.py**: app startup, CORS, lifespan hook, route registration.
64
+ - **routers/analyze_router.py**: request validation and endpoint definitions.
65
+ - **services/voice_analyze_service.py**: end-to-end orchestration.
66
+ - **utils/file_handler.py**: upload persistence + ffmpeg conversion.
67
+ - **utils/voice_data_extraction.py**: Praat/parselmouth feature extraction.
68
+ - **ml/model_predictor.py**: model download/cache and inference.
69
+
70
+ ---
71
 
72
+ ## 3) API endpoints
73
+
74
+ | Method | Path | Purpose |
75
+ | ------ | ---------------- | -------------------------------------------- |
76
+ | GET | `/` | Basic welcome/status message |
77
+ | GET | `/health` | Health + model cache state |
78
+ | POST | `/analyze/test` | Echo/debug endpoint for multipart form input |
79
+ | POST | `/analyze/voice` | Main prediction endpoint |
80
+
81
+ ### `GET /health` response
82
+
83
+ ```json
84
+ {
85
+ "status": "ok",
86
+ "models_loaded": true
87
+ }
88
+ ```
89
+
90
+ ---
91
+
92
+ ## 4) Main prediction endpoint
93
+
94
+ ### `POST /analyze/voice`
95
+
96
+ Content type: `multipart/form-data`
97
+
98
+ | Field | Type | Validation |
99
+ | ------------ | ------ | ------------------ |
100
+ | `age` | int | `10 < age < 120` |
101
+ | `sex` | string | `male` or `female` |
102
+ | `test_time` | float | `> 0` |
103
+ | `audio_file` | file | required |
104
+
105
+ ### Example response
106
 
107
  ```json
108
  {
 
110
  }
111
  ```
112
 
113
+ ---
114
+
115
+ ## 5) How prediction works (pipeline)
116
+
117
+ 1. Request arrives at `POST /analyze/voice`.
118
+ 2. Audio file is written to a temp file.
119
+ 3. Non-WAV formats are converted to WAV via `ffmpeg`.
120
+ 4. Praat/parselmouth extracts acoustic and nonlinear features.
121
+ 5. `sex` is encoded (`male=1`, `female=0`).
122
+ 6. Features are combined with `age` and `test_time`.
123
+ 7. Features are ordered/scaled according to `feature_names.pkl` and `scaler.pkl`.
124
+ 8. Ensemble model predicts UPDRS.
125
+ 9. Temp file is always cleaned up.
126
+
127
+ ---
128
+
129
+ ## 6) Extracted voice features
130
+
131
+ The service extracts these features:
132
+
133
+ - **Jitter**
134
+ - `Jitter(%)`
135
+ - `Jitter(Abs)`
136
+ - `Jitter:RAP`
137
+ - `Jitter:PPQ5`
138
+ - `Jitter:DDP`
139
+
140
+ - **Shimmer**
141
+ - `Shimmer`
142
+ - `Shimmer(dB)`
143
+ - `Shimmer:APQ3`
144
+ - `Shimmer:APQ5`
145
+ - `Shimmer:APQ11`
146
+ - `Shimmer:DDA`
147
+
148
+ - **Noise/Harmonics**
149
+ - `NHR`
150
+ - `HNR`
151
+
152
+ - **Nonlinear dynamics**
153
+ - `RPDE`
154
+ - `DFA`
155
+ - `PPE`
156
+
157
+ ---
158
+
159
+ ## 7) Model details
160
+
161
+ - Model repo: https://huggingface.co/xplorers/parkinsons-updrs-model
162
+ - Artifacts downloaded on startup:
163
+ - `ensemble_model.pkl`
164
+ - `feature_names.pkl`
165
+ - `scaler.pkl`
166
+ - Models are cached in-memory (`_cache`) after first load.
167
+
168
+ ---
169
+
170
+ ## 8) Environment variables
171
+
172
+ Create a `.env` file in the project root (optional but recommended):
173
+
174
+ ```env
175
+ HF_TOKEN=your_huggingface_access_token
176
+ ```
177
+
178
+ `main.py` calls `load_dotenv()`, so `.env` is loaded automatically.
179
 
180
+ ---
181
+
182
+ ## 9) Local development setup
183
+
184
+ ### Prerequisites
185
+
186
+ - Python 3.11+ (recommended for this codebase)
187
+ - `ffmpeg` installed and available in PATH
188
+
189
+ ### Install
190
+
191
+ ```bash
192
+ python -m venv venv
193
+ source venv/bin/activate
194
+ pip install -r requirements.txt
195
+ ```
196
 
197
+ ### Run
198
+
199
+ ```bash
200
+ uvicorn main:app --reload --host 0.0.0.0 --port 8000
201
+ ```
202
+
203
+ Open:
204
+
205
+ - Swagger UI: http://127.0.0.1:8000/docs
206
+ - ReDoc: http://127.0.0.1:8000/redoc
207
+
208
+ ---
209
+
210
+ ## 10) Docker usage
211
+
212
+ Build image:
213
+
214
+ ```bash
215
+ docker build -t updrs-api .
216
+ ```
217
+
218
+ Run container:
219
+
220
+ ```bash
221
+ docker run --rm -p 7860:7860 --env HF_TOKEN=$HF_TOKEN updrs-api
222
+ ```
223
+
224
+ Container entrypoint uses:
225
+
226
+ ```bash
227
+ uvicorn main:app --host 0.0.0.0 --port 7860
228
+ ```
229
+
230
+ ---
231
+
232
+ ## 11) cURL examples
233
+
234
+ ### Health check
235
+
236
+ ```bash
237
+ curl http://127.0.0.1:8000/health
238
+ ```
239
+
240
+ ### Voice prediction
241
+
242
+ ```bash
243
+ curl -X POST "http://127.0.0.1:8000/analyze/voice" \
244
+ -F "age=63" \
245
+ -F "sex=male" \
246
+ -F "test_time=12.5" \
247
+ -F "audio_file=@./sample.wav"
248
+ ```
249
+
250
+ ---
251
+
252
+ ## 12) Error handling and troubleshooting
253
+
254
+ ### 401 Unauthorized from Hugging Face
255
+
256
+ Cause: gated/private model repository.
257
+
258
+ Fix:
259
+
260
+ 1. Ensure your account has access to the model page.
261
+ 2. Set `HF_TOKEN` in environment or `.env`.
262
+ 3. Restart the API.
263
+
264
+ ### `ffmpeg` conversion failure
265
+
266
+ Cause: `ffmpeg` missing or unsupported input file.
267
+
268
+ Fix:
269
+
270
+ - Install `ffmpeg` (system package).
271
+ - Test source file manually with `ffmpeg -i <file>`.
272
+
273
+ ### Models not loaded
274
+
275
+ `predict_parkinson()` raises runtime error if startup download failed.
276
+
277
+ Fix:
278
+
279
+ - Check server startup logs.
280
+ - Verify internet access and token permissions.
281
+
282
+ ---
283
 
284
+ ## 13) License
285
 
286
+ This project includes a `LICENSE` file at the repository root. Review it before distribution or production use.