Skip to content

Commit ca6d5d7

Browse files
committed
Added packaging and running MAP of the REST service
Signed-off-by: M Q <mingmelvinq@nvidia.com>
1 parent 64fa618 commit ca6d5d7

File tree

1 file changed

+68
-26
lines changed

1 file changed

+68
-26
lines changed

platforms/aidoc/README.md

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
# Creating REST Service with MONAI Deploy Application
22

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/#).
44

55
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.
66

77
## High Level Design
88

99
The high-level design of this REST service involves a few key components:
1010

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.
1212
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.
1313
3. **Request Handling**:
1414
- When the REST service receives a request to process data, it handles only one request at a time, as per the API specification.
1515
- 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.
1717
- Crucially, it delegates the execution of the MONAI Deploy application to a separate background thread to avoid blocking the web server.
1818
4. **Callback Mechanism**:
1919
- 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:
2222

2323
This design separates the core AI application from the web-serving logic, allowing each to be developed and tested independently.
2424

25-
## Diagrams
26-
2725
### Component Diagram
2826

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.
3028

3129
```mermaid
3230
C4Component
@@ -96,9 +94,9 @@ sequenceDiagram
9694
REST Service-->>-Client: HTTP 200 OK ("status": "IDLE")
9795
```
9896

99-
## How to Run
97+
## How to Run in Development Environment
10098

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.
102100

103101
1. **Install Dependencies**
104102

@@ -107,27 +105,25 @@ Change working directory to the same level as this README.
107105
```bash
108106
pip install -r restful_app/requirements.txt
109107
```
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).
113110

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.
115112

116-
`gdown` may also work.
113+
`gdown` may also work:
117114
```
118115
pip install gdown
119116
gdown https://drive.google.com/uc?id=1IwWMpbo2fd38fKIqeIdL8SKTGvkn31tK
120117
```
121118

122-
Unzip the file to local folders. If deviating from the path noted below, please adjust the env var values
119+
Unzip the file to local folders. If deviating from the path noted below, please adjust the env var values.
123120

124121
```
125122
unzip -o "ai_spleen_seg_bundle_data.zip"
126123
rm -rf models && mkdir -p models/model && mv model.ts models/model && ls models/model
127124
```
128125

129-
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.
131127

132128
```
133129
export HOLOSCAN_MODEL_PATH=models
@@ -143,18 +139,15 @@ Change working directory to the same level as this README.
143139

144140
## Test API Endpoints
145141

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.
148143

149144
Open another console window and change directory to the same as this file.
150145

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).
154147
155148
```
156149
export HOLOSCAN_INPUT_PATH=dcm
157-
export HOLOSCAN_OUTPUT_PATH=output
150+
export HOLOSCAN_OUTPUT_PATH=output_restful_app
158151
```
159152
160153
Run the test script, and examine its console output.
@@ -163,8 +156,7 @@ Run the test script, and examine its console output.
163156
source test_endpoints.sh
164157
```
165158
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):
168160
169161
```
170162
output
@@ -173,7 +165,7 @@ output
173165
└── spleen.stl
174166
```
175167
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.
177169
178170
### Check Status
179171
@@ -210,7 +202,7 @@ The script can run multiple times, or modified to loop with different output fol
210202
211203
### Callback
212204
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:
214206
215207
```json
216208
{
@@ -246,3 +238,53 @@ Or in case of an error:
246238
"error_code": 500
247239
}
248240
```
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`:
249+
250+
```bash
251+
monai-deploy package restful_app -m models/spleen_ct -c restful_app/app.yaml -t monai-rest:1.0 --platform x86_64 -l DEBUG
252+
```
253+
254+
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/ \
268+
-e FLASK_HOST="0.0.0.0" \
269+
-e FLASK_PORT="5000" \
270+
--entrypoint /bin/bash monai-rest-x64-workstation-dgpu-linux-amd64:1.0 -c "python3 -u /opt/holoscan/app/"
271+
```
272+
273+
**Command parameters**
274+
275+
- `--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
288+
INPUT_DIR="/var/holoscan/input/spleen_ct_tcia"
289+
OUTPUT_DIR="/var/holoscan/output/output_spleen_rest"
290+
```

0 commit comments

Comments
 (0)