| # MRI Inference API |
|
|
| Base URL (local): `http://localhost:7860` |
| Base URL (HF Space): `https://<your-space>.hf.space` |
|
|
| --- |
|
|
| ## Endpoints |
|
|
| ### `GET /models` |
|
|
| Returns the list of available model checkpoint names. |
|
|
| **Response** |
| ```json |
| { |
| "models": ["small3dresnet_centiloid_v1"] |
| } |
| ``` |
|
|
| --- |
|
|
| ### `POST /inference` |
|
|
| Runs centiloid regression on an uploaded MRI scan and stores the result. |
| Re-submitting the same `filename` + `model_name` pair **overwrites** the existing row. |
|
|
| **Request** — `multipart/form-data` |
|
|
| | Field | Type | Required | Description | |
| |---|---|---|---| |
| | `file` | file | yes | `.nii`, `.nii.gz`, or `.tar` / `.tar.gz` containing a `.nii` | |
| | `model_name` | string | yes | Must match a name returned by `GET /models` | |
| | `label` | string | no | Ground-truth centiloid label (for tracking) | |
| | `fold` | integer | no | Optional fold id, `0`-`10`, for train/val/test analysis splits | |
|
|
| **curl** |
| ```bash |
| curl -X POST http://localhost:7860/inference \ |
| -F "file=@subject_001.nii.gz" \ |
| -F "model_name=small3dresnet_centiloid_v1" \ |
| -F "label=38.5" |
| ``` |
|
|
| **Python (requests)** |
| ```python |
| import requests |
| |
| with open("subject_001.nii.gz", "rb") as f: |
| r = requests.post( |
| "http://localhost:7860/inference", |
| files={"file": f}, |
| data={"model_name": "small3dresnet_centiloid_v1", "label": "38.5"}, |
| ) |
| print(r.json()) |
| ``` |
|
|
| **Response `200`** |
| ```json |
| { |
| "id": 1, |
| "filename": "subject_001.nii.gz", |
| "model_name": "small3dresnet_centiloid_v1", |
| "centiloid": 42.317, |
| "raw_output": 0.648231, |
| "label": "38.5", |
| "fold": null |
| } |
| ``` |
|
|
| | Field | Description | |
| |---|---| |
| | `centiloid` | Predicted centiloid value (inverse-transformed: `sinh(raw_output) × 50`) | |
| | `raw_output` | Raw model output in asinh-transformed space | |
| | `label` | Ground-truth label as provided, or `null` | |
| | `fold` | Optional fold id, or `null` | |
|
|
| **Errors** |
|
|
| | Status | Reason | |
| |---|---| |
| | `400` | Empty file | |
| | `404` | `model_name` not found in `checkpoints/` | |
| | `422` | Preprocessing or inference failed (bad NIfTI, no valid voxels, etc.) | |
|
|
| --- |
|
|
| ### `GET /results` |
|
|
| Returns paginated past inference results, most recent first. |
|
|
| Query params: |
|
|
| | Param | Type | Default | Description | |
| |---|---:|---:|---| |
| | `limit` | integer | `250` | Page size, max `1000` | |
| | `offset` | integer | `0` | Row offset | |
| | `fold` | integer | none | Optional fold filter, `0`-`10` | |
|
|
| **curl** |
| ```bash |
| curl "http://localhost:7860/results?limit=250&offset=0" |
| ``` |
|
|
| **Response `200`** |
| ```json |
| { |
| "count": 2, |
| "limit": 250, |
| "offset": 0, |
| "has_more": false, |
| "results": [ |
| { |
| "id": 2, |
| "filename": "subject_002.nii.gz", |
| "model_name": "small3dresnet_centiloid_v1", |
| "centiloid": 87.14, |
| "raw_output": 1.053812, |
| "label": null, |
| "fold": null, |
| "created_at": "2026-05-24T10:31:00.123456" |
| }, |
| { |
| "id": 1, |
| "filename": "subject_001.nii.gz", |
| "model_name": "small3dresnet_centiloid_v1", |
| "centiloid": 42.317, |
| "raw_output": 0.648231, |
| "label": "38.5", |
| "fold": 2, |
| "created_at": "2026-05-24T10:28:44.987654" |
| } |
| ] |
| } |
| ``` |
|
|
| --- |
|
|
| ### `GET /results/done` |
|
|
| Returns only completed `(filename, model_name)` pairs for resume scripts. |
|
|
| ```bash |
| curl http://localhost:7860/results/done |
| ``` |
|
|
| --- |
|
|
| ### `GET /results/folds` |
|
|
| Returns the fold ids currently present in the DB. |
|
|
| ```json |
| { "folds": [0, 1, 2] } |
| ``` |
|
|
| --- |
|
|
| ### `PATCH /results/fold` |
|
|
| Updates fold values in bulk. Use either `id` or `filename + model_name`. Set `fold` to `null` to clear it. |
|
|
| ```bash |
| curl -X PATCH http://localhost:7860/results/fold \ |
| -H "Content-Type: application/json" \ |
| -d '{"updates":[{"filename":"subject_001.nii.gz","model_name":"small3dresnet_centiloid_v1","fold":2}]}' |
| ``` |
|
|
| ```json |
| { "updated": 1, "missing": [] } |
| ``` |
|
|
| --- |
|
|
| ## Adding a New Model |
|
|
| 1. Place the `.ckpt` file in the `checkpoints/` directory. |
| 2. The file stem becomes the `model_name` — e.g. `checkpoints/small3dresnet_v2.ckpt` → `"small3dresnet_v2"`. |
| 3. No restart required; `GET /models` picks it up dynamically. |
|
|
| > **Note:** Checkpoints must be PyTorch Lightning `.ckpt` files saved from `CentiloidRegressorModule`. The API extracts `hyper_parameters.model_config` and `hyper_parameters.train_config` automatically. |
|
|