Skip to content

Commit 60134d1

Browse files
Merge Nuance Updates (#377)
Signed-off-by: Iain Henderson <[email protected]> Co-authored-by: iain_nuance <[email protected]> Co-authored-by: Iain Henderson <[email protected]>
1 parent b23b5f7 commit 60134d1

File tree

6 files changed

+234
-77
lines changed

6 files changed

+234
-77
lines changed

.gitignore

+122-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ coverage.xml
5050
*.py,cover
5151
.hypothesis/
5252
.pytest_cache/
53+
cover/
5354

5455
# Translations
5556
*.mo
@@ -72,6 +73,7 @@ instance/
7273
docs/_build/
7374

7475
# PyBuilder
76+
.pybuilder/
7577
target/
7678

7779
# Jupyter Notebook
@@ -82,6 +84,8 @@ profile_default/
8284
ipython_config.py
8385

8486
# pyenv
87+
# For a library or package, you might want to ignore these files since the code is
88+
# intended to run in multiple environments; otherwise, check them in:
8589
.python-version
8690

8791
# pipenv
@@ -91,7 +95,22 @@ ipython_config.py
9195
# install all needed dependencies.
9296
#Pipfile.lock
9397

94-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
98+
# poetry
99+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
100+
# This is especially recommended for binary packages to ensure reproducibility, and is more
101+
# commonly ignored for libraries.
102+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
103+
#poetry.lock
104+
105+
# pdm
106+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
107+
#pdm.lock
108+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
109+
# in version control.
110+
# https://pdm.fming.dev/#use-with-ide
111+
.pdm.toml
112+
113+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
95114
__pypackages__/
96115

97116
# Celery stuff
@@ -140,3 +159,105 @@ _autosummary
140159

141160
# model files
142161
*.ts
162+
163+
# pytype static type analyzer
164+
.pytype/
165+
166+
# Cython debug symbols
167+
cython_debug/
168+
169+
# PyCharm
170+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
171+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
172+
# and can be added to the global gitignore or merged into this file. For a more nuclear
173+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
174+
#.idea/
175+
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
176+
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
177+
178+
# User-specific stuff
179+
.idea/**/workspace.xml
180+
.idea/**/tasks.xml
181+
.idea/**/usage.statistics.xml
182+
.idea/**/dictionaries
183+
.idea/**/shelf
184+
185+
# AWS User-specific
186+
.idea/**/aws.xml
187+
188+
# Generated files
189+
.idea/**/contentModel.xml
190+
191+
# Sensitive or high-churn files
192+
.idea/**/dataSources/
193+
.idea/**/dataSources.ids
194+
.idea/**/dataSources.local.xml
195+
.idea/**/sqlDataSources.xml
196+
.idea/**/dynamic.xml
197+
.idea/**/uiDesigner.xml
198+
.idea/**/dbnavigator.xml
199+
200+
# Gradle
201+
.idea/**/gradle.xml
202+
.idea/**/libraries
203+
204+
# Gradle and Maven with auto-import
205+
# When using Gradle or Maven with auto-import, you should exclude module files,
206+
# since they will be recreated, and may cause churn. Uncomment if using
207+
# auto-import.
208+
# .idea/artifacts
209+
# .idea/compiler.xml
210+
# .idea/jarRepositories.xml
211+
# .idea/modules.xml
212+
# .idea/*.iml
213+
# .idea/modules
214+
# *.iml
215+
# *.ipr
216+
217+
# CMake
218+
cmake-build-*/
219+
220+
# Mongo Explorer plugin
221+
.idea/**/mongoSettings.xml
222+
223+
# File-based project format
224+
*.iws
225+
226+
# IntelliJ
227+
out/
228+
229+
# mpeltonen/sbt-idea plugin
230+
.idea_modules/
231+
232+
# JIRA plugin
233+
atlassian-ide-plugin.xml
234+
235+
# Cursive Clojure plugin
236+
.idea/replstate.xml
237+
238+
# SonarLint plugin
239+
.idea/sonarlint/
240+
241+
# Crashlytics plugin (for Android Studio and IntelliJ)
242+
com_crashlytics_export_strings.xml
243+
crashlytics.properties
244+
crashlytics-build.properties
245+
fabric.properties
246+
247+
# Editor-based Rest Client
248+
.idea/httpRequests
249+
250+
# Android studio 3.1+ serialized cache file
251+
.idea/caches/build_file_checksums.ser
252+
.vscode/*
253+
!.vscode/settings.json
254+
!.vscode/tasks.json
255+
!.vscode/launch.json
256+
!.vscode/extensions.json
257+
!.vscode/*.code-snippets
258+
259+
# Local History for Visual Studio Code
260+
.history/
261+
262+
# Built Visual Studio Code Extensions
263+
*.vsix

integrations/nuance_pin/Dockerfile

+47-25
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,73 @@
1+
FROM nvcr.io/nvidia/pytorch:21.07-py3 AS foundation
2+
3+
ARG EXTRA_PYTHON_PACKAGES
4+
5+
RUN apt-get -y update && \
6+
apt-get -y install python3-distutils python3-pip python3-venv && \
7+
python3 -m pip install --no-cache-dir --upgrade pip && \
8+
python3 -m pip install --no-cache-dir --ignore-installed setuptools
9+
10+
# Create a Virtual Environment to limit the size of the application container
11+
RUN python3 -m venv /opt/venv
12+
ENV PATH="/opt/venv/bin:$PATH"
13+
RUN python3 -m pip install --upgrade pip
14+
15+
# Copy the ai_service wheel, this is separate from requirements.txt to help with layer caching for repeated builds
16+
COPY lib/ai_service-*-py3-none-any.whl /tmp/
17+
RUN python3 -m pip install --no-cache-dir /tmp/ai_service-*-py3-none-any.whl
18+
19+
COPY requirements.txt /tmp/
20+
# Add any other python packages your AI Service requires
21+
RUN python3 -m pip install --no-cache-dir ${EXTRA_PYTHON_PACKAGES} -r /tmp/requirements.txt
22+
123
FROM nvcr.io/nvidia/pytorch:21.07-py3 AS application
224

325
ARG PARTNER_NAME
426
ARG SERVICE_NAME
527
ARG VERSION
628
ARG MONAI_APP_MODULE
729
ARG MODEL_PATH
8-
ARG EXTRA_PYTHON_PACKAGES
930

1031
ENV TZ=Etc/UTC
1132
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
1233

1334
# python3-gdcm or python-gdcm is required for decompression
1435
RUN apt-get -y update && \
15-
apt-get -y install --no-install-recommends python3-distutils python3-gdcm && \
16-
# apt-get -y install python3.7 && \
36+
apt-get -y install --no-install-recommends python3-gdcm && \
1737
apt-get autoclean && \
1838
apt-get clean && \
1939
rm -rf /var/lib/apt/lists/*
2040

21-
ENV DEBUG=YES
22-
ENV KEEP_FILES=YES
23-
24-
# make sure all messages reach the console
25-
ENV PYTHONUNBUFFERED=1
26-
27-
# copy MONAI app files
28-
COPY . /app/.
29-
WORKDIR /app
30-
3141
# copy model file to model folder
3242
RUN wget -q https://github.com/Project-MONAI/model-zoo/releases/download/hosting_storage_v1/lung_nodule_ct_detection_v0.2.0.zip && \
3343
unzip lung_nodule_ct_detection_v0.2.0.zip -d /tmp/ && \
34-
cp /tmp/lung_nodule_ct_detection/models/model.ts model/. && \
44+
mkdir -p /app/model && \
45+
cp /tmp/lung_nodule_ct_detection/models/model.ts /app/model/ && \
3546
rm -rf /tmp/lung_nodule_ct_detection && \
3647
rm lung_nodule_ct_detection_v0.2.0.zip
3748

3849
# non-root aiserviceuser in group aiserviceuser with UserID and GroupID as 20225
39-
RUN groupadd -g 20225 -r aiserviceuser && useradd -u 20225 -r -g aiserviceuser aiserviceuser && chown -R aiserviceuser:aiserviceuser /app && \
40-
chown -R aiserviceuser:aiserviceuser /var
50+
RUN groupadd -g 20225 -r aiserviceuser && \
51+
useradd -u 20225 -r -g aiserviceuser aiserviceuser && \
52+
chown -R aiserviceuser:aiserviceuser /app /var
4153
USER aiserviceuser:aiserviceuser
4254

43-
ENV VIRTUAL_ENV=.venv
44-
RUN python3 -m venv $VIRTUAL_ENV
45-
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
55+
# Enable Matplotlib cache folder
56+
RUN mkdir -p /app/.config/matplotlib
57+
ENV MPLCONFIGDIR=/app/.config/matplotlib
58+
59+
# Copy the virtual environment from the foundation image
60+
ENV VIRTUAL_ENV=/app/venv
61+
COPY --from=foundation --chown=aiserviceuser:aiserviceuser /opt/venv "${VIRTUAL_ENV}"
62+
ENV PATH="${VIRTUAL_ENV}/bin:${PATH}"
63+
64+
# make sure all messages reach the console
65+
ENV PYTHONUNBUFFERED=1
4666

47-
RUN python -m pip install --upgrade pip && \
48-
python -m pip install --upgrade --no-cache-dir ${EXTRA_PYTHON_PACKAGES} -r requirements.txt && \
49-
python -m pip install --upgrade --no-cache-dir lib/ai_service-*-py3-none-any.whl && \
50-
pip install --upgrade numpy && \
51-
rm -rf lib && \
52-
rm requirements.txt
67+
# copy MONAI app files
68+
COPY --chown=aiserviceuser:aiserviceuser app_wrapper.py /app/
69+
COPY --chown=aiserviceuser:aiserviceuser app/* /app/app/
70+
WORKDIR /app
5371

5472
ENV AI_PARTNER_NAME ${PARTNER_NAME}
5573
ENV AI_SVC_NAME ${SERVICE_NAME}
@@ -58,4 +76,8 @@ ENV AI_MODEL_PATH ${MODEL_PATH}
5876
ENV MONAI_APP_CLASSPATH ${MONAI_APP_MODULE}
5977

6078
ENV PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
79+
80+
ENV DEBUG=NO
81+
ENV KEEP_FILES=NO
82+
6183
CMD ["python", "app_wrapper.py"]

integrations/nuance_pin/app/lung_nodule.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@
1010
# limitations under the License.
1111

1212
import logging
13-
from typing import Callable
13+
from typing import Optional
1414

15+
from ai_service import AiJobProcessor
1516
from app.inference import LungNoduleInferenceOperator
1617
from app.post_inference_ops import CreatePINDiagnosticsReportOp, GenerateGSPSOp
1718

@@ -24,11 +25,10 @@
2425
@resource(cpu=1, gpu=1, memory="7Gi")
2526
# The monai pkg is not required by this class, instead by the included operators.
2627
class LungNoduleDetectionApp(Application):
27-
def __init__(self, upload_document: Callable, upload_gsps: Callable, *args, **kwargs):
28+
def __init__(self, pin_processor: Optional[AiJobProcessor] = None, *args, **kwargs):
2829
"""Creates an application instance."""
2930
self._logger = logging.getLogger("{}.{}".format(__name__, type(self).__name__))
30-
self.upload_document = upload_document
31-
self.upload_gsps = upload_gsps
31+
self.pin_processor = pin_processor
3232
super().__init__(*args, **kwargs)
3333

3434
def run(self, *args, **kwargs):
@@ -60,8 +60,8 @@ def compose(self):
6060
series_selector_op = DICOMSeriesSelectorOperator(dicom_selection_rules)
6161
series_to_vol_op = DICOMSeriesToVolumeOperator()
6262
detection_op = LungNoduleInferenceOperator()
63-
gsps_op = GenerateGSPSOp(upload_gsps_fn=self.upload_gsps)
64-
pin_report_op = CreatePINDiagnosticsReportOp(upload_doc_fn=self.upload_document)
63+
gsps_op = GenerateGSPSOp(pin_processor=self.pin_processor)
64+
pin_report_op = CreatePINDiagnosticsReportOp(pin_processor=self.pin_processor)
6565

6666
self.add_flow(study_loader_op, series_selector_op, {"dicom_study_list": "dicom_study_list"})
6767
self.add_flow(
@@ -87,4 +87,4 @@ def compose(self):
8787
# monai-deploy exec app.py -i input -m model/model.ts
8888
#
8989
logging.basicConfig(level=logging.DEBUG)
90-
app_instance = LungNoduleDetectionApp(lambda x: x, lambda x: x, do_run=True)
90+
app_instance = LungNoduleDetectionApp(do_run=True)

0 commit comments

Comments
 (0)