You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: platforms/aidoc/README.md
+68-26Lines changed: 68 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,19 +1,19 @@
1
1
# Creating REST Service with MONAI Deploy Application
2
2
3
-
This application provides an example of how to make a MONAI Deploy app run as a REST service on [Aidoc](https://www.aidoc.com/) platform. It is compliant with its [third party integration API](https://ai-partner-sdk.aidoc-cloud.com/prod/api/third-parties/doc/#), and the results [callback message schema](https://ai-partner-sdk.aidoc-cloud.com/prod/api/aidoc-callback/doc/#).
3
+
This application provides an example of how to make a MONAI Deploy app run as a REST service on the [Aidoc](https://www.aidoc.com/) platform. It is compliant with its [third party integration API](https://ai-partner-sdk.aidoc-cloud.com/prod/api/third-parties/doc/#), and the results [callback message schema](https://ai-partner-sdk.aidoc-cloud.com/prod/api/aidoc-callback/doc/#).
4
4
5
5
This example uses a subset of the callback message attributes, covering only the required ones as well as some common attributes. For the full message definition, please contact Aidoc directly.
6
6
7
7
## High Level Design
8
8
9
9
The high-level design of this REST service involves a few key components:
10
10
11
-
1.**MONAI Deploy Application**: The core AI logic is encapsulated in a standard MONAI Deploy application (e.g., `AISpleenSegApp`), which is built and tested as a regular containerized workload.
11
+
1.**MONAI Deploy Application**: The core AI logic is encapsulated in a standard MONAI Deploy application (e.g., `AISpleenSegApp`), which is built and tested as a regular containerized workload. The application is responsible for generating the inference results using Pydantic classes that are based on Aidoc's callback message schema. It then reports these results as a JSON string via a callback function provided during its construction.
12
12
2.**REST Service**: A lightweight REST application, built using Flask, acts as the front-end. It exposes endpoints to start and check the status of a processing job.
13
13
3.**Request Handling**:
14
14
- When the REST service receives a request to process data, it handles only one request at a time, as per the API specification.
15
15
- It creates an instance of the MONAI Deploy application.
16
-
- It sets the necessary environment variables for the input and output folders.
16
+
- It sets the necessary environment variables for the input and output folders for the processing execution.
17
17
- Crucially, it delegates the execution of the MONAI Deploy application to a separate background thread to avoid blocking the web server.
18
18
4.**Callback Mechanism**:
19
19
- The callback message, which includes the AI results and a list of output files, is generated within the MONAI Deploy application at the end of its run.
@@ -22,11 +22,9 @@ The high-level design of this REST service involves a few key components:
22
22
23
23
This design separates the core AI application from the web-serving logic, allowing each to be developed and tested independently.
24
24
25
-
## Diagrams
26
-
27
25
### Component Diagram
28
26
29
-
This diagram shows the static components of the system and their relationships using the C4 model.
27
+
This diagram shows the static components of the system and their relationships.
30
28
31
29
```mermaid
32
30
C4Component
@@ -96,9 +94,9 @@ sequenceDiagram
96
94
REST Service-->>-Client: HTTP 200 OK ("status": "IDLE")
97
95
```
98
96
99
-
## How to Run
97
+
## How to Run in Development Environment
100
98
101
-
Change working directory to the same level as this README.
99
+
Change your working directory to the one containing this README file and the `restful_app` folder.
102
100
103
101
1.**Install Dependencies**
104
102
@@ -107,27 +105,25 @@ Change working directory to the same level as this README.
107
105
```bash
108
106
pip install -r restful_app/requirements.txt
109
107
```
110
-
2. **Download Test Data and Set Env Vars**
111
-
The model and test DICOM series are shared on Google Drive requiring first gaining access permission, and
112
-
the zip file is [here](https://drive.google.com/uc?id=1IwWMpbo2fd38fKIqeIdL8SKTGvkn31tK).
108
+
2. **Download Test Data and Set Environment Variables**
109
+
The model and test DICOM series are shared on Google Drive, which requires gaining access permission first. The zip file is available [here](https://drive.google.com/uc?id=1IwWMpbo2fd38fKIqeIdL8SKTGvkn31tK).
113
110
114
-
Please make a request so that it can be shared to specific Gmail account.
111
+
Please make a request so that it can be shared with a specific Gmail account.
Set the environment vars so that the model can be found by the Spleen Seg app. Also,
130
-
the settings are consolidated in the `env_settings.sh`.
126
+
Set the environment variables so that the model can be found by the Spleen Seg app. These settings are also consolidated in the `env_settings.sh` script.
131
127
132
128
```
133
129
export HOLOSCAN_MODEL_PATH=models
@@ -143,18 +139,15 @@ Change working directory to the same level as this README.
143
139
144
140
## Test API Endpoints
145
141
146
-
A simplest test client is provided, which makes call to the endpoint, as well as providing
147
-
a callback endpoint to receives message content at the specified port.
142
+
A simple test client is provided, which makes calls to the endpoint, as well as providing a callback endpoint to receive message content at the specified port.
148
143
149
144
Open another console window and change directory to the same as this file.
150
145
151
-
Set the environment vars so that the test script can get the input DCM and write the callback contents.
152
-
Also, once the REST app completes each processing, the Spleen Seg app's output will also be saved in
153
-
the output folder specified below (the script passes the output folder via the Rest API).
146
+
Set the environment vars so that the test script can get the input DCM and write the callback contents. Also, once the REST app completes each processing, the Spleen Seg app's output will also be saved in the output folder specified below (the script passes the output folder via the REST API).
154
147
155
148
```
156
149
export HOLOSCAN_INPUT_PATH=dcm
157
-
export HOLOSCAN_OUTPUT_PATH=output
150
+
export HOLOSCAN_OUTPUT_PATH=output_restful_app
158
151
```
159
152
160
153
Run the test script, and examine its console output.
@@ -163,8 +156,7 @@ Run the test script, and examine its console output.
163
156
source test_endpoints.sh
164
157
```
165
158
166
-
Once the script completes, examine the `output` folder, which should contain the following (dcm file
167
-
name will be different)
159
+
Once the script completes, examine the `output` folder, which should contain the following (the DICOM file name will be different):
168
160
169
161
```
170
162
output
@@ -173,7 +165,7 @@ output
173
165
└── spleen.stl
174
166
```
175
167
176
-
The script can run multiple times, or modified to loop with different output folder setting.
168
+
The script can be run multiple times or modified to loop with different output folder settings.
177
169
178
170
### Check Status
179
171
@@ -210,7 +202,7 @@ The script can run multiple times, or modified to loop with different output fol
210
202
211
203
### Callback
212
204
213
-
When processing is complete, the application will send a `POST` request to the `callback_url` provided in the process request. The body of the callback will be:
205
+
When processing is complete, the application will send a `POST` request to the `callback_url` provided in the process request. The body of the callback will be similar to this:
214
206
215
207
```json
216
208
{
@@ -246,3 +238,53 @@ Or in case of an error:
246
238
"error_code": 500
247
239
}
248
240
```
241
+
242
+
Please note: The test script uses a simple `nc` command to emulate the callback service. This lightweight approach may sometimes lead to timeout errors on the client side (the REST service), preventing the test script from capturing the callback message. If this occurs, running the script again is a known workaround.
243
+
244
+
## Packaging and Testing the REST Service Container
245
+
246
+
### Packaging the Application
247
+
248
+
To package the REST service application into a MONAI App Package (MAP) container, you can use the MONAI Deploy CLI. The following is an example command, run with the current working directory as the parent of `restful_app`:
This command packages the `restful_app` directory, includes the specified model, uses `app.yaml` for configuration, and tags the resulting Docker image as `monai-rest-x64-workstation-dgpu-linux-amd64:1.0`, which includes the target platform name.
255
+
256
+
Note that the model folder should contain only the model file (e.g., `model.ts`) or subfolders that each contain only a model file.
257
+
258
+
259
+
### Running the MAP Container
260
+
261
+
While you can run MAPs with the `monai-deploy run` command, it currently has limitations regarding the mapping of arbitrary volumes and passing extra environment variables that are necessary for this REST service. Therefore, it's required to use the `docker run`command directly (or a platform specific equivalent) to have full control over the container's execution environment.
262
+
263
+
```bash
264
+
docker run --gpus=all --network host --name my_monai_rest_service -t --rm \
265
+
-v <host folder for staging input folder>:/var/holoscan/input/ \
266
+
-v <host folder for saving output folder>:/var/holoscan/output/ \
267
+
-v <host folder for saving temp files>:/var/holoscan/ \
- `--gpus=all`: Exposes all available host GPUs to the container, which is necessary for CUDA-based inference. A specific CUDA device ID can also be used.
276
+
- `--network host`: The container shares the host's network stack, making the Flask server directly accessible on the host's IP address and port (e.g., `http://localhost:5000`).
277
+
- `--name my_monai_rest_service`: Assigns a convenient name to the running container.
278
+
- `-t --rm`: Allocates a pseudo-terminal and automatically removes the container when it stops.
279
+
- `-v <host folder for staging input folder>:/var/holoscan/input/`: Mounts a host directory into the container as `/var/holoscan/input/`. This allows the REST service to access input files using an internal container path. For example, the inference input (e.g., a DICOM study's instance files) should be staged in a subfolder on the host, e.g. `my_test_study`, and the client request message must use the corresponding internal container path (e.g., `/var/holoscan/input/my_test_study`).
280
+
- `-v <host folder for saving output folder>:/var/holoscan/output/`: Mounts a host directory into the container as `/var/holoscan/output/`, allowing the REST service to save the inference result files.
281
+
- `-e FLASK_HOST="0.0.0.0"` and `-e FLASK_PORT="5000"`: These environment variables configure the Flask-based REST application to be accessible from outside the container on the specified port.
282
+
- `--entrypoint /bin/bash ... -c "python3 -u /opt/holoscan/app/"`: This overrides the default entrypoint of the MAP container. Instead of running the MONAI Deploy application directly, it starts a bash shell that executes the command to run the Flask application, effectively starting the REST service.
283
+
284
+
The simple test client, `test_endpoints.sh`, can be used to test the REST service container. It requires a couple of simple changes to use the container's internal folder paths for I/O. For example:
285
+
286
+
```bash
287
+
# Get the absolute path to the input and output directories
0 commit comments