├── .bumpversion.cfg ├── .coveragerc ├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── documentation-request.md │ ├── enhancement_request.md │ ├── feature_request.md │ └── submit-question.md ├── codecov.yml └── workflows │ └── pr.yml ├── .gitignore ├── .readthedocs.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── THIRD_PARTY_NOTICES ├── Pillow_HPND_LICENSE.txt ├── PyPDF2_BSD-3_LICENSE.txt ├── SimpleITK_Apache2.0_LICENSE.txt ├── clara-viz_Apache2.0_LICENSE.txt ├── colorama_BSD-3_LICENSE.txt ├── coverage_Apache2.0_LICENSE.txt ├── cucim_Apache2.0_LICENSE.txt ├── docker_Apache2.0_LICENSE.txt ├── highdicom_MIT_LICENSE.txt ├── holoscan_Apache2.0_LICENSE.txt ├── monai_Apache2.0_LICENSE.txt ├── networkx_BSD-3_LICENSE.txt ├── nibabel_MIT_LICENSE.txt ├── numpy_BSD-3_LICENSE.txt ├── parameterized_BSD-2_LICENSE.txt ├── pydicom_MIT_LICENSE.txt ├── pytest123_MIT_LICENSE.txt ├── pytype_Apache2.0_LICENSE.txt ├── scikit-image_BSD-3_LICENSE.txt ├── torch_BSD-3_LICENSE.txt └── typeguard_MIT_LICENSE.txt ├── docs ├── Makefile ├── _static │ └── custom.css ├── images │ ├── MONAI-logo-color.png │ └── favicon.ico ├── requirements.txt ├── source │ ├── _templates │ │ ├── autosummary │ │ │ ├── class.rst │ │ │ └── module.rst │ │ ├── navbar-logo.html │ │ └── sidebar-quicklinks.html │ ├── conf.py │ ├── developing_with_sdk │ │ ├── core_concepts.md │ │ ├── creating_application_class.md │ │ ├── creating_operator_classes.md │ │ ├── deploying_and_hosting_map.md │ │ ├── designing_workflow.md │ │ ├── executing_app_locally.ipynb │ │ ├── executing_packaged_app_locally.md │ │ ├── index.md │ │ └── packaging_app.md │ ├── getting_started │ │ ├── examples.md │ │ ├── index.md │ │ ├── installing_app_sdk.md │ │ └── tutorials │ │ │ ├── index.md │ │ │ ├── mednist_app.md │ │ │ ├── monai_bundle_app.md │ │ │ ├── multi_model_app.md │ │ │ ├── segmentation_app.md │ │ │ ├── segmentation_clara-viz_app.md │ │ │ └── simple_app.md │ ├── index.md │ ├── introduction │ │ ├── architecture.md │ │ ├── contributing.md │ │ ├── index.md │ │ ├── overview.md │ │ └── roadmap.md │ ├── modules │ │ ├── core.md │ │ ├── datastores.md │ │ ├── domain_objects.md │ │ ├── executors.md │ │ ├── graphs.md │ │ ├── index.md │ │ ├── models.md │ │ └── operators.md │ ├── release_notes │ │ ├── index.md │ │ ├── v0.1.0.md │ │ ├── v0.2.0.md │ │ ├── v0.2.1.md │ │ ├── v0.3.0.md │ │ ├── v0.4.0.md │ │ ├── v0.5.0.md │ │ ├── v0.5.1.md │ │ ├── v0.6.0.md │ │ ├── v1.0.0.md │ │ ├── v2.0.0.md │ │ └── v3.0.0.md │ └── spelling_wordlist.txt └── srs.md ├── examples └── apps │ ├── ai_livertumor_seg_app │ ├── __init__.py │ ├── __main__.py │ ├── app.py │ └── livertumor_seg_operator.py │ ├── ai_multi_ai_app │ ├── __init__.py │ ├── __main__.py │ ├── app.py │ ├── app.yaml │ ├── readme.md │ └── requirements.txt │ ├── ai_pancreas_seg_app │ ├── __init__.py │ ├── __main__.py │ └── app.py │ ├── ai_remote_infer_app │ ├── __main__.py │ ├── app.py │ ├── env_settings_example.sh │ ├── models_client_side │ │ └── spleen_ct │ │ │ └── config.pbtxt │ └── spleen_seg_operator.py │ ├── ai_spleen_seg_app │ ├── __init__.py │ ├── __main__.py │ ├── app.py │ ├── app.yaml │ └── requirements.txt │ ├── ai_unetr_seg_app │ ├── __init__.py │ ├── __main__.py │ ├── app.py │ └── unetr_seg_operator.py │ ├── breast_density_classifier_app │ ├── README.md │ ├── __init__.py │ ├── __main__.py │ ├── app.py │ ├── app.yaml │ ├── breast_density_classifier_operator.py │ └── requirements.txt │ ├── cchmc_ped_abd_ct_seg_app │ ├── README.md │ ├── __init__.py │ ├── __main__.py │ ├── abdomen_seg_operator.py │ ├── app.py │ ├── app.yaml │ ├── dicom_sc_writer_operator.py │ ├── mongodb_entry_creator_operator.py │ ├── mongodb_writer_operator.py │ ├── post_transforms.py │ ├── requirements.txt │ └── scripts │ │ ├── map_build.sh │ │ ├── map_extract.sh │ │ ├── map_run.sh │ │ ├── map_run_interactive.sh │ │ └── model_run.sh │ ├── deploy_app_on_aarch64.md │ ├── dicom_series_to_image_app │ ├── __init__.py │ ├── __main__.py │ └── app.py │ ├── hugging_face_integration_app │ ├── Dockerfile │ ├── debug.sh │ └── med_image_generation │ │ ├── app.py │ │ ├── out.jpg │ │ └── run.sh │ ├── mednist_classifier_monaideploy │ ├── app.yaml │ ├── mednist_classifier_monaideploy.py │ └── requirements.txt │ └── simple_imaging_app │ ├── __init__.py │ ├── __main__.py │ ├── _version.py │ ├── app.py │ ├── app.yaml │ ├── final_output.png │ ├── gaussian_operator.py │ ├── input │ └── brain_mr_input.jpg │ ├── median_operator.py │ ├── requirements.txt │ └── sobel_operator.py ├── monai-deploy-app-sdk.code-workspace ├── monai └── deploy │ ├── __init__.py │ ├── _version.py │ ├── conditions │ └── __init__.py │ ├── core │ ├── __init__.py │ ├── app_context.py │ ├── arg_parser.py │ ├── datastores │ │ ├── __init__.py │ │ ├── datastore.py │ │ ├── factory.py │ │ └── memory.py │ ├── domain │ │ ├── __init__.py │ │ ├── datapath.py │ │ ├── dicom_series.py │ │ ├── dicom_series_selection.py │ │ ├── dicom_sop_instance.py │ │ ├── dicom_study.py │ │ ├── domain.py │ │ └── image.py │ ├── io_type.py │ ├── models │ │ ├── __init__.py │ │ ├── factory.py │ │ ├── model.py │ │ ├── named_model.py │ │ ├── torch_model.py │ │ └── triton_model.py │ └── runtime_env.py │ ├── exceptions.py │ ├── executors │ └── __init__.py │ ├── graphs │ └── __init__.py │ ├── logger │ └── __init__.py │ ├── logging.json │ ├── operators │ ├── __init__.py │ ├── clara_viz_operator.py │ ├── dicom_data_loader_operator.py │ ├── dicom_encapsulated_pdf_writer_operator.py │ ├── dicom_seg_writer_operator.py │ ├── dicom_series_selector_operator.py │ ├── dicom_series_to_volume_operator.py │ ├── dicom_text_sr_writer_operator.py │ ├── dicom_utils.py │ ├── inference_operator.py │ ├── monai_bundle_inference_operator.py │ ├── monai_seg_inference_operator.py │ ├── nii_data_loader_operator.py │ ├── png_converter_operator.py │ ├── publisher_operator.py │ └── stl_conversion_operator.py │ ├── py.typed │ ├── resources │ └── __init__.py │ └── utils │ ├── __init__.py │ ├── argparse_types.py │ ├── deviceutil.py │ ├── fileutil.py │ ├── importutil.py │ ├── sizeutil.py │ ├── spinner.py │ └── version.py ├── notebooks └── tutorials │ ├── 01_simple_app.ipynb │ ├── 02_mednist_app-prebuilt.ipynb │ ├── 02_mednist_app.ipynb │ ├── 03_segmentation_app.ipynb │ ├── 03_segmentation_viz_app.ipynb │ ├── 04_monai_bundle_app.ipynb │ └── 05_multi_model_app.ipynb ├── platforms ├── aws_healthimaging │ ├── README.md │ └── monaideploy_arch.png ├── london_aicentre_aide │ ├── README.md │ └── aide_md.png ├── mayo_cai_viewer └── nuance_pin │ ├── .dockerignore │ ├── Dockerfile │ ├── README.md │ ├── app │ ├── __init__.py │ ├── inference.py │ ├── lung_nodule.py │ └── post_inference_ops.py │ ├── app_wrapper.py │ ├── docker-compose.yml │ ├── model │ └── .gitkeep │ └── requirements.txt ├── pyproject.toml ├── requirements-dev.txt ├── requirements-examples.txt ├── requirements-min.txt ├── requirements.txt ├── run ├── setup.cfg ├── setup.py ├── tests ├── __init__.py ├── conftest.py ├── fixtures │ ├── __init__.py │ └── runner_fixtures.py ├── integration │ └── __init__.py ├── performance │ └── __init__.py ├── system │ └── packager │ │ └── test_packager.py ├── unit │ ├── __init__.py │ ├── test_argparse_types.py │ ├── test_runner.py │ ├── test_runner_utils.py │ └── test_sizeutil.py └── util │ └── __init__.py └── versioneer.py /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 3.0.0 3 | parse = (?P\d+)\.(?P\d+)\.(?P\d+)((?Pa|b|rc)(?P\d+))? 4 | serialize = 5 | {major}.{minor}.{patch}{release}{build} 6 | {major}.{minor}.{patch} 7 | tag_name = {new_version} 8 | tag_message = Bump version: {current_version} → {new_version} 9 | commit = True 10 | commit_args = -s 11 | tag = True 12 | 13 | [bumpversion:part:release] 14 | values = 15 | a 16 | b 17 | rc 18 | '' 19 | optional_value = '' 20 | 21 | [bumpversion:part:build] 22 | first_value = 1 23 | -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | # .coveragerc to control coverage.py 2 | # Refer to: https://coverage.readthedocs.io/en/latest/config.html#syntax 3 | 4 | [run] 5 | source = 6 | monai 7 | omit = 8 | # omit versioneer file 9 | */monai/deploy/_version.py 10 | 11 | [paths] 12 | source = 13 | monai 14 | */site-packages 15 | 16 | 17 | [report] 18 | show_missing = true 19 | precision = 2 20 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = space 3 | indent_size = 4 4 | charset = utf-8 5 | trim_trailing_whitespace = true 6 | max_line_length = 120 7 | insert_final_newline = true 8 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | monai/deploy/_version.py export-subst 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to help us improve MONAI Deploy App SDK 4 | title: "[BUG] " 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | 14 | 15 | **Steps/Code to reproduce bug** 16 | 19 | 20 | **Expected behavior** 21 | 24 | 25 | **Environment details (please complete the following information)** 26 | 27 | - OS/Platform: 28 | - Python Version: 29 | - Method of MONAI Deploy App SDK install: [pip, conda, Docker, or from source] 30 | - SDK Version: 31 | 32 | **Additional context** 33 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation request 3 | about: Report incorrect or needed documentation 4 | title: "[DOC] " 5 | labels: documentation 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Report incorrect documentation 11 | 12 | **Location of incorrect documentation** 13 | 16 | 17 | **Describe the problems or issues found in the documentation** 18 | 21 | 22 | **Steps taken to verify documentation is incorrect** 23 | 26 | 27 | **Suggested fix for documentation** 28 | 31 | 32 | --- 33 | 34 | ## Report needed documentation 35 | 36 | **Report needed documentation** 37 | 40 | 41 | **Describe the documentation you'd like** 42 | 45 | 46 | **Steps taken to search for needed documentation** 47 | 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/enhancement_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Enhancement request 3 | about: Suggest enhancements on specific implementation of MONAI Deploy App SDK and example applications 4 | title: "[IMP] " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your enhancement request related to a problem? Please describe.** 11 | 14 | 15 | **Describe the solution you'd like** 16 | 19 | 20 | **Describe alternatives you've considered** 21 | 24 | 25 | **Additional context** 26 | 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for MONAI Deploy App SDK 4 | title: "[FEA] " 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | 14 | 15 | **Describe the solution you'd like** 16 | 19 | 20 | **Describe alternatives you've considered** 21 | 24 | 25 | **Additional context** 26 | 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/submit-question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Submit question 3 | about: Ask a general question about MONAI Deploy App SDK 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Please use MONAI Deploy App SDK's Discussions tab** 11 | 12 | For questions relating to MONAI Deploy App SDK usage, please do not create an issue. 13 | 14 | Instead, use [MONAI Deploy App SDK's GitHub Discussions tab](https://github.com/Project-MONAI/monai-deploy-app-sdk/discussions). This can be found next to Issues and Pull Requests along the top of our repository. 15 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: 70% 6 | threshold: 10 7 | base: parent 8 | if_no_uploads: error 9 | if_not_found: success 10 | if_ci_failed: error 11 | only_pulls: false 12 | flags: null 13 | paths: null 14 | patch: 15 | default: 16 | target: auto 17 | # Allows PRs without tests, overall stats count 18 | threshold: 100 19 | base: auto 20 | if_no_uploads: error 21 | if_not_found: success 22 | if_ci_failed: error 23 | only_pulls: false 24 | flags: null 25 | paths: null 26 | 27 | # Disable comments on PR 28 | comment: false 29 | 30 | ignore: 31 | - "/monai/deploy/_version.py" 32 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: build 5 | 6 | on: 7 | push: 8 | branches: [ main ] 9 | pull_request: 10 | branches: [ main ] 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 3.9 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: "3.9" 21 | - name: Setup Dev Environment 22 | run: | 23 | pip install virtualenv 24 | virtualenv .venv 25 | source .venv/bin/activate 26 | python3 -m pip install nvidia-cuda-runtime-cu12 27 | ./run setup 28 | - name: Check formatting 29 | run: | 30 | source .venv/bin/activate 31 | python3 -m pip install nvidia-cuda-runtime-cu12 32 | python3 -c 'import sys; print(sys.executable)' 33 | python3 -c 'import site; print(site.getsitepackages())' 34 | python3 -m pip freeze 35 | export CUDA_WHL_LIB_DIR=$(python3 -c 'import nvidia.cuda_runtime; print(nvidia.cuda_runtime.__path__[0])')/lib 36 | export LD_LIBRARY_PATH="$CUDA_WHL_LIB_DIR:$LD_LIBRARY_PATH" 37 | python3 -c 'from holoscan.core import *' 38 | ./run check -f 39 | - name: Run Unit tests 40 | run: | 41 | source .venv/bin/activate 42 | python3 -m pip install nvidia-cuda-runtime-cu12 43 | export CUDA_WHL_LIB_DIR=$(python3 -c 'import nvidia.cuda_runtime; print(nvidia.cuda_runtime.__path__[0])')/lib 44 | export LD_LIBRARY_PATH="$CUDA_WHL_LIB_DIR:$LD_LIBRARY_PATH" 45 | ./run test all unit 46 | - name: Coverage 47 | run: | 48 | source .venv/bin/activate 49 | python3 -m pip install nvidia-cuda-runtime-cu12 50 | export CUDA_WHL_LIB_DIR=$(python3 -c 'import nvidia.cuda_runtime; print(nvidia.cuda_runtime.__path__[0])')/lib 51 | export LD_LIBRARY_PATH="$CUDA_WHL_LIB_DIR:$LD_LIBRARY_PATH" 52 | coverage xml 53 | - name: Upload coverage 54 | uses: codecov/codecov-action@v2 55 | with: 56 | fail_ci_if_error: false 57 | files: ./coverage.xml 58 | -------------------------------------------------------------------------------- /.readthedocs.yml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 3 | 4 | # Required 5 | version: 2 6 | 7 | # Set the OS, Python version and other tools you might need 8 | build: 9 | os: ubuntu-22.04 10 | tools: 11 | python: "3.9" 12 | # You can also specify other tool versions: 13 | # nodejs: "20" 14 | # rust: "1.70" 15 | # golang: "1.20" 16 | 17 | # Build documentation in the "docs/" directory with Sphinx 18 | sphinx: 19 | configuration: docs/source/conf.py 20 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 21 | # builder: "dirhtml" 22 | # Fail on all warnings to avoid broken references 23 | # fail_on_warning: true 24 | 25 | # Optionally build your docs in additional formats such as PDF and ePub 26 | # formats: 27 | # - pdf 28 | # - epub 29 | 30 | # Optional but recommended, declare the Python requirements required 31 | # to build your documentation 32 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 33 | python: 34 | install: 35 | - requirements: docs/requirements.txt 36 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at monai.contact@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, 71 | available at https://www.contributor-covenant.org/version/2/1/code_of_conduct 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # https://packaging.python.org/guides/using-manifest-in/ 2 | 3 | include versioneer.py 4 | include monai/deploy/_version.py 5 | include monai/deploy/logging.json 6 | 7 | include README.md 8 | include LICENSE 9 | -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/Pillow_HPND_LICENSE.txt: -------------------------------------------------------------------------------- 1 | The Python Imaging Library (PIL) is 2 | 3 | Copyright © 1997-2011 by Secret Labs AB 4 | Copyright © 1995-2011 by Fredrik Lundh 5 | 6 | Pillow is the friendly PIL fork. It is 7 | 8 | Copyright © 2010-2021 by Alex Clark and contributors 9 | 10 | Like PIL, Pillow is licensed under the open source HPND License: 11 | 12 | By obtaining, using, and/or copying this software and/or its associated 13 | documentation, you agree that you have read, understood, and will comply 14 | with the following terms and conditions: 15 | 16 | Permission to use, copy, modify, and distribute this software and its 17 | associated documentation for any purpose and without fee is hereby granted, 18 | provided that the above copyright notice appears in all copies, and that 19 | both that copyright notice and this permission notice appear in supporting 20 | documentation, and that the name of Secret Labs AB or the author not be 21 | used in advertising or publicity pertaining to distribution of the software 22 | without specific, written prior permission. 23 | 24 | SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 25 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 26 | IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL, 27 | INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 28 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 29 | OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 30 | PERFORMANCE OF THIS SOFTWARE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/PyPDF2_BSD-3_LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2008, Mathieu Fenniak 2 | Some contributions copyright (c) 2007, Ashish Kulkarni 3 | Some contributions copyright (c) 2014, Steve Witham 4 | 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are 9 | met: 10 | 11 | * Redistributions of source code must retain the above copyright notice, 12 | this list of conditions and the following disclaimer. 13 | * Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | * The name of the author may not be used to endorse or promote products 17 | derived from this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/colorama_BSD-3_LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Jonathan Hartley 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the copyright holders, nor those of its contributors 15 | may be used to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/highdicom_MIT_LICENSE.txt: -------------------------------------------------------------------------------- 1 | highdicom is licensed under the MIT License: http://www.opensource.org/licenses/mit-license.php 2 | 3 | A short and simple permissive license with conditions only requiring preservation of copyright and license notices. Licensed works, modifications, and larger works may be distributed under different terms and without source code. 4 | 5 | 6 | Copyright 2020 MGH Computational Pathology 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/networkx_BSD-3_LICENSE.txt: -------------------------------------------------------------------------------- 1 | NetworkX is distributed with the 3-clause BSD license. 2 | 3 | :: 4 | 5 | Copyright (C) 2004-2022, NetworkX Developers 6 | Aric Hagberg 7 | Dan Schult 8 | Pieter Swart 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are 13 | met: 14 | 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 18 | * Redistributions in binary form must reproduce the above 19 | copyright notice, this list of conditions and the following 20 | disclaimer in the documentation and/or other materials provided 21 | with the distribution. 22 | 23 | * Neither the name of the NetworkX Developers nor the names of its 24 | contributors may be used to endorse or promote products derived 25 | from this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/numpy_BSD-3_LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2005-2020, NumPy Developers. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of the NumPy Developers nor the names of any 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/parameterized_BSD-2_LICENSE.txt: -------------------------------------------------------------------------------- 1 | Unless stated otherwise in the source files, all code is copyright 2010 David 2 | Wolever . All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY DAVID WOLEVER ``AS IS'' AND ANY EXPRESS OR 15 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 16 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 17 | EVENT SHALL DAVID WOLEVER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 21 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 22 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | 25 | The views and conclusions contained in the software and documentation are those 26 | of the authors and should not be interpreted as representing official policies, 27 | either expressed or implied, of David Wolever. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/pydicom_MIT_LICENSE.txt: -------------------------------------------------------------------------------- 1 | License file for pydicom, a pure-python DICOM library 2 | 3 | Copyright (c) 2008-2020 Darcy Mason and pydicom contributors 4 | 5 | Except for portions outlined below, pydicom is released under an MIT license: 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | 25 | Portions of pydicom (private dictionary file(s)) were generated from the 26 | private dictionary of the GDCM library, released under the following license: 27 | 28 | Program: GDCM (Grassroots DICOM). A DICOM library 29 | Module: http://gdcm.sourceforge.net/Copyright.html 30 | 31 | Copyright (c) 2006-2010 Mathieu Malaterre 32 | Copyright (c) 1993-2005 CREATIS 33 | (CREATIS = Centre de Recherche et d'Applications en Traitement de l'Image) 34 | All rights reserved. 35 | 36 | Redistribution and use in source and binary forms, with or without 37 | modification, are permitted provided that the following conditions are met: 38 | 39 | * Redistributions of source code must retain the above copyright notice, 40 | this list of conditions and the following disclaimer. 41 | 42 | * Redistributions in binary form must reproduce the above copyright notice, 43 | this list of conditions and the following disclaimer in the documentation 44 | and/or other materials provided with the distribution. 45 | 46 | * Neither name of Mathieu Malaterre, or CREATIS, nor the names of any 47 | contributors (CNRS, INSERM, UCB, Universite Lyon I), may be used to 48 | endorse or promote products derived from this software without specific 49 | prior written permission. 50 | 51 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 52 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR 55 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 57 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 58 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 59 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 60 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/pytest123_MIT_LICENSE.txt: -------------------------------------------------------------------------------- 1 | This is the MIT license: http://www.opensource.org/licenses/mit-license.php 2 | 3 | Copyright (c) Alex Grönholm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | software and associated documentation files (the "Software"), to deal in the Software 7 | without restriction, including without limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 9 | to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/torch_BSD-3_LICENSE.txt: -------------------------------------------------------------------------------- 1 | From PyTorch: 2 | 3 | Copyright (c) 2016- Facebook, Inc (Adam Paszke) 4 | Copyright (c) 2014- Facebook, Inc (Soumith Chintala) 5 | Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert) 6 | Copyright (c) 2012-2014 Deepmind Technologies (Koray Kavukcuoglu) 7 | Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu) 8 | Copyright (c) 2011-2013 NYU (Clement Farabet) 9 | Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou, Iain Melvin, Jason Weston) 10 | Copyright (c) 2006 Idiap Research Institute (Samy Bengio) 11 | Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert, Samy Bengio, Johnny Mariethoz) 12 | 13 | From Caffe2: 14 | 15 | Copyright (c) 2016-present, Facebook Inc. All rights reserved. 16 | 17 | All contributions by Facebook: 18 | Copyright (c) 2016 Facebook Inc. 19 | 20 | All contributions by Google: 21 | Copyright (c) 2015 Google Inc. 22 | All rights reserved. 23 | 24 | All contributions by Yangqing Jia: 25 | Copyright (c) 2015 Yangqing Jia 26 | All rights reserved. 27 | 28 | All contributions by Kakao Brain: 29 | Copyright 2019-2020 Kakao Brain 30 | 31 | All contributions from Caffe: 32 | Copyright(c) 2013, 2014, 2015, the respective contributors 33 | All rights reserved. 34 | 35 | All other contributions: 36 | Copyright(c) 2015, 2016 the respective contributors 37 | All rights reserved. 38 | 39 | Caffe2 uses a copyright model similar to Caffe: each contributor holds 40 | copyright over their contributions to Caffe2. The project versioning records 41 | all such contribution and copyright details. If a contributor wants to further 42 | mark their specific copyright on a particular contribution, they should 43 | indicate their copyright solely in the commit message of the change when it is 44 | committed. 45 | 46 | All rights reserved. 47 | 48 | Redistribution and use in source and binary forms, with or without 49 | modification, are permitted provided that the following conditions are met: 50 | 51 | 1. Redistributions of source code must retain the above copyright 52 | notice, this list of conditions and the following disclaimer. 53 | 54 | 2. Redistributions in binary form must reproduce the above copyright 55 | notice, this list of conditions and the following disclaimer in the 56 | documentation and/or other materials provided with the distribution. 57 | 58 | 3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories America 59 | and IDIAP Research Institute nor the names of its contributors may be 60 | used to endorse or promote products derived from this software without 61 | specific prior written permission. 62 | 63 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 64 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 67 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 68 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 69 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 70 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 71 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 72 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 73 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /THIRD_PARTY_NOTICES/typeguard_MIT_LICENSE.txt: -------------------------------------------------------------------------------- 1 | This is the MIT license: http://www.opensource.org/licenses/mit-license.php 2 | 3 | Copyright (c) Alex Grönholm 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this 6 | software and associated documentation files (the "Software"), to deal in the Software 7 | without restriction, including without limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons 9 | to whom the Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or 12 | substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 15 | INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 16 | PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 17 | FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 19 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | 22 | clean: 23 | rm -rf build/ 24 | -------------------------------------------------------------------------------- /docs/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* 2 | https://github.com/pandas-dev/pydata-sphinx-theme/blob/master/pydata_sphinx_theme/static/css/theme.css 3 | https://pydata-sphinx-theme.readthedocs.io/en/latest/user_guide/customizing.html#customizing-the-css 4 | */ 5 | 6 | @import url("https://fonts.googleapis.com/css?family=Lekton:700|Roboto&display=swap"); 7 | body { 8 | font-family: "Roboto", sans-serif; 9 | } 10 | 11 | .wy-menu-vertical p.caption { 12 | color: #7cccc7; 13 | } 14 | 15 | * { 16 | font-variant-ligatures: none; 17 | } 18 | 19 | .autoclasstoc td { 20 | padding: 0.2rem; 21 | line-height: normal; 22 | } 23 | 24 | dl.field-list>dt { 25 | word-break: normal; 26 | } 27 | 28 | h5.card-header { 29 | margin-top: 0px; 30 | margin-bottom: 0px; 31 | } 32 | 33 | h5.card-header::before { 34 | height: 0px; 35 | margin-top: 0px; 36 | } 37 | 38 | 39 | /* Customize styles */ 40 | 41 | :root { 42 | --pst-color-inline-code: 232, 62, 140; 43 | --pst-font-size-h1: 32px; 44 | --pst-font-size-h2: 26px; 45 | --pst-font-size-h3: 21px; 46 | --pst-font-size-h4: 18px; 47 | --pst-font-size-h5: 16px; 48 | --pst-font-size-h6: 14px; 49 | } 50 | 51 | 52 | /* Customize headings */ 53 | 54 | .heading-style, 55 | h1 { 56 | font-family: Content-font, Roboto, sans-serif; 57 | font-weight: 500; 58 | line-height: 1.5; 59 | } 60 | 61 | /* Code Highlight */ 62 | div[class^="highlight"] pre { 63 | color: rgb(248, 248, 242); 64 | background-color: rgb(41, 44, 46); 65 | border: 0px; 66 | box-shadow: none; 67 | } 68 | div.highlight{ 69 | border-radius: 5px; 70 | } 71 | div.highlight pre { 72 | border-radius: 5px; 73 | } 74 | div.cell div.cell_input div.highlight { 75 | border-radius: 0px; 76 | } 77 | 78 | /* Code Block Caption */ 79 | div.code-block-caption { 80 | font-weight: bold; 81 | font-style: italic; 82 | } 83 | 84 | /* Code Line Highlight */ 85 | .highlight .hll { 86 | background-color: rgb(133, 132, 24); 87 | } 88 | 89 | /* Left bar color for cells in Jupyter Notebook */ 90 | div.cell div.cell_input { 91 | border-left-color: rgb(127, 218, 255) 92 | } 93 | 94 | /* Code highlight in source code view */ 95 | .viewcode-block:target { 96 | background-color: #382927; 97 | } 98 | 99 | /* Backquote */ 100 | blockquote { 101 | background-color: rgb(129 252 255 / 30%); 102 | border-left: 8px solid rgb(127, 218, 255); 103 | padding: 15px 30px 15px 15px; 104 | } 105 | blockquote p { 106 | margin-bottom: 0px; 107 | } 108 | 109 | /* Mermaid 110 | to avoid the label text being cut off 111 | */ 112 | .edgeTerminals { 113 | font-size: 9px !important; 114 | } 115 | -------------------------------------------------------------------------------- /docs/images/MONAI-logo-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/docs/images/MONAI-logo-color.png -------------------------------------------------------------------------------- /docs/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/docs/images/favicon.ico -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | Sphinx==4.1.2 2 | sphinx-autobuild==2021.3.14 3 | myst-nb==0.17.2 # this version is fine in python 3.9 and avoids pulling in multiple nbformat packages 4 | myst-parser==0.18.0 5 | lxml_html_clean # needed by myst-nb 6 | linkify-it-py==1.0.1 # https://myst-parser.readthedocs.io/en/latest/syntax/optional.html?highlight=linkify#linkify 7 | sphinx-togglebutton==0.2.3 8 | sphinx-copybutton==0.4.0 9 | sphinxcontrib-bibtex<2.0.0 # https://github.com/executablebooks/jupyter-book/issues/1137 10 | sphinxcontrib-spelling==7.2.1 # https://sphinxcontrib-spelling.readthedocs.io/en/latest/index.html 11 | sphinx-thebe==0.0.10 12 | sphinx-panels==0.6.0 13 | ablog==0.10.19 14 | docutils==0.16 # 0.17 causes error. https://github.com/executablebooks/MyST-Parser/issues/343 15 | pydata_sphinx_theme==0.6.3 16 | sphinxemoji==0.1.8 17 | torch>=1.12.0 18 | sphinx-autodoc-typehints==1.12.0 19 | sphinxcontrib-applehelp==1.0.2 20 | sphinxcontrib-devhelp==1.0.2 21 | sphinxcontrib-htmlhelp==2.0.0 22 | sphinxcontrib-jsmath==1.0.1 23 | sphinxcontrib-qthelp==1.0.3 24 | sphinxcontrib-serializinghtml==1.1.5 25 | sphinxcontrib-mermaid==0.7.1 26 | -------------------------------------------------------------------------------- /docs/source/_templates/autosummary/class.rst: -------------------------------------------------------------------------------- 1 | {{ fullname | escape | underline}} 2 | 3 | .. currentmodule:: {{ module }} 4 | 5 | .. autoclass:: {{ objname }} 6 | 7 | {% block methods %} 8 | 9 | {% if methods %} 10 | .. rubric:: {{ _('Methods') }} 11 | 12 | .. autosummary:: 13 | {% for item in methods %} 14 | ~{{ name }}.{{ item }} 15 | {%- endfor %} 16 | {% endif %} 17 | {% endblock %} 18 | 19 | {% block attributes %} 20 | {% if attributes %} 21 | .. rubric:: {{ _('Attributes') }} 22 | 23 | .. autosummary:: 24 | {% for item in attributes %} 25 | ~{{ name }}.{{ item }} 26 | {%- endfor %} 27 | {% endif %} 28 | {% endblock %} -------------------------------------------------------------------------------- /docs/source/_templates/autosummary/module.rst: -------------------------------------------------------------------------------- 1 | {{ fullname }} 2 | {{ underline }} 3 | 4 | .. contents:: 5 | :local: 6 | 7 | .. automodule:: {{fullname}} 8 | :members: 9 | :noindex: 10 | :undoc-members: 11 | :show-inheritance: -------------------------------------------------------------------------------- /docs/source/_templates/navbar-logo.html: -------------------------------------------------------------------------------- 1 | 2 | {% if logo %} 3 | {% if not theme_logo_link %} 4 | 5 | 6 | 7 | {% elif theme_logo_link[:4] == 'http' %} 8 | 18 | {% else %} 19 | 20 | 21 | 22 | {% endif %} 23 | {% else %} 24 | 25 |

{{ project }}

26 |
27 | {% endif %} 28 | -------------------------------------------------------------------------------- /docs/source/_templates/sidebar-quicklinks.html: -------------------------------------------------------------------------------- 1 |
2 |
Version {{ release }}
3 |
4 | 10 |
11 |
12 | -------------------------------------------------------------------------------- /docs/source/developing_with_sdk/core_concepts.md: -------------------------------------------------------------------------------- 1 | # Core concepts 2 | 3 | This document introduces the basic concepts of the MONAI Deploy App SDK. If you are eager to try out the SDK in practice, you can start with the [tutorial](/getting_started/tutorials/index). After the tutorial, you can return to this document to learn more about how MONAI Deploy App SDK works. 4 | 5 | As described in the [Architecture of MONAI Deploy App SDK](/introduction/architecture), an application is implemented by subclassing [Application](/modules/_autosummary/monai.deploy.core.Application) class. 6 | 7 | ```{mermaid} 8 | :alt: Application class diagram 9 | :align: center 10 | 11 | %%{init: {"theme": "base", "themeVariables": { "fontSize": "12px"}} }%% 12 | 13 | classDiagram 14 | direction TB 15 | class Application { 16 | } 17 | 18 | class Graph { 19 | } 20 | 21 | class Operator { 22 | } 23 | 24 | <> Application 25 | <> Graph 26 | <> Operator 27 | 28 | Application --> Graph : makes use of 29 | Graph "1" --> "many" Operator : contains 30 | ``` 31 | 32 | [Application](/modules/_autosummary/monai.deploy.core.Application) represents a workflow as a [Graph](/modules/graphs) and the graph handles [Operator](/modules/_autosummary/monai.deploy.core.Operator)s which are computational tasks. 33 | 34 | To develop and deploy your MONAI App, you can follow the steps below (click a node to see the detail): 35 | 36 | ## 1. Developing Application 37 | 38 | ```{mermaid} 39 | :alt: Developing Application 40 | :align: center 41 | :caption: ⠀⠀Steps to develop an application 42 | 43 | %%{init: {"theme": "base", "themeVariables": { "fontSize": "12px"}} }%% 44 | 45 | graph TD 46 | 47 | Design(Designing Workflow) 48 | --> Operator(Creating Operator classes) 49 | --> App(Creating Application class) 50 | --> ExecApp(Executing app locally) 51 | 52 | 53 | click Design "./designing_workflow.html" "Go to the document" _self 54 | click Operator "./creating_operator_classes.html" "Go to the document" _self 55 | click App "./creating_application_class.html" "Go to the document" _self 56 | click ExecApp "./executing_app_locally.html" "Go to the document" _self 57 | ``` 58 | 59 | 60 | First, you will need to design the workflow of your application that defines [Operator](/modules/_autosummary/monai.deploy.core.Operator)s (tasks) and flows among them. Once the workflow is designed, you can start implementing operator classes for those that you cannot use existing operators as they are. Then implement an [Application](/modules/_autosummary/monai.deploy.core.Application) class to make a workflow graph with the operators. 61 | 62 | You can execute and debug your application locally in a Jupyter notebook or through CLI. 63 | 64 | ## 2. Packaging, Local-Running, and Deploying Application Package 65 | 66 | ```{mermaid} 67 | :alt: Application class diagram 68 | :align: center 69 | :caption: ⠀⠀Steps to package, local-running, and deploying a MONAI Application Package (MAP) 70 | 71 | %%{init: {"theme": "base", "themeVariables": { "fontSize": "12px"}} }%% 72 | 73 | graph TD 74 | 75 | Package(Packaging app) 76 | --> ExecPackage(Executing packaged app locally) 77 | --> DeployPackage(Deploying to the remote server) 78 | 79 | click Package "./packaging_app.html" "Go to the document" _self 80 | click ExecPackage "./executing_packaged_app_locally.html" "Go to the document" _self 81 | click DeployPackage "./deploying_and_hosting_map.html" "Go to the document" _self 82 | ``` 83 | 84 | 85 | After your application is tested and verified well and you feel you made a great application :), it's time to package your application, test locally, and deploy it to the remote server. 86 | -------------------------------------------------------------------------------- /docs/source/developing_with_sdk/deploying_and_hosting_map.md: -------------------------------------------------------------------------------- 1 | # Deploying and Hosting MONAI App Package 2 | 3 | The MONAI Application Package, MAP, built and packaged using MONAI Deploy App SDK, can be deployed in multiple ways, each with different levels of integration with a hosting platform. 4 | - A MAP is an OCI compliant container, albeit requiring Nvidia Container Toolkit as it is by default based on Nvidia container image with GPU support. The hosting platforms, via their own tooling, can inspect the MAP metadata and ensure dependencies are satisfied on launching the MAP container, for example, an MAP can be used in a [Argo workflow](https://argoproj.github.io/argo-workflows/), in [Docker Compose](https://docs.docker.com/compose/), or simply run using [Docker](https://www.docker.com/). 5 | - A MAP runs "natively" on a platform, where the platform specific adaptor or utilities embedded in the MAP can understand the MAP and the platform APIs thus manage the life cycle of the application per platform requests. At the onset, the only native execution planned is on the MONAI Deploy. The support for other platforms is on the horizon. 6 | - As envisioned for the long term, standardization of deployment package specification will be needed, so that compliant application packages shall work on all compliant platforms. One of the initiatives in this area is the Open Application Model, where an MAP can be used as the Application component. 7 | -------------------------------------------------------------------------------- /docs/source/developing_with_sdk/index.md: -------------------------------------------------------------------------------- 1 | # DEVELOPING WITH SDK 2 | 3 | ```{toctree} 4 | :glob: 5 | :maxdepth: 2 6 | 7 | core_concepts 8 | designing_workflow 9 | creating_operator_classes 10 | creating_application_class 11 | executing_app_locally.ipynb 12 | packaging_app 13 | executing_packaged_app_locally 14 | deploying_and_hosting_map 15 | ``` 16 | -------------------------------------------------------------------------------- /docs/source/getting_started/examples.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | ## Apps 4 | 5 | has example apps that you can see. 6 | 7 | - simple_imaging_app 8 | - mednist_classifier_monaideploy 9 | - ai_spleen_seg_app 10 | - ai_pancreas_seg_app 11 | - ai_multi_ai_app 12 | - ai_livertumor_seg_app 13 | - ai_unetr_seg_app 14 | - dicom_series_to_image_app 15 | - breast_density_classifer_app 16 | - cchmc_ped_abd_ct_seg_app 17 | - ai_remote_infer_app 18 | -------------------------------------------------------------------------------- /docs/source/getting_started/index.md: -------------------------------------------------------------------------------- 1 | # GETTING STARTED 2 | 3 | ```{toctree} 4 | :maxdepth: 2 5 | 6 | installing_app_sdk 7 | tutorials/index 8 | examples 9 | ``` 10 | -------------------------------------------------------------------------------- /docs/source/getting_started/installing_app_sdk.md: -------------------------------------------------------------------------------- 1 | # Installing App SDK 2 | 3 | MONAI Deploy App SDK is available as a Python package through [Python Package Index (PyPI)](https://pypi.org/project/monai-deploy-app-sdk/). 4 | 5 | MONAI Deploy App SDK's core functionality is written in Python 3 (>= 3.8) for Linux. 6 | 7 | ```bash 8 | pip install monai-deploy-app-sdk 9 | ``` 10 | 11 | If you have installed MONAI Deploy App SDK previously, you can upgrade to the latest version with: 12 | 13 | ```bash 14 | pip install --upgrade monai-deploy-app-sdk 15 | ``` 16 | 17 | :::{note} 18 | For packaging and running your application using [MONAI Application Packager](/developing_with_sdk/packaging_app) and [MONAI Application Runner (MAR)](/developing_with_sdk/executing_packaged_app_locally), [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) needs to be installed. 19 | 20 | For version 1.0.0, `nvcr.io/nvidia/clara-holoscan/holoscan:v1.0.3-dgpu` is used by [MONAI Application Packager](/developing_with_sdk/packaging_app) as base image for X86-64 in Linux system, though this will change with versions. 21 | 22 | The base image size is large, so it is recommended to pull the image in advance to save time. Note that the container image tag in the following example, e.g. `v1.0.3`, corresponds to the underlying Holoscan SDK version. 23 | 24 | ```bash 25 | docker pull nvcr.io/nvidia/clara-holoscan/holoscan:v1.0.3-dgpu 26 | ``` 27 | 28 | ::: 29 | 30 | :::{note} 31 | Windows users can install [CUDA on WSL](https://docs.nvidia.com/cuda/wsl-user-guide/index.html) to use MONAI Deploy App SDK. 32 | ::: 33 | -------------------------------------------------------------------------------- /docs/source/getting_started/tutorials/index.md: -------------------------------------------------------------------------------- 1 | # Tutorials 2 | 3 | ```{toctree} 4 | :glob: 5 | :maxdepth: 2 6 | 7 | simple_app 8 | mednist_app 9 | monai_bundle_app 10 | segmentation_clara-viz_app 11 | multi_model_app 12 | segmentation_app 13 | ``` 14 | -------------------------------------------------------------------------------- /docs/source/getting_started/tutorials/multi_model_app.md: -------------------------------------------------------------------------------- 1 | # Creating a Segmentation App Supporting Multiple Models 2 | 3 | This tutorial shows how to create an inference application with multiple models, focusing on model files organization, inferring with named model in the application, and packaging. 4 | 5 | The models used in this example are trained with MONAI, and are packaged in the [MONAI Bundle](https://docs.monai.io/en/latest/bundle_intro.html) format. 6 | 7 | ## Setup 8 | 9 | ```bash 10 | # Create a virtual environment with Python 3.9. 11 | # Skip if you are already in a virtual environment. 12 | conda create -n monai python=3.9 pytorch torchvision jupyterlab cudatoolkit=12.2 -c pytorch -c conda-forge 13 | conda activate monai 14 | 15 | # Launch JupyterLab if you want to work on Jupyter Notebook 16 | jupyter-lab 17 | ``` 18 | 19 | ## Executing from Jupyter Notebook 20 | 21 | ```{toctree} 22 | :maxdepth: 4 23 | 24 | ../../notebooks/tutorials/05_multi_model_app.ipynb 25 | ``` 26 | 27 | ```{raw} html 28 |

29 | 30 | Download 05_multi_model_app.ipynb 31 | 32 |

33 | ``` 34 | 35 | ## Executing from Shell 36 | 37 | **_Note:_** Data files are now access controlled. Please first request permission to access the [shared folder on Google Drive](https://drive.google.com/drive/folders/1EONJsrwbGsS30td0hs8zl4WKjihew1Z3?usp=sharing). Please download zip file, `ai_multi_model_bundle_data.zip` in the `ai_multi_ai_app` folder, to the same folder as the notebook example. 38 | 39 | ```bash 40 | # Clone the github project (the latest version of main branch only) 41 | git clone --branch main --depth 1 https://github.com/Project-MONAI/monai-deploy-app-sdk.git 42 | 43 | cd monai-deploy-app-sdk 44 | 45 | # Install monai-deploy-app-sdk package 46 | pip install --upgrade monai-deploy-app-sdk 47 | 48 | # Download the zip file containing both the model and test data. 49 | # After downloading it using gdown, unzip the zip file saved by gdown 50 | rm -rf dcm && rm -rf multi_models 51 | unzip -o ai_multi_model_bundle_data.zip 52 | 53 | # Install necessary packages from the app; note that numpy-stl and trimesh are only 54 | # needed if the application uses the STL Conversion Operator 55 | pip install monai torch pydicom highdicom SimpleITK Pillow nibabel scikit-image numpy-stl trimesh 56 | 57 | # Use env variables for input, output, and model paths for local running of Python application 58 | export HOLOSCAN_INPUT_PATH=dcm 59 | export HOLOSCAN_MODEL_PATH=multi_models 60 | export HOLOSCAN_OUTPUT_PATH="output" 61 | export HOLOSCAN_LOG_LEVEL=TRACE 62 | 63 | # Local execution of the app directly 64 | python examples/apps/ai_multi_ai_app/app.py 65 | 66 | # Package app (creating MAP docker image) using `-l DEBUG` option to see progress. 67 | # This assumes that nvidia docker is installed in the local machine. 68 | # Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2. 69 | monai-deploy package examples/apps/ai_multi_ai_app \ 70 | --tag multi_model_app:latest \ 71 | --config examples/apps/ai_multi_ai_app/app.yaml \ 72 | --models multi_models \ 73 | --platform x86_64 \ 74 | -l DEBUG 75 | 76 | # Note: for AMD GPUs, nvidia-docker is not required, but the dependency of the App SDK, namely Holoscan SDK 77 | # has not been tested to work with a ROCM base image. 78 | 79 | # Run the app with docker image and input file locally 80 | rm -rf output 81 | monai-deploy run multi_model_app-x64-workstation-dgpu-linux-amd64:latest -i dcm -o output 82 | ls -R output 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/source/getting_started/tutorials/segmentation_app.md: -------------------------------------------------------------------------------- 1 | # Creating a Segmentation App with a TorchScript Model 2 | 3 | This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI and saved as TorchScript, without necessarily being a MONAI bundle. 4 | 5 | Please note that the following steps are for demonstration purpose. The code pulled from GitHub is not the same as that in the actual Jupyter Notebook, which deliberately does not use the MONAI Bundle Inference Operator. 6 | 7 | ## Setup 8 | 9 | ```bash 10 | # Create a virtual environment with Python 3.9. 11 | # Skip if you are already in a virtual environment. 12 | conda create -n monai python=3.9 pytorch torchvision jupyterlab cudatoolkit=12.2 -c pytorch -c conda-forge 13 | conda activate monai 14 | 15 | # Launch JupyterLab if you want to work on Jupyter Notebook 16 | jupyter-lab 17 | ``` 18 | 19 | ## Executing from Jupyter Notebook 20 | 21 | ```{toctree} 22 | :maxdepth: 4 23 | 24 | ../../notebooks/tutorials/03_segmentation_app.ipynb 25 | ``` 26 | 27 | ```{raw} html 28 |

29 | 30 | Download 03_segmentation_app.ipynb 31 | 32 |

33 | ``` 34 | 35 | ## Executing from Shell 36 | 37 | **_Note:_** Data files are now access controlled. Please first request permission to access the [shared folder on Google Drive](https://drive.google.com/drive/folders/1EONJsrwbGsS30td0hs8zl4WKjihew1Z3?usp=sharing). Please download zip file, `ai_spleen_seg_bundle_data.zip` in the `ai_spleen_seg_app` folder, to the same folder as the notebook example. 38 | 39 | ```bash 40 | # Clone the github project (the latest version of main branch only) 41 | git clone --branch main --depth 1 https://github.com/Project-MONAI/monai-deploy-app-sdk.git 42 | 43 | cd monai-deploy-app-sdk 44 | 45 | # Install monai-deploy-app-sdk package 46 | pip install --upgrade monai-deploy-app-sdk 47 | 48 | # Download the zip file containing both the model and test data. 49 | # After downloading it using gdown, unzip the zip file saved by gdown and 50 | # copy the model file into a folder structure that is required by CLI Packager 51 | rm -rf dcm 52 | unzip -o ai_spleen_seg_bundle_data.zip 53 | rm -rf spleen_model && mkdir -p spleen_model && mv model.ts spleen_model && ls spleen_model 54 | 55 | # Install necessary packages from the app; note that numpy-stl and trimesh are only 56 | # needed if the application uses the STL Conversion Operator 57 | pip install monai torch pydicom highdicom SimpleITK Pillow nibabel scikit-image numpy-stl trimesh 58 | 59 | # Use env variables for input, output, and model paths for local running of Python application 60 | export HOLOSCAN_INPUT_PATH=dcm 61 | export HOLOSCAN_MODEL_PATH=spleen_model/model.ts 62 | export HOLOSCAN_OUTPUT_PATH="output" 63 | export HOLOSCAN_LOG_LEVEL=TRACE 64 | 65 | # Local execution of the app directly or using MONAI Deploy CLI 66 | python examples/apps/ai_spleen_seg_app/app.py 67 | 68 | # Package app (creating MAP docker image) using `-l DEBUG` option to see progress. 69 | # This assumes that nvidia docker is installed in the local machine. 70 | # Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2. 71 | monai-deploy package examples/apps/ai_spleen_seg_app \ 72 | --config examples/apps/ai_spleen_seg_app/app.yaml \ 73 | --tag seg_app:latest \ 74 | --models spleen_model/model.ts \ 75 | --platform x86_64 \ 76 | -l DEBUG 77 | 78 | # Note: for AMD GPUs, nvidia-docker is not required, but the dependency of the App SDK, namely Holoscan SDK 79 | # has not been tested to work with a ROCM base image. 80 | 81 | # Run the app with docker image and input file locally 82 | rm -rf output 83 | monai-deploy run seg_app-x64-workstation-dgpu-linux-amd64:latest -i dcm -o output 84 | ls -R output 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/source/getting_started/tutorials/segmentation_clara-viz_app.md: -------------------------------------------------------------------------------- 1 | # Creating a Segmentation App Including Including Visualization with Clara-Viz 2 | 3 | This tutorial shows how to create an organ segmentation application for a PyTorch model that has been trained with MONAI, and provide interactive visualization of the segmentation and input images with Clara Viz integration. 4 | 5 | ## Setup 6 | 7 | ```bash 8 | # Create a virtual environment with Python 3.9. 9 | # Skip if you are already in a virtual environment. 10 | conda create -n monai python=3.9 pytorch torchvision jupyterlab cudatoolkit=12.2 -c pytorch -c conda-forge 11 | conda activate monai 12 | 13 | # Launch JupyterLab if you want to work on Jupyter Notebook 14 | jupyter-lab 15 | ``` 16 | 17 | ## Executing from Jupyter Notebook 18 | 19 | ```{toctree} 20 | :maxdepth: 4 21 | 22 | ../../notebooks/tutorials/03_segmentation_viz_app.ipynb 23 | ``` 24 | 25 | ```{raw} html 26 |

27 | 28 | Download 03_segmentation_viz_app.ipynb 29 | 30 |

31 | ``` -------------------------------------------------------------------------------- /docs/source/getting_started/tutorials/simple_app.md: -------------------------------------------------------------------------------- 1 | # Creating a Simple Image Processing App 2 | 3 | This tutorial shows how a simple image processing application can be created with MONAI Deploy App SDK. 4 | 5 | ## Setup 6 | 7 | ```bash 8 | # Create a virtual environment with Python 3.9. 9 | # Skip if you are already in a virtual environment. 10 | conda create -n monai python=3.9 pytorch torchvision jupyterlab cudatoolkit=12.2 -c pytorch -c conda-forge 11 | conda activate monai 12 | 13 | # Launch JupyterLab if you want to work on Jupyter Notebook 14 | jupyter-lab 15 | ``` 16 | 17 | ## Executing from Jupyter Notebook 18 | 19 | ```{toctree} 20 | :maxdepth: 4 21 | 22 | ../../notebooks/tutorials/01_simple_app.ipynb 23 | ``` 24 | 25 | 30 | 31 | ```{raw} html 32 |

33 | 34 | Download 01_simple_app.ipynb 35 | 36 |

37 | ``` 38 | 39 | ## Executing from Shell 40 | 41 | ```bash 42 | # Clone the github project (the latest version of the main branch only) 43 | git clone --branch main --depth 1 https://github.com/Project-MONAI/monai-deploy-app-sdk.git 44 | 45 | cd monai-deploy-app-sdk 46 | 47 | # Install monai-deploy-app-sdk package 48 | pip install monai-deploy-app-sdk 49 | 50 | # Install necessary packages from the app. Can simply run `pip install -r examples/apps/simple_imaging_app/requirements.txt` 51 | pip install scikit-image, setuptools, Pillow, matplotlib 52 | 53 | # See the input file exists in the default `input`` folder in the current working directory 54 | ls examples/apps/simple_imaging_app/input/ 55 | 56 | # Set the environment variable for the input, with relative path in this example. 57 | export HOLOSCAN_INPUT_PATH="./examples/apps/simple_imaging_app/input" 58 | 59 | # Env var can also be used to direct the output instead of using the default folder as in the following steps 60 | export HOLOSCAN_OUTPUT_PATH="./output_simple_imaging" 61 | 62 | # Local execution of the app with output file in the `output` folder in the current working directory 63 | python examples/apps/simple_imaging_app/app.py 64 | 65 | # Check the output file 66 | ls output 67 | 68 | # Package app (creating MAP docker image) using `-l DEBUG` option to see progress. Note the container image name is postfixed with platform info. 69 | # This assumes that nvidia docker is installed in the local machine. 70 | # Please see https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#docker to install nvidia-docker2. 71 | 72 | monai-deploy package examples/apps/simple_imaging_app -c examples/apps/simple_imaging_app/app.yaml -t simple_app:latest --platform x86_64 -l DEBUG 73 | 74 | # Show the application and package manifest files of the MONAI Application Package 75 | 76 | docker images | grep simple_app 77 | docker run --rm simple_app-x64-workstation-dgpu-linux-amd64:latest show 78 | 79 | # Run the MAP container image with MONAI Deploy MAP Runner, with a cleaned output folder 80 | rm -rf output 81 | monai-deploy run simple_app-x64-workstation-dgpu-linux-amd64:latest -i $HOLOSCAN_INPUT_PATH -o output 82 | 83 | # Check the output file 84 | ls output 85 | ``` 86 | -------------------------------------------------------------------------------- /docs/source/index.md: -------------------------------------------------------------------------------- 1 | # MONAI Deploy App SDK 2 | 3 | ```{toctree} 4 | :glob: 5 | :maxdepth: 3 6 | 7 | introduction/index 8 | getting_started/index 9 | developing_with_sdk/index 10 | ``` 11 | 12 | ```{toctree} 13 | :glob: 14 | :maxdepth: 2 15 | 16 | modules/index 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/source/introduction/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to MONAI Deploy App SDK 2 | 3 | ```{include} ../../../CONTRIBUTING.md 4 | :relative-docs: docs/ 5 | :relative-images: 6 | ``` 7 | -------------------------------------------------------------------------------- /docs/source/introduction/index.md: -------------------------------------------------------------------------------- 1 | # INTRODUCTION 2 | 3 | ```{toctree} 4 | :glob: 5 | :maxdepth: 3 6 | 7 | overview 8 | architecture 9 | roadmap 10 | ../release_notes/index 11 | contributing 12 | ``` 13 | -------------------------------------------------------------------------------- /docs/source/introduction/overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | The MONAI Deploy Application SDK offers a framework and associated tools to design, verify and analyze the performance of AI-driven applications in the healthcare domain. 4 | 5 | It contains the following elements: 6 | 7 | - Pythonic framework for app development 8 | - A mechanism to package an app in a "MONAI Application Package" (MAP), a container image that is self-describing 9 | - A mechanism to locally run a MAP via App Runner 10 | - A set of sample applications 11 | - API documentation 12 | 13 | To further accelerate the development of medical imaging AI inference application with DICOM imaging network integration, a set of domain specific functionalities are provided by this Application SDK, 14 | - generic application classes to automate the inference with MONAI Bundle 15 | - DICOM study parsing and selection classes, as well as DICOM instance to volume image conversion 16 | - DICOM instance writers to encapsulate AI inference results in these DICOM OID, 17 | - DICOM Segmentation 18 | - DICOM Basic Text Structured Report 19 | - DICOM Encapsulated PDF 20 | - and more to come 21 | 22 | :::{note} 23 | - Starting with release v0.6, the core modules are dependent on the Python SDK of [Nvidia Holoscan](https://docs.nvidia.com/holoscan-sdk/index.html), for its enterprise grade optimized libraries for data processing and AI, and core microservices to run surgical video, ultrasound, medical imaging, and other applications anywhere, from embedded to edge to cloud. A list of its modules are directly exposed through this SDK's namespace, `monai.deploy`. Domain specific operators from previous releases, e.g. DICOM parsing and writing, remain naive to this App SDK, and have been updated to be compatible with the `holoscan` based core modules. 24 | - The software and the imaging AI results generated are for research use only, and per applicable laws and regulations, are not for clinical use. 25 | - The App SDK, and specifically the DICOM instance writers, rely upon the underlying operating system to provide accurate and consistent time, and have no direct control over how the OS performs time synchronization, e.g. NTP on Ubuntu. It would be incumbent on the developer to appropriately use the available system time service and reflect the correct time in those objects properly. Additionally, the DICOM instance generated by the App SDK built-in classes set the [Timezone Offset From UTC](https://dicom.nema.org/medical/dicom/2020b/output/chtml/part03/sect_C.12.5.html) with the underlying operating system's timezone setting. 26 | ::: -------------------------------------------------------------------------------- /docs/source/introduction/roadmap.md: -------------------------------------------------------------------------------- 1 | # Roadmap 2 | 3 | The first versions of the MONAI Deploy App SDK offer a core framework to build & package healthcare AI apps so that they can be deployed to a production environment. 4 | 5 | We are currently in the process of refining the roadmap for the product based on the community’s input, though it is clear that on the roadmap are more built-in DICOM parsing and DICOM OID generation capabilities to better support [IHE AIR profiles](https://www.ihe.net/uploadedFiles/Documents/Radiology/IHE_RAD_Suppl_AIR_Rev1-2_TI_2022-07-06.pdf), as well as serving model network in a separate process using [Triton](https://developer.nvidia.com/triton-inference-server) and potentially utilizing [Nvidia Inference Microservices](https://www.nvidia.com/en-us/ai/). 6 | -------------------------------------------------------------------------------- /docs/source/modules/core.md: -------------------------------------------------------------------------------- 1 | # Core 2 | 3 | ```{eval-rst} 4 | .. automodule:: monai.deploy.core 5 | :noindex: 6 | ``` 7 | -------------------------------------------------------------------------------- /docs/source/modules/datastores.md: -------------------------------------------------------------------------------- 1 | # Datastores 2 | 3 | ```{eval-rst} 4 | .. automodule:: monai.deploy.core.datastores 5 | :noindex: 6 | ``` 7 | -------------------------------------------------------------------------------- /docs/source/modules/domain_objects.md: -------------------------------------------------------------------------------- 1 | # Domain objects 2 | 3 | ```{eval-rst} 4 | .. automodule:: monai.deploy.core.domain 5 | :noindex: 6 | ``` 7 | -------------------------------------------------------------------------------- /docs/source/modules/executors.md: -------------------------------------------------------------------------------- 1 | # Executors 2 | 3 | Please see Holoscan SDK Python API for classes that are in this module. 4 | 5 | ```{eval-rst} 6 | .. automodule:: monai.deploy.core.executors 7 | :noindex: 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/source/modules/graphs.md: -------------------------------------------------------------------------------- 1 | # Graphs 2 | 3 | Please see Holoscan SDK Python API for classes that are in this module. 4 | 5 | ```{eval-rst} 6 | .. automodule:: monai.deploy.core.graphs 7 | :noindex: 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/source/modules/index.md: -------------------------------------------------------------------------------- 1 | # MODULES APIS 2 | 3 | ```{toctree} 4 | :glob: 5 | :maxdepth: 2 6 | 7 | core 8 | conditions 9 | domain_objects 10 | operators 11 | models 12 | executors 13 | graphs 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/source/modules/models.md: -------------------------------------------------------------------------------- 1 | # Models 2 | 3 | ```{eval-rst} 4 | .. automodule:: monai.deploy.core.models 5 | :noindex: 6 | ``` 7 | -------------------------------------------------------------------------------- /docs/source/modules/operators.md: -------------------------------------------------------------------------------- 1 | # Operators 2 | 3 | Please also see Holoscan SDK Python API for additional operators that are exposed in this module. 4 | 5 | ```{eval-rst} 6 | .. automodule:: monai.deploy.operators 7 | :noindex: 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/source/release_notes/index.md: -------------------------------------------------------------------------------- 1 | # Release Notes 2 | 3 | ```{toctree} 4 | :hidden: 5 | :maxdepth: 2 6 | 7 | ``` 8 | ## Version 3.0 9 | 10 | ```{toctree} 11 | :maxdepth: 1 12 | 13 | v3.0.0 14 | ``` 15 | ## Version 2.0 16 | 17 | ```{toctree} 18 | :maxdepth: 1 19 | 20 | v2.0.0 21 | ``` 22 | ## Version 1.0 23 | 24 | ```{toctree} 25 | :maxdepth: 1 26 | 27 | v1.0.0 28 | ``` 29 | ## Version 0.6 30 | 31 | ```{toctree} 32 | :maxdepth: 1 33 | 34 | v0.6.0 35 | ``` 36 | ## Version 0.5 37 | 38 | ```{toctree} 39 | :maxdepth: 1 40 | 41 | v0.5.1 42 | v0.5.0 43 | ``` 44 | ## Version 0.4 45 | 46 | ```{toctree} 47 | :maxdepth: 1 48 | 49 | v0.4.0 50 | ``` 51 | ## Version 0.3 52 | 53 | ```{toctree} 54 | :maxdepth: 1 55 | 56 | v0.3.0 57 | ``` 58 | 59 | ## Version 0.2 60 | 61 | ```{toctree} 62 | :maxdepth: 1 63 | 64 | v0.2.1 65 | v0.2.0 66 | ``` 67 | 68 | ## Version 0.1 69 | 70 | ```{toctree} 71 | :maxdepth: 1 72 | 73 | v0.1.0 74 | ``` 75 | -------------------------------------------------------------------------------- /docs/source/release_notes/v0.1.0.md: -------------------------------------------------------------------------------- 1 | # Version 0.1.0 (September 23, 2021) 2 | 3 | This is the first version of MONAI Deploy App SDK!🎉 4 | 5 | Please visit [GETTING STARTED](/getting_started/index) guide and follow tutorials. 6 | 7 | You can learn more about SDK usage through [DEVELOPING WITH SDK](/developing_with_sdk/index). 8 | 9 | Please let us know how you like it and what could be improved by [submitting an issue](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/new/choose) or [asking questions](https://github.com/Project-MONAI/monai-deploy-app-sdk/discussions)😀 10 | -------------------------------------------------------------------------------- /docs/source/release_notes/v0.2.0.md: -------------------------------------------------------------------------------- 1 | # Version 0.2.0 (November 23, 2021) 2 | 3 | This is a new and enhanced version of MONAI Deploy App SDK, just in time for Thanksgiving and RSNA 2021!🎉 4 | 5 | Please visit [GETTING STARTED](/getting_started/index) guide and follow tutorials. 6 | 7 | You can learn more about SDK usage through [DEVELOPING WITH SDK](/developing_with_sdk/index). 8 | 9 | Please let us know how you like it and what could be improved by [submitting an issue](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/new/choose) or [asking questions](https://github.com/Project-MONAI/monai-deploy-app-sdk/discussions)😀 10 | 11 | ## What's new in this version 0.2.0 12 | ### Series Selection Operator 13 | This is to support the use case where whole DICOM studies are used as input to an AI inference application even though only specific series are applicable. 14 | 15 | The selection rules are defined in JSON, allowing multiple selections, each with a set of matching conditions. The rules processing engine is implemented in the `DICOMSeriesSelectorOperator`, which itself is regarded as a base class with a default implementation. More advanced rules and processing engines can be implemented in the derived classes. 16 | 17 | Multiple instances of the series selection operators, each having its own rules, can be chained in a MONAI Deploy application. In part this is made possible by the new App SDK Domain classes which encapsulate the selected series in a DICOM study, and are used as the output of each series selection operator. 18 | 19 | ### DICOM Comprehensive Structured Report Writer 20 | This is introduced to support generating DICOM SR SOP instances for AI classification results, and as such, the DICOM SR writer is limited to supporting textual results only. 21 | 22 | The DICOM SR writer is implemented in `DICOMTextSRWriterOperator`, it 23 | - loads the AI result from a in-memory object as well as from a file path, with the in-memory object taking precedence 24 | - copies applicable DICOM tags from the original DICOM series used as input for the inference application, as well as generating tags anew when there is no DICOM series provided. 25 | - supports assigning DICOM tags via a dictionary with DICOM keywords and their respective values, so that an application can customize the tags in the DICOM SR instance 26 | - provides classes for an application to encapsulate the AI model information as well as DICOM equipment information, per [IHE Radiology Technical Framework Supplement AI Results (AIR)](https://www.ihe.net/uploadedFiles/Documents/Radiology/IHE_RAD_Suppl_AIR.pdf) 27 | 28 | ### Updated example applications 29 | - [The AI Spleen Segmentation](https://github.com/Project-MONAI/monai-deploy-app-sdk/tree/main/examples/apps/ai_spleen_seg_app) application updated to demonstrate the use of series selection rules 30 | - [The MedNIST Classifier application](https://github.com/Project-MONAI/monai-deploy-app-sdk/tree/main/examples/apps/mednist_classifier_monaideploy) updated to demonstrate the use of DCIOM SR writing (without initial DICOM input) 31 | - Updated are the main functions of the built-in [operators](https://github.com/Project-MONAI/monai-deploy-app-sdk/tree/main/monai/deploy/operators), which serve as examples on how to parse the output objects 32 | - Updated also are [Jupyter notebook tutorials](https://github.com/Project-MONAI/monai-deploy-app-sdk/tree/main/notebooks/tutorials) 33 | - Multiple [issues](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues?q=is%3Aissue+is%3Aclosed) were fixed and closed -------------------------------------------------------------------------------- /docs/source/release_notes/v0.2.1.md: -------------------------------------------------------------------------------- 1 | # Version 0.2.1 (January 25, 2022) 2 | 3 | This is a patch release of [v0.2](https://docs.monai.io/projects/monai-deploy-app-sdk/en/latest/release_notes/v0.2.0.html#). 4 | 5 | Please visit [GETTING STARTED](/getting_started/index) guide and follow tutorials. 6 | 7 | You can learn more about SDK usage through [DEVELOPING WITH SDK](/developing_with_sdk/index). 8 | 9 | Please let us know how you like it and what could be improved by [submitting an issue](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/new/choose) or [asking questions](https://github.com/Project-MONAI/monai-deploy-app-sdk/discussions)😀 10 | 11 | ## What's new 12 | 13 | As per MONAI Core's [Python 3.6 drop](https://github.com/Project-MONAI/MONAI/pull/3536), drop the support for Python 3.6 from MONAI Deploy App SDK. 14 | 15 | - Drop Python 3.6 support [#248](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/248) by [@gigony](https://github.com/gigony) 16 | 17 | ## What's fixed/updated 18 | 19 | - Fixed minor dependencies for fresh deployment [#208](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/208) by [@vikashg](https://github.com/vikashg) 20 | - Fix minor typo in chapter 4 notebook [#209](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/209) by [@KavinKrishnan](https://github.com/KavinKrishnan) 21 | - Bump numpy >= 1.20 to avoid MKL error in conda env, and add --upgrade for pip install app sdk [#211](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/211) by [@MMelQin](https://github.com/MMelQin) 22 | - Update notebooks with cloning repo and building MIS container [#214](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/214) by [@KavinKrishnan](https://github.com/KavinKrishnan) 23 | - Update notebooks with cloning repo and building MIS container [#215](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/215) by [@KavinKrishnan](https://github.com/KavinKrishnan) 24 | - Change the model name in the Spleen seg example dataset to model.ts [#222](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/222) by [@MMelQin](https://github.com/MMelQin) 25 | - Remove developer names/aliases from notebooks and documentation [#225](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/225) by [@KavinKrishnan](https://github.com/KavinKrishnan) 26 | - Fixed empty documentation on docs.monai [#233](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/233) by [@vikashg](https://github.com/vikashg) 27 | - Handle exception case with missing DICOM Rescale Intercept and Slope attributes [#236](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/236) by [@MMelQin](https://github.com/MMelQin) 28 | - Fix IPython detection routine [#237](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/237) by [@gigony](https://github.com/gigony) 29 | - Use Python 3.7 for JupyterLab [#241](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/241) by [@gigony](https://github.com/gigony) 30 | - Update gdown command and missing package [#246](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/246) by [@gigony](https://github.com/gigony) 31 | - Do not upgrade packages when packaging [#247](https://github.com/Project-MONAI/monai-deploy-app-sdk/pull/247) by [@gigony](https://github.com/gigony) 32 | -------------------------------------------------------------------------------- /docs/source/release_notes/v0.4.0.md: -------------------------------------------------------------------------------- 1 | # Version 0.4.0 2 | 3 | 4 | 5 | ## What's new in 0.4.0 6 | - New operator to automate inference with the newly introduced [MONAI Bundle](https://docs.monai.io/en/stable/whatsnew_0_9.html) 7 | 8 | ### MONAI Bundle Inference Operator 9 | 10 | The new operator, `MONAI Bundle Inference Operator`, is intended to automate the inference with a MONAI Bundle in TorchScript with the following functionalities: 11 | - Parse the model metadata and extra configuration data in the TorchScript file 12 | - Instantiate MONAI transforms and inferer objects per bundle configuration data 13 | - Convert input/output of the operator to and from model network input 14 | - Support named model and can be used in a multi-model application 15 | 16 | The example [spleen segmentation application](https://github.com/Project-MONAI/monai-deploy-app-sdk/tree/main/examples/apps/ai_spleen_seg_app) was accordingly updated to demonstrate the use of this new operator with the newly published [Spleen CT Segmentation Bundle](https://github.com/Project-MONAI/model-zoo/tree/dev/models/spleen_ct_segmentation). 17 | 18 | More details are in the [tutorial](https://github.com/Project-MONAI/monai-deploy-app-sdk/blob/main/notebooks/tutorials/06_monai_bundle_app.ipynb). 19 | 20 | ## What's fixed/updated 21 | 22 | - [[FEA] A generic operator to automate inference execution with a MONAI Bundle](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/286) 23 | - [[FEA] Integrating Model Zoo and MMAR](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/213) 24 | - [[FEA] Multi-model support in an application built with MONAI Deploy App SDK](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/244) 25 | - [[DOC] Missing python dependencies for the segmentation app](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/299) and the [duplicate](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/305) 26 | - [mednist_app:latest -- No module named 'nibabel'](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/302) 27 | - [[DOC] Series Selector dictionary](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/300) 28 | 29 | ## Additional information 30 | Please visit [GETTING STARTED](/getting_started/index) guide and follow the tutorials. 31 | 32 | You can learn more about SDK usage through [DEVELOPING WITH SDK](/developing_with_sdk/index). 33 | 34 | Please let us know how you like it and what could be improved by [submitting an issue](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/new/choose) or [asking questions](https://github.com/Project-MONAI/monai-deploy-app-sdk/discussions) -------------------------------------------------------------------------------- /docs/source/release_notes/v0.5.0.md: -------------------------------------------------------------------------------- 1 | # Version 0.5.0 2 | 3 | ## What's new in 0.5.0 4 | - App SDK is now compatible with MONAI v0.9.1 and later 5 | - DICOM Encapsulated PDF Writer. This built-in operator provides a simple and easy way to encapsulate PDF contents in a DICOM instance with or without referenced original DICOM instance(s) 6 | - DICOM Segmentation Writer with highdicom back end. This improves the description of segments with proper DICOM coding sequence(s) 7 | - Generated DICOM instances as AI evidence now have the attribute (0008,0201) Timezone Offset From UTC, in addition to the DICOM date and time which are set with values from the underlying operating system. The OS is expected to be synchronized with a known good timing source and have the correct timezone setting 8 | - Generated DICOM instance file names are now based on the SOP instance UID 9 | - Support DICOM instance level attribute matching in the DICOM Series Selection Operator 10 | - Operators and example applications are verified to be re-runable without needing to reinitialize the application object or re-load the AI model network. This will allow a main function or an external script to instantiate the application object once and use it to process multiple discrete inputs, either in a batch processing mode or in a long running service 11 | - Tutorials, in Jupyter notebooks, are re-organized and updated 12 | - Reference added for MONAI Deploy Express for hosting MAPs in development environments 13 | - Removed is the reference to the deprecated MONAI Inference Service 14 | 15 | ## What's fixed/updated 16 | 17 | Please see the closed issues on Github and the closed pull requests on Github. 18 | 19 | ## Known Issues 20 | The example MedNIST Classifier application works but its MAP container image may fail to run. 21 | 22 | ## Additional information 23 | Please visit [GETTING STARTED](/getting_started/index) guide and follow the tutorials. 24 | 25 | You can learn more about SDK usage through [DEVELOPING WITH SDK](/developing_with_sdk/index). 26 | 27 | Please let us know how you like it and what could be improved by [submitting an issue](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/new/choose) or [asking questions](https://github.com/Project-MONAI/monai-deploy-app-sdk/discussions) -------------------------------------------------------------------------------- /docs/source/release_notes/v3.0.0.md: -------------------------------------------------------------------------------- 1 | # Version 3.0.0 (April 22nd, 2025) 2 | 3 | ## What's new in 3.0.0 4 | 5 | - This version of the App SDK is based on the newly released [Holoscan SDK v3](https://pypi.org/project/holoscan/), and is expected to be so with future minor releases of Holoscan SDK v3. 6 | 7 | - Starting with version 3.0.0, [Holoscan SDK](https://pypi.org/project/holoscan/) and [Holoscan CLI](https://pypi.org/project/holoscan-cli/) are released in separate packages, and as such, this version of the MONAI Deploy App SDK has both as dependencies. As of now, version 3 of both packages are compatible. 8 | 9 | - Remote inference on [Triton Inference Server](https://github.com/triton-inference-server) is now supported. Effort was made to make it user-friendly so existing example applications can be easily converted to use this feature by simply providing the network location of the server as well as the [Triton model configuration file](https://github.com/triton-inference-server/server/blob/main/docs/user_guide/model_configuration.md) sans the actual model files. [An example application](https://github.com/Project-MONAI/monai-deploy-app-sdk/tree/main/examples/apps/ai_remote_infer_app) has been provided to demonstrate such use case. 10 | 11 | ### Key changes 12 | 13 | - [Cincinnati Children's Hospital Medical Cente](https://www.cincinnatichildrens.org/) researchers, @[Bryan](https://github.com/bluna301) @[Will](https://github.com/WillButAgain) and Elan, contributed numerous enhancements from experience developing and deploying MONAI based AI applications in clinical environments, to name but a few 14 | 15 | - Enhanced the DICOM data loader to handle multi-phase DICOM series where multiple acquisitions exist and some DICOM SOP instances have the same image pospositiontion patient. 16 | 17 | - Enahnced the DICOM series to volume operator to better handle the data types of the converted volume image for improved efficiency and memory usage. 18 | 19 | - Enhanced the DICOM Segmentation operator to populate DICOM tags with AI model information which are consistent with other DICOM writers in the SDK. 20 | 21 | 22 | Please also see the closed issues on Github and the closed pull requests on Github. 23 | 24 | ## Additional information 25 | Please visit [GETTING STARTED](/getting_started/index) guide and follow the tutorials. 26 | 27 | You can learn more about SDK usage through [DEVELOPING WITH SDK](/developing_with_sdk/index). 28 | 29 | Please let us know how you like it and what could be improved by [submitting an issue](https://github.com/Project-MONAI/monai-deploy-app-sdk/issues/new/choose) or [asking questions](https://github.com/Project-MONAI/monai-deploy-app-sdk/discussions) -------------------------------------------------------------------------------- /docs/source/spelling_wordlist.txt: -------------------------------------------------------------------------------- 1 | builtin 2 | builtins 3 | classmethod 4 | staticmethod 5 | classmethods 6 | staticmethods 7 | args 8 | kwargs 9 | callstack 10 | Changelog 11 | Indices 12 | -------------------------------------------------------------------------------- /examples/apps/ai_livertumor_seg_app/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import os 13 | import sys 14 | 15 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 16 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 17 | sys.path.insert(0, _current_dir) 18 | del _current_dir 19 | -------------------------------------------------------------------------------- /examples/apps/ai_livertumor_seg_app/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import logging 13 | 14 | from app import AILiverTumorApp 15 | 16 | if __name__ == "__main__": 17 | logging.info(f"Begin {__name__}") 18 | AILiverTumorApp().run() 19 | logging.info(f"End {__name__}") 20 | -------------------------------------------------------------------------------- /examples/apps/ai_multi_ai_app/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 5 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 6 | sys.path.insert(0, _current_dir) 7 | del _current_dir 8 | -------------------------------------------------------------------------------- /examples/apps/ai_multi_ai_app/__main__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app import App 4 | 5 | if __name__ == "__main__": 6 | logging.info(f"Begin {__name__}") 7 | App().run() 8 | logging.info(f"End {__name__}") 9 | -------------------------------------------------------------------------------- /examples/apps/ai_multi_ai_app/app.yaml: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | # SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | --- 17 | application: 18 | title: MONAI Deploy App Package - Multi Model App 19 | version: 1.0 20 | inputFormats: ["file"] 21 | outputFormats: ["file"] 22 | 23 | resources: 24 | cpu: 1 25 | gpu: 1 26 | memory: 1Gi 27 | gpuMemory: 10Gi 28 | -------------------------------------------------------------------------------- /examples/apps/ai_multi_ai_app/readme.md: -------------------------------------------------------------------------------- 1 | # About the Multi-Model/Multi-AI Example 2 | 3 | This example demonstrates how to create a multi-model/multi-AI application. 4 | 5 | ## The important steps 6 | - Place the model TorchScripts in a defined folder structure, see below for details 7 | - Pass the model name to the inference operator instance in the app 8 | - Connect the input to and output from the inference operators, as required by the app 9 | 10 | ## Required model folder structure: 11 | - The model TorchScripts, be it MONAI Bundle compliant or not, must be placed in a parent folder, whose path is used as the path to the model(s) on app execution 12 | - Each TorchScript file needs to be in a sub-folder, whose name is the model name 13 | 14 | An example is shown below, where the `parent_foler` name can be the app's own choosing, and the sub-folder names become model names, `pancreas_ct_dints` and `spleen_model`, respectively. 15 | ``` 16 | 17 | ├── pancreas_ct_dints 18 | │ └── model.ts 19 | └── spleen_ct 20 | └── model.ts 21 | ``` 22 | 23 | ## Note: 24 | - The TorchScript files of MONAI Bundles can be downloaded from MONAI Model Zoo, at https://github.com/Project-MONAI/model-zoo/tree/dev/models 25 | - The input DICOM instances are from a DICOM Series of CT Abdomen study, similar to the ones used in the Spleen Segmentation example 26 | - This example is purely for technical demonstration, not for clinical use. -------------------------------------------------------------------------------- /examples/apps/ai_multi_ai_app/requirements.txt: -------------------------------------------------------------------------------- 1 | scikit-image>=0.17.2 2 | pydicom>=2.3.0 3 | highdicom>=0.18.2 4 | SimpleITK>=2.0.0 5 | Pillow>=8.0.0 6 | numpy-stl>=2.12.0 7 | trimesh>=3.8.11 8 | nibabel>=3.2.1 9 | torch>=1.12.0 10 | monai>=1.0.0 -------------------------------------------------------------------------------- /examples/apps/ai_pancreas_seg_app/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import os 13 | import sys 14 | 15 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 16 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 17 | sys.path.insert(0, _current_dir) 18 | del _current_dir 19 | -------------------------------------------------------------------------------- /examples/apps/ai_pancreas_seg_app/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import logging 13 | 14 | from app import AIPancreasSegApp 15 | 16 | if __name__ == "__main__": 17 | logging.info(f"Begin {__name__}") 18 | AIPancreasSegApp().run() 19 | logging.info(f"End {__name__}") 20 | -------------------------------------------------------------------------------- /examples/apps/ai_remote_infer_app/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from app import AIRemoteInferSpleenSegApp 13 | 14 | if __name__ == "__main__": 15 | AIRemoteInferSpleenSegApp().run() 16 | -------------------------------------------------------------------------------- /examples/apps/ai_remote_infer_app/env_settings_example.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | #!/bin/bash 13 | export HOLOSCAN_INPUT_PATH="inputs/spleen_ct_tcia" 14 | export HOLOSCAN_MODEL_PATH="examples/apps/ai_remote_infer_app/models_client_side" 15 | export HOLOSCAN_OUTPUT_PATH="output_spleen" 16 | export HOLOSCAN_LOG_LEVEL=DEBUG # TRACE can be used for verbose low-level logging 17 | export TRITON_SERVER_NETLOC="localhost:8000" # Triton server network location, host:port 18 | -------------------------------------------------------------------------------- /examples/apps/ai_remote_infer_app/models_client_side/spleen_ct/config.pbtxt: -------------------------------------------------------------------------------- 1 | platform: "pytorch_libtorch" 2 | 3 | max_batch_size: 16 # The maximum batch size. 0 for no batching with full shape in dims 4 | 5 | default_model_filename: "model_spleen_ct_segmentation_v1.ts" # The name of the TorchScript model file 6 | 7 | input [ 8 | { 9 | name: "INPUT_0" # The name of the input tensor (or should match the input tensor name in your model if used) 10 | data_type: TYPE_FP32 # Data type is FP32 11 | dims: [ 1, 96, 96, 96 ] # Input dimensions: [channels, width, height, depth], to be stacked as a batch 12 | } 13 | ] 14 | 15 | output [ 16 | { 17 | name: "OUTPUT_0" # The name of the output tensor (match this with your TorchScript model's output name) 18 | data_type: TYPE_FP32 # Output is FP32 19 | dims: [ 2, 96, 96, 96 ] # Output dimensions: [channels, width, height, depth], stacked to match input batch size 20 | } 21 | ] 22 | 23 | version_policy: { latest: { num_versions: 1}} # Only serve the latest version, which is the default 24 | 25 | instance_group [ 26 | { 27 | kind: KIND_GPU # Specify the hardware type (GPU in this case) 28 | count: 1 # Number of instances created for each GPU listed in 'gpus' (adjust based on your resources) 29 | } 30 | ] 31 | 32 | dynamic_batching { 33 | preferred_batch_size: [ 4, 8, 16 ] # Preferred batch size(s) for dynamic batching. Matching the max_batch_size for sync calls. 34 | max_queue_delay_microseconds: 1000 # Max delay before processing the batch. 35 | } 36 | 37 | # The initial calls to a loaded TorchScript model take extremely long. 38 | # Due to this longer model warmup issue, Triton allows execution of models without these optimizations. 39 | parameters: { 40 | key: "DISABLE_OPTIMIZED_EXECUTION" 41 | value: { 42 | string_value: "true" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/apps/ai_spleen_seg_app/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import os 13 | import sys 14 | 15 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 16 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 17 | sys.path.insert(0, _current_dir) 18 | del _current_dir 19 | -------------------------------------------------------------------------------- /examples/apps/ai_spleen_seg_app/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import logging 13 | 14 | from app import AISpleenSegApp 15 | 16 | if __name__ == "__main__": 17 | logging.info(f"Begin {__name__}") 18 | AISpleenSegApp().run() 19 | logging.info(f"End {__name__}") 20 | -------------------------------------------------------------------------------- /examples/apps/ai_spleen_seg_app/app.yaml: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | # SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | --- 17 | application: 18 | title: MONAI Deploy App Package - Spleen Seg Inference 19 | version: 1.0 20 | inputFormats: ["file"] 21 | outputFormats: ["file"] 22 | 23 | resources: 24 | cpu: 1 25 | gpu: 1 26 | memory: 1Gi 27 | gpuMemory: 7Gi 28 | -------------------------------------------------------------------------------- /examples/apps/ai_spleen_seg_app/requirements.txt: -------------------------------------------------------------------------------- 1 | scikit-image>=0.17.2 2 | pydicom>=2.3.0 3 | highdicom>=0.18.2 4 | SimpleITK>=2.0.0 5 | Pillow>=8.0.0 6 | numpy-stl>=2.12.0 7 | trimesh>=3.8.11 8 | nibabel>=3.2.1 9 | torch>=1.12.0 10 | monai>=1.0.0 -------------------------------------------------------------------------------- /examples/apps/ai_unetr_seg_app/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 5 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 6 | sys.path.insert(0, _current_dir) 7 | del _current_dir 8 | -------------------------------------------------------------------------------- /examples/apps/ai_unetr_seg_app/__main__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app import AIUnetrSegApp 4 | 5 | if __name__ == "__main__": 6 | logging.info(f"Begin {__name__}") 7 | AIUnetrSegApp().run() 8 | logging.info(f"End {__name__}") 9 | -------------------------------------------------------------------------------- /examples/apps/breast_density_classifier_app/README.md: -------------------------------------------------------------------------------- 1 | ## A MONAI Application Package to deploy breast density classification algorithm 2 | This MAP is based on the Breast Density Model in MONAI [Model-Zoo](https://github.com/Project-MONAI/model-zoo). This model is developed at the Center for Augmented Intelligence in Imaging at the Mayo Clinic, Florida. 3 | For any questions, feel free to contact Vikash Gupta (gupta.vikash@mayo.edu) 4 | Sample data and a torchscript model can be downloaded from https://drive.google.com/drive/folders/1Dryozl2MwNunpsGaFPVoaKBLkNbVM3Hu?usp=sharing 5 | 6 | 7 | ## Run the application code with Python interpreter 8 | ``` 9 | python app.py -i -o -m 10 | ``` 11 | 12 | ## Package the application as a MONAI Application Package (container image) 13 | In order to build the MONAI App Package, go a level up and execute the following command. 14 | ``` 15 | monai-deploy package breast_density_classification_app -m -c breast_density_classifer_app/app.yaml --tag breast_density:0.1.0 --platform x64-workstation -l DEBUG 16 | ``` 17 | 18 | ## Run the MONAI Application Package using MONAI Deploy CLI 19 | ``` 20 | monai-deploy run breast_density-x64-workstation-dgpu-linux-amd64:0.1.0 -i -o 21 | ``` 22 | 23 | Once the container exits successfully, check the results in the output directory. There should be a newly created DICOM instance file and a `output.json` file containing the classification results. -------------------------------------------------------------------------------- /examples/apps/breast_density_classifier_app/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 5 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 6 | sys.path.insert(0, _current_dir) 7 | del _current_dir 8 | -------------------------------------------------------------------------------- /examples/apps/breast_density_classifier_app/__main__.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from app import BreastClassificationApp 4 | 5 | if __name__ == "__main__": 6 | logging.info(f"Begin {__name__}") 7 | BreastClassificationApp().run() 8 | logging.info(f"End {__name__}") 9 | -------------------------------------------------------------------------------- /examples/apps/breast_density_classifier_app/app.yaml: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | # SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | --- 17 | application: 18 | title: MONAI Deploy App Package - Spleen Seg Inference 19 | version: 1.0 20 | inputFormats: ["file"] 21 | outputFormats: ["file"] 22 | 23 | resources: 24 | cpu: 1 25 | gpu: 1 26 | memory: 1Gi 27 | gpuMemory: 2Gi 28 | -------------------------------------------------------------------------------- /examples/apps/breast_density_classifier_app/requirements.txt: -------------------------------------------------------------------------------- 1 | highdicom>=0.18.2 2 | monai>=1.2.0 3 | pydicom>=2.3.0 4 | torch>=1.12.0 -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/README.md: -------------------------------------------------------------------------------- 1 | # MONAI Application Package (MAP) for CCHMC Pediatric Abdominal CT Segmentation MONAI Bundle 2 | 3 | This MAP is based on the [CCHMC Pediatric Abdominal CT Segmentation MONAI Bundle](https://github.com/cchmc-dll/pediatric_abdominal_segmentation_bundle/tree/original). This model was developed at Cincinnati Children's Hospital Medical Center by the Department of Radiology. 4 | 5 | The PyTorch and TorchScript DynUNet models can be downloaded from the [MONAI Bundle Repository](https://github.com/cchmc-dll/pediatric_abdominal_segmentation_bundle/tree/original/models). 6 | 7 | For questions, please feel free to contact Elan Somasundaram (Elanchezhian.Somasundaram@cchmc.org) and Bryan Luna (Bryan.Luna@cchmc.org). 8 | 9 | ## Unique Features 10 | 11 | Some unique features of this MAP pipeline include: 12 | - **Custom Inference Operator:** custom `AbdomenSegOperator` enables either PyTorch or TorchScript model loading 13 | - **DICOM Secondary Capture Output:** custom `DICOMSecondaryCaptureWriterOperator` writes a DICOM SC with organ contours 14 | - **Output Filtering:** model produces Liver-Spleen-Pancreas segmentations, but seg visibility in the outputs (DICOM SEG, SC, SR) can be controlled in `app.py` 15 | - **MONAI Deploy Express MongoDB Write:** custom operators (`MongoDBEntryCreatorOperator` and `MongoDBWriterOperator`) allow for writing to the MongoDB database associated with MONAI Deploy Express 16 | 17 | ## Scripts 18 | Several scripts have been compiled that quickly execute useful actions (such as running the app code locally with Python interpreter, MAP packaging, MAP execution, etc.). Some scripts require the input of command line arguments; review the `scripts` folder for more details. 19 | 20 | ## Notes 21 | The DICOM Series selection criteria has been customized based on the model's training and CCHMC use cases. By default, Axial CT series with Slice Thickness between 3.0 - 5.0 mm (inclusive) will be selected for. 22 | 23 | If MongoDB writing is not desired, please comment out the relevant sections in `app.py` and the `AbdomenSegOperator`. 24 | 25 | To execute the pipeline with MongoDB writing enabled, it is best to create a `.env` file that the `MongoDBWriterOperator` can load in. Below is an example `.env` file that follows the format outlined in this operator; note that these values are the default variable values as defined in the [.env](https://github.com/Project-MONAI/monai-deploy/blob/main/deploy/monai-deploy-express/.env) and [docker-compose.yaml](https://github.com/Project-MONAI/monai-deploy/blob/main/deploy/monai-deploy-express/docker-compose.yml) files of v0.6.0 of MONAI Deploy Express: 26 | 27 | ```dotenv 28 | MONGODB_USERNAME=root 29 | MONGODB_PASSWORD=rootpassword 30 | MONGODB_PORT=27017 31 | MONGODB_IP_DOCKER=172.17.0.1 # default Docker bridge network IP 32 | ``` 33 | 34 | Prior to packaging into a MAP, the MongoDB credentials should be hardcoded into the `MongoDBWriterOperator`. 35 | 36 | The MONAI Deploy Express MongoDB Docker container (`mdl-mongodb`) needs to be connected to the Docker bridge network in order for the MongoDB write to be successful. Executing the following command in a MONAI Deploy Express terminal will establish this connection: 37 | 38 | ```bash 39 | docker network connect bridge mdl-mongodb 40 | ``` 41 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # __init__.py is used to initialize a Python package 13 | # ensures that the directory __init__.py resides in is included at the start of the sys.path 14 | # this is useful when you want to import modules from this directory, even if it’s not the 15 | # directory where your Python script is running. 16 | 17 | # give access to operating system and Python interpreter 18 | import os 19 | import sys 20 | 21 | # grab absolute path of directory containing __init__.py 22 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 23 | 24 | # if sys.path is not the same as the directory containing the __init__.py file 25 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 26 | # insert directory containing __init__.py file at the beginning of sys.path 27 | sys.path.insert(0, _current_dir) 28 | # delete variable 29 | del _current_dir 30 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # __main__.py is needed for MONAI Application Packager to detect the main app code (app.py) when 13 | # app.py is executed in the application folder path 14 | # e.g., python my_app 15 | 16 | import logging 17 | 18 | # import AIAbdomenSegApp class from app.py 19 | from app import AIAbdomenSegApp 20 | 21 | # if __main__.py is being run directly 22 | if __name__ == "__main__": 23 | logging.info(f"Begin {__name__}") 24 | # create and run an instance of AIAbdomenSegApp 25 | AIAbdomenSegApp().run() 26 | logging.info(f"End {__name__}") 27 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/app.yaml: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | --- 12 | 13 | # app.yaml is a configuration file that specifies MAP settings 14 | # used by MONAI App SDK to understand how to run our app in a MAP and what resources it needs 15 | 16 | # specifies high-level information about our app 17 | application: 18 | title: MONAI Deploy App Package - CCHMC Pediatric CT Abdominal Segmentation 19 | version: 0.0.1 20 | inputFormats: ["file"] 21 | outputFormats: ["file"] 22 | 23 | # specifies the resources our app needs to run 24 | # per MONAI docs (https://docs.monai.io/projects/monai-deploy-app-sdk/en/latest/developing_with_sdk/executing_packaged_app_locally.html) 25 | # MAR does not validate all of the resource requirements embedded in the MAP to ensure they are met in host system 26 | # e.g, MAR will throw an error if gpu requirement is not met on host system; however, gpuMemory parameter doesn't appear to be validated 27 | resources: 28 | cpu: 1 29 | gpu: 1 30 | memory: 1Gi 31 | # during MAP execution, for an input DICOM Series of 204 instances, GPU usage peaks at just under 8900 MiB ~= 9.3 GB ~= 8.7 Gi 32 | gpuMemory: 9Gi 33 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/requirements.txt: -------------------------------------------------------------------------------- 1 | monai>=1.3.0 2 | torch>=1.12.0 3 | pytorch-ignite>=0.4.9 4 | fire>=0.4.0 5 | numpy>=1.22.2 6 | nibabel>=4.0.1 7 | # pydicom v3.0.0 removed pydicom._storage_sopclass_uids; don't meet or exceed this version 8 | pydicom>=2.3.0,<3.0.0 9 | highdicom>=0.18.2 10 | itk>=5.3.0 11 | SimpleITK>=2.0.0 12 | scikit-image>=0.17.2 13 | Pillow>=8.0.0 14 | numpy-stl>=2.12.0 15 | trimesh>=3.8.11 16 | matplotlib>=3.7.2 17 | setuptools>=59.5.0 # for pkg_resources 18 | python-dotenv>=1.0.1 19 | 20 | # pymongo for MongoDB writing 21 | pymongo>=4.10.1 22 | 23 | # pytz for MongoDB Timestamp 24 | pytz>=2024.1 25 | 26 | # MONAI Deploy App SDK package installation 27 | monai-deploy-app-sdk 28 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/scripts/map_build.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # build a MAP 13 | 14 | # check if the correct number of arguments are provided 15 | if [ "$#" -ne 3 ]; then 16 | echo "Please provide all arguments. Usage: $0 " 17 | exit 1 18 | fi 19 | 20 | # assign command-line arguments to variables 21 | tag_prefix=$1 22 | image_version=$2 23 | sdk_version=$3 24 | 25 | # load in environment variables 26 | source .env 27 | 28 | # build MAP 29 | monai-deploy package cchmc_ped_abd_ct_seg_app -m $HOLOSCAN_MODEL_PATH -c cchmc_ped_abd_ct_seg_app/app.yaml -t ${tag_prefix}:${image_version} --platform x64-workstation --sdk-version ${sdk_version} -l DEBUG 30 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/scripts/map_extract.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # display and extract MAP contents 13 | 14 | # check if the correct number of arguments are provided 15 | if [ "$#" -ne 2 ]; then 16 | echo "Please provide all arguments. Usage: $0 " 17 | exit 1 18 | fi 19 | 20 | # assign command-line arguments to variables 21 | tag_prefix=$1 22 | image_version=$2 23 | 24 | # display basic MAP manifests 25 | docker run --rm ${tag_prefix}-x64-workstation-dgpu-linux-amd64:${image_version} show 26 | 27 | # remove and subsequently create export folder 28 | rm -rf `pwd`/export && mkdir -p `pwd`/export 29 | 30 | # extract MAP contents 31 | docker run --rm -v `pwd`/export/:/var/run/holoscan/export/ ${tag_prefix}-x64-workstation-dgpu-linux-amd64:${image_version} extract 32 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/scripts/map_run.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # execute MAP locally with MAR 13 | 14 | # check if the correct number of arguments are provided 15 | if [ "$#" -ne 2 ]; then 16 | echo "Please provide all arguments. Usage: $0 " 17 | exit 1 18 | fi 19 | 20 | # assign command-line arguments to variables 21 | tag_prefix=$1 22 | image_version=$2 23 | 24 | # load in environment variables 25 | source .env 26 | 27 | # remove the output directory 28 | rm -rf "$HOLOSCAN_OUTPUT_PATH" 29 | 30 | # execute MAP locally via MAR 31 | monai-deploy run -i $HOLOSCAN_INPUT_PATH -o $HOLOSCAN_OUTPUT_PATH ${tag_prefix}-x64-workstation-dgpu-linux-amd64:${image_version} 32 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/scripts/map_run_interactive.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # run an interactive MAP container 13 | 14 | # check if the correct number of arguments are provided 15 | if [ "$#" -ne 2 ]; then 16 | echo "Please provide all arguments. Usage: $0 " 17 | exit 1 18 | fi 19 | 20 | # assign command-line arguments to variables 21 | tag_prefix=$1 22 | image_version=$2 23 | 24 | # load in environment variables 25 | source .env 26 | 27 | # remove the output directory 28 | rm -rf "$HOLOSCAN_OUTPUT_PATH" 29 | 30 | # execute MAP locally via MAR and start interactive container 31 | monai-deploy run -i $HOLOSCAN_INPUT_PATH -o $HOLOSCAN_OUTPUT_PATH ${tag_prefix}-x64-workstation-dgpu-linux-amd64:${image_version} --terminal 32 | 33 | # # start interactive MAP container without MAR 34 | # docker run -it --entrypoint /bin/bash ${tag_prefix}-x64-workstation-dgpu-linux-amd64:${image_version} 35 | 36 | # # see dependencies installed in MAP 37 | # pip freeze 38 | -------------------------------------------------------------------------------- /examples/apps/cchmc_ped_abd_ct_seg_app/scripts/model_run.sh: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # execute model bundle locally (pythonically) 13 | 14 | # load in environment variables 15 | source .env 16 | 17 | # remove the output directory 18 | rm -rf "$HOLOSCAN_OUTPUT_PATH" 19 | 20 | # execute model bundle locally (pythonically) 21 | python cchmc_ped_abd_ct_seg_app -i "$HOLOSCAN_INPUT_PATH" -o "$HOLOSCAN_OUTPUT_PATH" -m "$HOLOSCAN_MODEL_PATH" 22 | -------------------------------------------------------------------------------- /examples/apps/deploy_app_on_aarch64.md: -------------------------------------------------------------------------------- 1 | # MONAI Application Package for ARMv8 AArch64 on Linux 2 | 3 | This article describes how to containerize a MONAI Deploy application, as a **MONAI Application Package**, targeting ARMv8 AArch64 on Linux. 4 | 5 | Section [Packaging App](https://docs.monai.io/projects/monai-deploy-app-sdk/en/stable/developing_with_sdk/packaging_app.html) in the MONAI Deploy App SDK [Users Guide](https://docs.monai.io/projects/monai-deploy-app-sdk/en/stable/index.html) describes the general steps to package an application into a MAP. Building MAPs for AArch64 on Linux with discrete GPU can be done with this simple change of command line options, 6 | 7 | `--platform x64-workstation` replaced with 8 | 9 | `--platform igx-orin-devkit --platform-config dgpu` -------------------------------------------------------------------------------- /examples/apps/dicom_series_to_image_app/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import os 13 | import sys 14 | 15 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 16 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 17 | sys.path.insert(0, _current_dir) 18 | del _current_dir 19 | -------------------------------------------------------------------------------- /examples/apps/dicom_series_to_image_app/__main__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from app import App 13 | 14 | if __name__ == "__main__": 15 | App().run() 16 | -------------------------------------------------------------------------------- /examples/apps/dicom_series_to_image_app/app.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from pathlib import Path 13 | 14 | from monai.deploy.conditions import CountCondition 15 | from monai.deploy.core import AppContext, Application 16 | from monai.deploy.operators.dicom_data_loader_operator import DICOMDataLoaderOperator 17 | from monai.deploy.operators.dicom_series_selector_operator import DICOMSeriesSelectorOperator 18 | from monai.deploy.operators.dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator 19 | from monai.deploy.operators.png_converter_operator import PNGConverterOperator 20 | 21 | 22 | class App(Application): 23 | """This application loads DICOM files, converts them to 3D image, then to PNG files on disk. 24 | 25 | This showcases the MONAI Deploy application framework 26 | """ 27 | 28 | def compose(self): 29 | # Use command line options over environment variables to init context. 30 | app_context: AppContext = Application.init_app_context(self.argv) 31 | input_dcm_folder = Path(app_context.input_path) 32 | output_folder = Path(app_context.output_path) 33 | print(f"input_dcm_folder: {input_dcm_folder}") 34 | 35 | # Set the first operator to run only once by setting the count condition to 1 36 | study_loader_op = DICOMDataLoaderOperator( 37 | self, CountCondition(self, 1), input_folder=input_dcm_folder, name="dcm_loader" 38 | ) 39 | series_selector_op = DICOMSeriesSelectorOperator(self, name="series_selector") 40 | series_to_vol_op = DICOMSeriesToVolumeOperator(self, name="series_to_vol") 41 | png_converter_op = PNGConverterOperator(self, output_folder=output_folder, name="png_converter") 42 | 43 | # Create the execution DAG by linking operators' named output to named input. 44 | self.add_flow(study_loader_op, series_selector_op, {("dicom_study_list", "dicom_study_list")}) 45 | self.add_flow( 46 | series_selector_op, series_to_vol_op, {("study_selected_series_list", "study_selected_series_list")} 47 | ) 48 | self.add_flow(series_to_vol_op, png_converter_op, {("image", "image")}) 49 | 50 | 51 | if __name__ == "__main__": 52 | App().run() 53 | -------------------------------------------------------------------------------- /examples/apps/hugging_face_integration_app/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nvcr.io/nvidia/clara-holoscan/holoscan:v2.1.0-dgpu 2 | RUN pip install --upgrade pip 3 | RUN pip install monai-deploy-app-sdk 4 | RUN pip install transformers 5 | RUN pip install hub 6 | RUN pip install diffusers 7 | RUN pip install torch 8 | RUN pip install pydicom 9 | RUN pip install accelerate 10 | -------------------------------------------------------------------------------- /examples/apps/hugging_face_integration_app/debug.sh: -------------------------------------------------------------------------------- 1 | IMAGE=vikash112/monai-hugging:0.1.0 2 | docker build -t $IMAGE . 3 | 4 | monai_dir=/raid/Vikash/Tools/HUGGINGFACE/med_image_generation 5 | 6 | NV_GPU=1 nvidia-docker run -it --rm --shm-size=4g --ulimit memlock=-1 --ulimit stack=67108864 -v $monai_dir:/workspace/app/test $IMAGE /bin/bash 7 | -------------------------------------------------------------------------------- /examples/apps/hugging_face_integration_app/med_image_generation/app.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import logging 3 | 4 | import torch 5 | from diffusers import StableDiffusionPipeline 6 | 7 | from monai.deploy.core import Application 8 | 9 | 10 | class App(Application): 11 | name = "Diffusion Image App" 12 | description = "Simple application showing diffusion to generate Images" 13 | 14 | def compose(self): 15 | model_id = "Nihirc/Prompt2MedImage" 16 | device = "cuda" 17 | parser = argparse.ArgumentParser() 18 | parser.add_argument("--input_prompt", type=str, default="Generate a X-ray") 19 | parser.add_argument("--output", type=str, default="./out.jpg") 20 | args = parser.parse_args() 21 | 22 | input_prompt = args.input_prompt 23 | output_path = args.output 24 | print("Input Prompt: ", input_prompt) 25 | pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16) 26 | pipe = pipe.to(device) 27 | prompt = "Show me an X ray pevic fracture" 28 | image = pipe(prompt).images[0] 29 | image.save(output_path) 30 | 31 | 32 | if __name__ == "__main__": 33 | logging.info(f"Begin {__name__}") 34 | App().run() 35 | logging.info(f"End {__name__}") 36 | -------------------------------------------------------------------------------- /examples/apps/hugging_face_integration_app/med_image_generation/out.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/examples/apps/hugging_face_integration_app/med_image_generation/out.jpg -------------------------------------------------------------------------------- /examples/apps/hugging_face_integration_app/med_image_generation/run.sh: -------------------------------------------------------------------------------- 1 | 2 | python app.py --input_prompt "The patient had residual paralysis of the hand after poliomyelitis. It was necessary to stabilize the thumb with reference to the index finger. This was accomplished by placing a graft from the bone bank between the first and second metacarpals. The roentgenogram shows the complete healing of the graft one year later." --output out.jpg 3 | -------------------------------------------------------------------------------- /examples/apps/mednist_classifier_monaideploy/app.yaml: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | # SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | --- 17 | application: 18 | title: MONAI Deploy App Package - MedNIST Classifier App 19 | version: 1.0 20 | inputFormats: ["file"] 21 | outputFormats: ["file"] 22 | 23 | resources: 24 | cpu: 1 25 | gpu: 1 26 | memory: 1Gi 27 | gpuMemory: 1Gi 28 | -------------------------------------------------------------------------------- /examples/apps/mednist_classifier_monaideploy/requirements.txt: -------------------------------------------------------------------------------- 1 | monai>=1.2.0 2 | Pillow>=8.4.0 3 | pydicom>=2.3.0 4 | highdicom>=0.18.2 5 | SimpleITK>=2.0.0 6 | setuptools>=59.5.0 # for pkg_resources 7 | 8 | -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/__init__.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | _current_dir = os.path.abspath(os.path.dirname(__file__)) 5 | if sys.path and os.path.abspath(sys.path[0]) != _current_dir: 6 | sys.path.insert(0, _current_dir) 7 | del _current_dir 8 | -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/__main__.py: -------------------------------------------------------------------------------- 1 | from app import App 2 | 3 | if __name__ == "__main__": 4 | App().run() 5 | -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/app.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import logging 13 | from pathlib import Path 14 | 15 | from gaussian_operator import GaussianOperator 16 | from median_operator import MedianOperator 17 | from sobel_operator import SobelOperator 18 | 19 | from monai.deploy.conditions import CountCondition 20 | from monai.deploy.core import AppContext, Application 21 | 22 | 23 | # Decorator support is not available in this version of the SDK, to be re-introduced later 24 | # @resource(cpu=1) 25 | # @env(pip_packages=["scikit-image >= 0.17.2"]) 26 | class App(Application): 27 | """This is a very basic application. 28 | 29 | This showcases the MONAI Deploy application framework. 30 | """ 31 | 32 | # App's name. ('App') if not specified. 33 | name = "simple_imaging_app" 34 | # App's description. if not specified. 35 | description = "This is a very simple application." 36 | # App's version. or '0.0.0' if not specified. 37 | version = "0.1.0" 38 | 39 | def compose(self): 40 | """This application has three operators. 41 | 42 | Each operator has a single input and a single output port. 43 | Each operator performs some kind of image processing function. 44 | """ 45 | 46 | # Use Commandline options over environment variables to init context. 47 | app_context: AppContext = Application.init_app_context(self.argv) 48 | sample_data_path = Path(app_context.input_path) 49 | output_data_path = Path(app_context.output_path) 50 | logging.info(f"sample_data_path: {sample_data_path}") 51 | 52 | # Please note that the Application object, self, is passed as the first positional argument 53 | # and the others as kwargs. 54 | # Also note the CountCondition of 1 on the first operator, indicating to the application executor 55 | # to invoke this operator, hence the pipeline, only once. 56 | sobel_op = SobelOperator(self, CountCondition(self, 1), input_path=sample_data_path, name="sobel_op") 57 | median_op = MedianOperator(self, name="median_op") 58 | gaussian_op = GaussianOperator(self, output_folder=output_data_path, name="gaussian_op") 59 | self.add_flow( 60 | sobel_op, 61 | median_op, 62 | { 63 | ("out1", "in1"), 64 | }, 65 | ) 66 | self.add_flow( 67 | median_op, 68 | gaussian_op, 69 | { 70 | ( 71 | "out1", 72 | "in1", 73 | ) 74 | }, 75 | ) 76 | 77 | 78 | if __name__ == "__main__": 79 | logging.info(f"Begin {__name__}") 80 | App().run() 81 | logging.info(f"End {__name__}") 82 | -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/app.yaml: -------------------------------------------------------------------------------- 1 | %YAML 1.2 2 | # SPDX-FileCopyrightText: Copyright (c) 2022-2023 MONAI. All rights reserved. 3 | # SPDX-License-Identifier: Apache-2.0 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | --- 17 | application: 18 | title: MONAI Deploy App Package - Simple Imaging App 19 | version: 1.0 20 | inputFormats: ["file"] 21 | outputFormats: ["file"] 22 | 23 | resources: 24 | cpu: 1 25 | gpu: 1 26 | memory: 1Gi 27 | gpuMemory: 1Gi 28 | -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/final_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/examples/apps/simple_imaging_app/final_output.png -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/gaussian_operator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from pathlib import Path 13 | 14 | from monai.deploy.core import ConditionType, Fragment, Operator, OperatorSpec 15 | 16 | 17 | # If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other 18 | # operators and the application in packaging time. 19 | # @md.env(pip_packages=["scikit-image >= 0.17.2"]) 20 | class GaussianOperator(Operator): 21 | """This Operator implements a smoothening based on Gaussian. 22 | 23 | It has the following input and output: 24 | single input: 25 | an image array object 26 | single output: 27 | an image array object, without enforcing a downstream receiver 28 | 29 | Besides, this operator also saves the image file in the given output folder. 30 | """ 31 | 32 | DEFAULT_OUTPUT_FOLDER = Path.cwd() / "output" 33 | 34 | def __init__(self, fragment: Fragment, *args, output_folder: Path, **kwargs): 35 | """Create an instance to be part of the given application (fragment). 36 | 37 | Args: 38 | fragment (Fragment): The instance of Application class which is derived from Fragment 39 | output_folder (Path): The folder to save the output file. 40 | """ 41 | self.output_folder = output_folder if output_folder else GaussianOperator.DEFAULT_OUTPUT_FOLDER 42 | self.index = 0 43 | 44 | # If `self.sigma_default` is set here (e.g., `self.sigma_default = 0.2`), then 45 | # the default value by `param()` in `setup()` will be ignored. 46 | # (you can just call `spec.param("sigma_default")` in `setup()` to use the 47 | # default value) 48 | self.sigma_default = 0.2 49 | self.channel_axis = 2 50 | 51 | # Need to call the base class constructor last 52 | super().__init__(fragment, *args, **kwargs) 53 | 54 | def setup(self, spec: OperatorSpec): 55 | spec.input("in1") 56 | spec.output("out1").condition(ConditionType.NONE) # Condition is for no or not-ready receiver ports. 57 | spec.param("sigma_default", 0.2) 58 | spec.param("channel_axis", 2) 59 | 60 | def compute(self, op_input, op_output, context): 61 | import numpy as np 62 | from skimage.filters import gaussian 63 | from skimage.io import imsave 64 | 65 | self.index += 1 66 | print(f"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}") 67 | 68 | data_in = op_input.receive("in1") 69 | data_out = gaussian(data_in, sigma=self.sigma_default, channel_axis=self.channel_axis) 70 | 71 | # Make sure the data type is what PIL Image can support, as the imsave function calls PIL Image fromarray() 72 | # Some details can be found at https://stackoverflow.com/questions/55319949/pil-typeerror-cannot-handle-this-data-type 73 | print(f"Data type of output: {type(data_out)!r}, max = {np.max(data_out)!r}") 74 | if np.max(data_out) <= 1: 75 | data_out = (data_out * 255).astype(np.uint8) 76 | print(f"Data type of output post conversion: {type(data_out)!r}, max = {np.max(data_out)!r}") 77 | 78 | # For now, use attribute of self to find the output path. 79 | self.output_folder.mkdir(parents=True, exist_ok=True) 80 | output_path = self.output_folder / "final_output.png" 81 | imsave(output_path, data_out) 82 | 83 | op_output.emit(data_out, "out1") 84 | -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/input/brain_mr_input.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/examples/apps/simple_imaging_app/input/brain_mr_input.jpg -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/median_operator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from monai.deploy.core import Fragment, Operator, OperatorSpec 13 | 14 | 15 | # If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other 16 | # operators and the application in packaging time. 17 | # @md.env(pip_packages=["scikit-image >= 0.17.2"]) 18 | class MedianOperator(Operator): 19 | """This Operator implements a noise reduction. 20 | 21 | The algorithm is based on the median operator. 22 | It ingests a single input and provides a single output, both are in-memory image arrays 23 | """ 24 | 25 | # Define __init__ method with super().__init__() if you want to override the default behavior. 26 | def __init__(self, fragment: Fragment, *args, **kwargs): 27 | """Create an instance to be part of the given application (fragment). 28 | 29 | Args: 30 | fragment (Fragment): The instance of Application class which is derived from Fragment 31 | """ 32 | 33 | self.index = 0 34 | 35 | # Need to call the base class constructor last 36 | super().__init__(fragment, *args, **kwargs) 37 | 38 | def setup(self, spec: OperatorSpec): 39 | spec.input("in1") 40 | spec.output("out1") 41 | 42 | def compute(self, op_input, op_output, context): 43 | from skimage.filters import median 44 | 45 | self.index += 1 46 | print(f"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}") 47 | data_in = op_input.receive("in1") 48 | data_out = median(data_in) 49 | op_output.emit(data_out, "out1") 50 | -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/requirements.txt: -------------------------------------------------------------------------------- 1 | scikit-image 2 | setuptools>=59.5.0 # for pkg_resources -------------------------------------------------------------------------------- /examples/apps/simple_imaging_app/sobel_operator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from pathlib import Path 13 | 14 | from monai.deploy.core import Fragment, Operator, OperatorSpec 15 | 16 | 17 | # # If `pip_packages` is specified, the definition will be aggregated with the package dependency list of other 18 | # # operators and the application in packaging time. 19 | # # @md.env(pip_packages=["scikit-image >= 0.17.2"]) 20 | class SobelOperator(Operator): 21 | """This Operator implements a Sobel edge detector. 22 | 23 | It has the following input and output: 24 | single input: 25 | a image file, first one found in the input folder 26 | single output: 27 | array object in memory 28 | """ 29 | 30 | DEFAULT_INPUT_FOLDER = Path.cwd() / "input" 31 | 32 | def __init__(self, fragment: Fragment, *args, input_path: Path, **kwargs): 33 | """Create an instance to be part of the given application (fragment). 34 | 35 | Args: 36 | fragment (Fragment): An instance of the Application class which is derived from Fragment 37 | input_path (Path): The path of the input image file or folder containing the image file 38 | """ 39 | self.index = 0 40 | 41 | # May want to validate the path, but it should really be validated when the compute function is called, also, 42 | # when file path as input is supported in the operator or execution context, input_folder needs not an attribute. 43 | self.input_path = input_path if input_path else SobelOperator.DEFAULT_INPUT_FOLDER 44 | 45 | # Need to call the base class constructor last 46 | super().__init__(fragment, *args, **kwargs) 47 | 48 | def setup(self, spec: OperatorSpec): 49 | spec.output("out1") 50 | 51 | def compute(self, op_input, op_output, context): 52 | from skimage import filters, io 53 | 54 | self.index += 1 55 | print(f"Number of times operator {self.name} whose class is defined in {__name__} called: {self.index}") 56 | 57 | # Ideally the op_input or execution context should provide the file path 58 | # to read data from, for operators that are file input based. 59 | # For now, use a temporary way to get input path. e.g. value set on init 60 | input_path = self.input_path 61 | print(f"Input from: {input_path}, whose absolute path: {input_path.absolute()}") 62 | if input_path.is_dir(): 63 | input_path = next(input_path.glob("*.*")) # take the first file 64 | 65 | data_in = io.imread(input_path)[:, :, :3] # discard alpha channel if exists 66 | data_out = filters.sobel(data_in) 67 | 68 | op_output.emit(data_out, "out1") 69 | -------------------------------------------------------------------------------- /monai-deploy-app-sdk.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | } 6 | ], 7 | "extensions": { 8 | "recommendations": [ 9 | "eamodio.gitlens", 10 | "ms-python.python", 11 | "ms-python.vscode-pylance", 12 | "shardulm94.trailing-spaces", 13 | ] 14 | }, 15 | "settings": { 16 | "editor.rulers": [ 17 | 79, 18 | 120 19 | ], 20 | "editor.wordWrapColumn": 120, 21 | "python.formatting.provider": "black", 22 | "python.linting.mypyEnabled": true, 23 | "python.languageServer": "Pylance", 24 | "editor.formatOnSaveMode": "modifications", 25 | }, 26 | "launch": { 27 | "version": "0.2.0", 28 | // https://code.visualstudio.com/docs/editor/variables-reference 29 | "configurations": [ 30 | { 31 | "name": "Python: simple_imaging_app", 32 | "type": "python", 33 | "request": "launch", 34 | "program": "${workspaceFolder:monai-deploy-app-sdk}/examples/apps/simple_imaging_app/app.py", 35 | "args": ["-i", "${workspaceFolder:monai-deploy-app-sdk}/examples/apps/simple_imaging_app/brain_mr_input.jpg", "-o", "${workspaceFolder:monai-deploy-app-sdk}/output"], 36 | "cwd": "${workspaceFolder:monai-deploy-app-sdk}", 37 | "console": "integratedTerminal", 38 | // Hanging on WSL2 if DISPLAY is set. Due to https://github.com/matplotlib/matplotlib/pull/17396 39 | "env" : {"DISPLAY": ""} 40 | } 41 | ] 42 | } 43 | } -------------------------------------------------------------------------------- /monai/deploy/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | """ 12 | .. autosummary:: 13 | :toctree: _autosummary 14 | 15 | conditions 16 | core 17 | loggers 18 | resources 19 | utils 20 | exceptions 21 | """ 22 | 23 | from . import _version, conditions, core, exceptions, logger, resources, utils 24 | 25 | __version__ = _version.get_versions()["version"] 26 | -------------------------------------------------------------------------------- /monai/deploy/conditions/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | .. autosummary:: 3 | :toctree: _autosummary 4 | 5 | BooleanCondition 6 | CountCondition 7 | DownstreamMessageAffordableCondition 8 | MessageAvailableCondition 9 | PeriodicCondition 10 | """ 11 | 12 | # Need to import explicit ones to quiet mypy complaints 13 | from holoscan.conditions import * 14 | from holoscan.conditions import CountCondition 15 | -------------------------------------------------------------------------------- /monai/deploy/core/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | """ 12 | .. autosummary:: 13 | :toctree: _autosummary 14 | 15 | Application 16 | Fragment 17 | Operator 18 | Condition 19 | ConditionType 20 | AppContext 21 | ExecutionContext 22 | OperatorSpec 23 | IOType 24 | InputContext 25 | OutputContext 26 | RuntimeEnv 27 | init_app_context 28 | parse_args 29 | """ 30 | 31 | # Need to import explicit ones to quiet mypy complaints 32 | from holoscan.core import * 33 | from holoscan.core import Application, Condition, ConditionType, Fragment, Operator, OperatorSpec 34 | 35 | from .app_context import AppContext, init_app_context 36 | from .arg_parser import parse_args 37 | from .domain.datapath import DataPath 38 | from .domain.image import Image 39 | from .io_type import IOType 40 | from .models import Model, ModelFactory, NamedModel, TorchScriptModel, TritonModel 41 | from .runtime_env import RuntimeEnv 42 | 43 | # Add the function to the existing Application class, which could've been used as helper func too. 44 | # It is well understood that deriving from the Application base is a better approach, but maybe later. 45 | Application.init_app_context = init_app_context 46 | -------------------------------------------------------------------------------- /monai/deploy/core/datastores/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | """ 12 | .. autosummary:: 13 | :toctree: _autosummary 14 | 15 | DatastoreFactory 16 | Datastore 17 | MemoryDatastore 18 | """ 19 | 20 | from .datastore import Datastore 21 | from .factory import DatastoreFactory 22 | from .memory import MemoryDatastore 23 | -------------------------------------------------------------------------------- /monai/deploy/core/datastores/datastore.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from abc import ABC, abstractmethod 13 | from typing import Any, Hashable, KeysView, Optional 14 | 15 | 16 | class Datastore(ABC): 17 | """Base class for data store.""" 18 | 19 | @abstractmethod 20 | def get(self, key: Hashable, def_val: Optional[Any] = None) -> Any: 21 | """Get value from the data store. 22 | 23 | Args: 24 | key (Hashable): A key to get. 25 | 26 | Returns: 27 | value (Any): A value from the data store. 28 | """ 29 | pass 30 | 31 | @abstractmethod 32 | def put(self, key: Hashable, value: Any): 33 | """Put value into the data store. 34 | 35 | Args: 36 | key (Hashable): A key to put. 37 | value (Any): A value to put. 38 | """ 39 | pass 40 | 41 | @abstractmethod 42 | def delete(self, key: Hashable): 43 | """Delete value from the data store. 44 | 45 | Args: 46 | key (Hashable): A key to delete. 47 | """ 48 | pass 49 | 50 | @abstractmethod 51 | def exists(self, key: Hashable) -> bool: 52 | """Check if key exists in data store. 53 | 54 | Args: 55 | key (Hashable): A key to check. 56 | 57 | Returns: 58 | exists (bool): True if key exists, False otherwise. 59 | """ 60 | pass 61 | 62 | @abstractmethod 63 | def size(self) -> int: 64 | """Get size of data store. 65 | 66 | Returns: 67 | size (int): A size of data store. 68 | """ 69 | pass 70 | 71 | @abstractmethod 72 | def keys(self) -> KeysView: 73 | """Get keys from data store. 74 | 75 | Returns: 76 | keys (KeysView): A view of keys. 77 | """ 78 | pass 79 | -------------------------------------------------------------------------------- /monai/deploy/core/datastores/factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from typing import Dict, Optional 13 | 14 | from monai.deploy.exceptions import UnknownTypeError 15 | 16 | from .datastore import Datastore 17 | from .memory import MemoryDatastore 18 | 19 | 20 | class DatastoreFactory: 21 | """DatastoreFactory is an abstract class that provides a way to create a datastore object.""" 22 | 23 | NAMES = ["memory"] 24 | DEFAULT = "memory" 25 | 26 | @staticmethod 27 | def create(datastore_type: str, datastore_params: Optional[Dict] = None) -> Datastore: 28 | """Creates a datastore object. 29 | 30 | Args: 31 | datastore_type (str): A type of the datastore. 32 | datastore_params (Dict): A dictionary of parameters of the datastore. 33 | 34 | Returns: 35 | Datastore: A datastore object. 36 | """ 37 | 38 | datastore_params = datastore_params or {} 39 | 40 | if datastore_type == "memory": 41 | return MemoryDatastore(**datastore_params) 42 | else: 43 | raise UnknownTypeError(f"Unknown datastore type: {datastore_type}") 44 | -------------------------------------------------------------------------------- /monai/deploy/core/datastores/memory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from typing import Any, Dict, Hashable, KeysView, Optional 13 | 14 | from .datastore import Datastore 15 | 16 | 17 | class MemoryDatastore(Datastore): 18 | def __init__(self, **kwargs: Dict): 19 | self._storage: Dict = {} 20 | 21 | def get(self, key: Hashable, def_val: Optional[Any] = None) -> Any: 22 | return self._storage.get(key, None) 23 | 24 | def put(self, key: Hashable, value: Any): 25 | self._storage[key] = value 26 | 27 | def delete(self, key: Hashable): 28 | del self._storage[key] 29 | 30 | def exists(self, key: Hashable) -> bool: 31 | return key in self._storage 32 | 33 | def size(self) -> int: 34 | return len(self._storage) 35 | 36 | def keys(self) -> KeysView: 37 | return self._storage.keys() 38 | -------------------------------------------------------------------------------- /monai/deploy/core/domain/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | """ 12 | .. autosummary:: 13 | :toctree: _autosummary 14 | 15 | Domain 16 | DataPath 17 | NamedDataPath 18 | Image 19 | DICOMStudy 20 | DICOMSeries 21 | DICOMSOPInstance 22 | SelectedSeries 23 | StudySelectedSeries 24 | """ 25 | 26 | from .datapath import DataPath, NamedDataPath 27 | from .dicom_series import DICOMSeries 28 | from .dicom_series_selection import SelectedSeries, StudySelectedSeries 29 | from .dicom_sop_instance import DICOMSOPInstance 30 | from .dicom_study import DICOMStudy 31 | from .domain import Domain 32 | from .image import Image 33 | -------------------------------------------------------------------------------- /monai/deploy/core/domain/datapath.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from pathlib import Path 13 | from typing import Dict, Optional, Union 14 | 15 | from monai.deploy.exceptions import IOMappingError, ItemNotExistsError 16 | 17 | from .domain import Domain 18 | 19 | 20 | class DataPath(Domain): 21 | def __init__(self, path: Union[str, Path], read_only: bool = False, metadata: Optional[Dict] = None): 22 | """Initializes a DataPath object. 23 | 24 | Args: 25 | path (Union[str, Path]): Path to the data file/directory. 26 | read_only (bool): True if the the file/directory path cannot be modified. 27 | metadata (Optional[Dict]): A metadata. 28 | """ 29 | super().__init__(metadata=metadata) 30 | self._path: Path = Path(path) 31 | self._read_only: bool = read_only 32 | 33 | @property 34 | def path(self): 35 | """Returns the path of the data file/directory.""" 36 | return self._path 37 | 38 | @path.setter 39 | def path(self, val): 40 | if self._read_only: 41 | raise IOMappingError("This DataPath is read-only.") 42 | self._path = Path(val) 43 | 44 | def to_absolute(self): 45 | """Convert the internal representation of the path to an absolute path.""" 46 | if not self._path.is_absolute(): 47 | self._path = self._path.absolute() 48 | 49 | 50 | class NamedDataPath(Domain): 51 | """A data path dictionary with name as key and data path as value. 52 | 53 | This class is used to store data paths and the provided name of each data path is unique. 54 | 55 | A data path for a name is accessible by calling the `get()` method with the name. 56 | 57 | If only one data path is available and the name is not specified, the data path is returned. 58 | """ 59 | 60 | def __init__(self, paths: Dict[str, DataPath], metadata: Optional[Dict] = None): 61 | super().__init__(metadata=metadata) 62 | self._paths = paths 63 | 64 | def get(self, name: Optional[str] = "") -> DataPath: 65 | if name not in self._paths: 66 | if name == "" and len(self._paths) == 1: 67 | return next(iter(self._paths.values())) 68 | else: 69 | raise IOMappingError( 70 | f"{name!r} is not a valid name. It should be one of ({', '.join(self._paths.keys())})." 71 | ) 72 | else: 73 | datapath = self._paths.get(name) 74 | if not datapath: 75 | raise ItemNotExistsError(f"A DataPath instance for {name!r} does not exist.") 76 | return datapath 77 | -------------------------------------------------------------------------------- /monai/deploy/core/domain/dicom_sop_instance.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from typing import Any, Union 13 | 14 | from monai.deploy.utils.importutil import optional_import 15 | 16 | from .domain import Domain 17 | 18 | DataElement_, dataelement_ok_ = optional_import("pydicom", name="DataElement") 19 | # Dynamic class is not handled so make it Any for now: https://github.com/python/mypy/issues/2477 20 | DataElement: Any = DataElement_ if dataelement_ok_ else Any 21 | Dataset_, dataset_ok_ = optional_import("pydicom", name="Dataset") 22 | # Dynamic class is not handled so make it Any for now: https://github.com/python/mypy/issues/2477 23 | Dataset: Any = Dataset_ if dataset_ok_ else Any 24 | Tag_, tag_ok_ = optional_import("pydicom.tag", name="Tag") 25 | # Dynamic class is not handled so make it Any for now: https://github.com/python/mypy/issues/2477 26 | Tag: Any = Tag_ if tag_ok_ else Any 27 | 28 | 29 | class DICOMSOPInstance(Domain): 30 | """This class represents a SOP Instance. 31 | 32 | An attribute can be looked up with a slice ([group_number, element number]). 33 | """ 34 | 35 | def __init__(self, native_sop): 36 | super().__init__(None) 37 | self._sop: Any = native_sop 38 | 39 | def get_native_sop_instance(self): 40 | return self._sop 41 | 42 | def __getitem__(self, key: Union[int, slice, Tag]) -> Union[Dataset, DataElement]: 43 | return self._sop.__getitem__(key) 44 | 45 | def get_pixel_array(self): 46 | return self._sop.pixel_array 47 | 48 | def __str__(self): 49 | result = "---------------" + "\n" 50 | 51 | return result 52 | -------------------------------------------------------------------------------- /monai/deploy/core/domain/domain.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from abc import ABC 13 | from typing import Dict, Optional 14 | 15 | 16 | class Domain(ABC): 17 | """Domain Class.""" 18 | 19 | def __init__(self, metadata: Optional[Dict] = None): 20 | """Initialize a Domain object. 21 | 22 | Args: 23 | metadata (Optional[Dict]): A metadata. 24 | """ 25 | super().__init__() 26 | 27 | if metadata is not None: 28 | self._metadata = metadata 29 | else: 30 | self._metadata = {} 31 | 32 | def metadata(self) -> Dict: 33 | return self._metadata 34 | -------------------------------------------------------------------------------- /monai/deploy/core/domain/image.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from typing import Any, Dict, Optional, Union 13 | 14 | try: 15 | from numpy.typing import _ArrayLike # type: ignore 16 | 17 | ArrayLike: Any = _ArrayLike 18 | except ImportError: 19 | ArrayLike = Any 20 | 21 | from .domain import Domain 22 | 23 | 24 | class Image(Domain): 25 | """_summary_ 26 | 27 | Args: 28 | Domain (_type_): _description_ 29 | """ 30 | 31 | def __init__(self, data: Union[ArrayLike], metadata: Optional[Dict] = None): 32 | """This class encapsulates array-lile object along with its associated metadata dictionary. 33 | 34 | It is designed to represent an image object, without constraining the specific format of its data. Derived 35 | classes should be created for more specific type of images. 36 | The default implementation assumes the internal data object is a ndarray, and the metadata dictionary 37 | is expected to hold the key attributes associated with the original image, e.g., for image converted 38 | from DICOM instances, the pixel spacings, image orientation patient, etc. 39 | 40 | Args: 41 | data (Union[ArrayLike]): Numpy Array object. 42 | metadata (Optional[Dict], optional): A dictionary of the object's metadata. Defaults to None. 43 | """ 44 | super().__init__(metadata) 45 | self._data = data 46 | 47 | def asnumpy(self) -> ArrayLike: 48 | return self._data 49 | -------------------------------------------------------------------------------- /monai/deploy/core/io_type.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from enum import Enum 13 | 14 | 15 | class IOType(Enum): 16 | UNKNOWN = 0 17 | DISK = 1 18 | IN_MEMORY = 2 19 | 20 | def __or__(self, other): 21 | return self.value | other.value 22 | -------------------------------------------------------------------------------- /monai/deploy/core/models/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | """ 12 | .. autosummary:: 13 | :toctree: _autosummary 14 | 15 | ModelFactory 16 | Model 17 | NamedModel 18 | TorchScriptModel 19 | TritonModel 20 | """ 21 | 22 | from .factory import ModelFactory 23 | from .model import Model 24 | from .named_model import NamedModel 25 | from .torch_model import TorchScriptModel 26 | from .triton_model import TritonModel, TritonRemoteModel 27 | 28 | Model.register([TritonModel, NamedModel, TorchScriptModel, Model]) 29 | -------------------------------------------------------------------------------- /monai/deploy/core/models/factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from pathlib import Path 13 | from typing import Optional, Tuple, Type, Union 14 | 15 | from .model import Model 16 | 17 | 18 | class ModelFactory: 19 | """ModelFactory is a class that provides a way to create a model object.""" 20 | 21 | @staticmethod 22 | def create(path: Union[str, Path], name: str = "", model_type: str = "") -> Optional[Model]: 23 | """Creates a model object. 24 | 25 | Args: 26 | path (Union[str, Path]): A path to the model. 27 | name (str): A name of the model. 28 | model_type (str): A type of the model. 29 | 30 | Returns: 31 | A model object. Returns None if the model file/folder does not exist. 32 | """ 33 | model_type, model_cls = ModelFactory.detect_model_type(path, model_type) 34 | 35 | if model_type and model_cls: 36 | model = model_cls(str(path), name) 37 | return model 38 | else: 39 | return None 40 | 41 | @staticmethod 42 | def detect_model_type(path: Union[str, Path], model_type: str = "") -> Tuple[str, Optional[Type[Model]]]: 43 | """Detects the model type based on a model path. 44 | 45 | Args: 46 | path (Union[str, Path]): A path to the model file/folder. 47 | model_type (str): A model type. 48 | 49 | Returns: 50 | A tuple of the model type string and the model class. 51 | """ 52 | path = Path(path) 53 | 54 | for model_cls in Model.registered_models(): 55 | # If a model_type is specified, check if it matches the model type. 56 | if model_type and model_cls.model_type != model_type: 57 | continue 58 | 59 | accept, model_type = model_cls.accept(path) 60 | if accept: 61 | return model_type, model_cls 62 | 63 | return "", None 64 | -------------------------------------------------------------------------------- /monai/deploy/core/runtime_env.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2025 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import os 13 | from abc import ABC 14 | from typing import Dict, Optional, Tuple 15 | 16 | 17 | class RuntimeEnv(ABC): 18 | """Class responsible for managing run time settings. 19 | 20 | The expected variables can be set via the host env vars which override the 21 | default values in the internal dictionary. 22 | Selective overriding of variables can be done by passing a dictionary to the constructor, 23 | which should have the same structure as the internal dictionary. 24 | """ 25 | 26 | ENV_DEFAULT: Dict[str, Tuple[str, ...]] = { 27 | "input": ("HOLOSCAN_INPUT_PATH", "input"), 28 | "output": ("HOLOSCAN_OUTPUT_PATH", "output"), 29 | "model": ("HOLOSCAN_MODEL_PATH", "models"), 30 | "workdir": ("HOLOSCAN_WORKDIR", ""), 31 | "triton_server_netloc": ("TRITON_SERVER_NETLOC", ""), 32 | } 33 | 34 | # Place holders as the values will be set in the __init__ method 35 | input: str = "" 36 | output: str = "" 37 | model: str = "" 38 | workdir: str = "" 39 | triton_server_netloc: str = "" # Triton server host:port 40 | 41 | def __init__(self, defaults: Optional[Dict[str, Tuple[str, ...]]] = None): 42 | if defaults is None: 43 | defaults = self.ENV_DEFAULT 44 | else: 45 | defaults = {**self.ENV_DEFAULT, **defaults} 46 | 47 | for key, (env, default) in defaults.items(): 48 | self.__dict__[key] = os.environ.get(env, default) 49 | -------------------------------------------------------------------------------- /monai/deploy/exceptions.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | 13 | class MONAIAppSdkError(Exception): 14 | """Base class for exceptions in this module.""" 15 | 16 | pass 17 | 18 | 19 | class ItemAlreadyExistsError(MONAIAppSdkError): 20 | """Raises when an item already exists in the container.""" 21 | 22 | pass 23 | 24 | 25 | class ItemNotExistsError(MONAIAppSdkError): 26 | """Raises when an item does not exist in the container.""" 27 | 28 | pass 29 | 30 | 31 | class IOMappingError(MONAIAppSdkError): 32 | """Raises when IO mapping is missing or invalid.""" 33 | 34 | pass 35 | 36 | 37 | class UnknownTypeError(MONAIAppSdkError): 38 | """Raises when unknown/wrong type/name is specified.""" 39 | 40 | pass 41 | 42 | 43 | class WrongValueError(MONAIAppSdkError): 44 | """Raises when wrong value is specified.""" 45 | 46 | pass 47 | 48 | 49 | class UnsupportedOperationError(MONAIAppSdkError): 50 | """Raises when unsupported operation is requested.""" 51 | 52 | pass 53 | -------------------------------------------------------------------------------- /monai/deploy/executors/__init__.py: -------------------------------------------------------------------------------- 1 | from holoscan.executors import * 2 | -------------------------------------------------------------------------------- /monai/deploy/graphs/__init__.py: -------------------------------------------------------------------------------- 1 | from holoscan.graphs import * 2 | -------------------------------------------------------------------------------- /monai/deploy/logger/__init__.py: -------------------------------------------------------------------------------- 1 | from holoscan.logger import * 2 | 3 | # Can also use explicit list, e.g. 4 | # from holoscan.logger import set_log_level 5 | -------------------------------------------------------------------------------- /monai/deploy/logging.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "disable_existing_loggers": false, 4 | "formatters": { 5 | "single": { 6 | "format": "%(message)s" 7 | }, 8 | "simple": { 9 | "format": "[%(asctime)s] [%(levelname)s] (%(name)s) - %(message)s" 10 | } 11 | }, 12 | "handlers": { 13 | "console": { 14 | "class": "logging.StreamHandler", 15 | "formatter": "simple" 16 | }, 17 | "runner_console": { 18 | "class": "logging.StreamHandler", 19 | "formatter": "single" 20 | } 21 | }, 22 | "root": { 23 | "level": "INFO", 24 | "propagate": false, 25 | "handlers": [ 26 | "console" 27 | ] 28 | }, 29 | "loggers": { 30 | "app_runner": { 31 | "propagate": false, 32 | "handlers": [ 33 | "runner_console" 34 | ] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /monai/deploy/operators/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2022 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | """ 12 | .. autosummary:: 13 | :toctree: _autosummary 14 | 15 | BundleConfigNames 16 | ClaraVizOperator 17 | DICOMDataLoaderOperator 18 | DICOMEncapsulatedPDFWriterOperator 19 | DICOMSegmentationWriterOperator 20 | DICOMSeriesSelectorOperator 21 | DICOMSeriesToVolumeOperator 22 | DICOMTextSRWriterOperator 23 | EquipmentInfo 24 | InferenceOperator 25 | IOMapping 26 | ModelInfo 27 | MonaiBundleInferenceOperator 28 | MonaiSegInferenceOperator 29 | PNGConverterOperator 30 | PublisherOperator 31 | STLConversionOperator 32 | STLConverter 33 | NiftiDataLoader 34 | """ 35 | 36 | # If needed, can choose to expose some or all of Holoscan SDK built-in operators. 37 | # from holoscan.operators import * 38 | from holoscan.operators import PingRxOp, PingTxOp, VideoStreamRecorderOp, VideoStreamReplayerOp 39 | 40 | from .clara_viz_operator import ClaraVizOperator 41 | from .dicom_data_loader_operator import DICOMDataLoaderOperator 42 | from .dicom_encapsulated_pdf_writer_operator import DICOMEncapsulatedPDFWriterOperator 43 | from .dicom_seg_writer_operator import DICOMSegmentationWriterOperator 44 | from .dicom_series_selector_operator import DICOMSeriesSelectorOperator 45 | from .dicom_series_to_volume_operator import DICOMSeriesToVolumeOperator 46 | from .dicom_text_sr_writer_operator import DICOMTextSRWriterOperator 47 | from .dicom_utils import EquipmentInfo, ModelInfo, random_with_n_digits, save_dcm_file, write_common_modules 48 | from .inference_operator import InferenceOperator 49 | from .monai_bundle_inference_operator import BundleConfigNames, IOMapping, MonaiBundleInferenceOperator 50 | from .monai_seg_inference_operator import MonaiSegInferenceOperator 51 | from .nii_data_loader_operator import NiftiDataLoader 52 | from .png_converter_operator import PNGConverterOperator 53 | from .publisher_operator import PublisherOperator 54 | from .stl_conversion_operator import STLConversionOperator, STLConverter 55 | -------------------------------------------------------------------------------- /monai/deploy/operators/inference_operator.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from typing import Any, Dict, Tuple, Union 13 | 14 | from monai.deploy.core import Fragment, Image, Operator 15 | 16 | 17 | class InferenceOperator(Operator): 18 | """The base operator for operators that perform AI inference. 19 | 20 | This operator performs pre-transforms on a input image, inference with 21 | a given model, post-transforms, and final results generation. 22 | """ 23 | 24 | def __init__(self, fragment: Fragment, *args, **kwargs): 25 | """Constructor of the operator.""" 26 | super().__init__(fragment, *args, **kwargs) 27 | 28 | # @abstractmethod 29 | def pre_process(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]: 30 | """Transforms input before being used for predicting on a model. 31 | 32 | This method must be overridden by a derived class. 33 | 34 | Raises: 35 | NotImplementedError: When the subclass does not override this method. 36 | """ 37 | 38 | raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.") 39 | 40 | # @abstractmethod 41 | def compute(self, op_input, op_output, context): 42 | """An abstract method that needs to be implemented by the user. 43 | 44 | Args: 45 | op_input (InputContext): An input context for the operator. 46 | op_output (OutputContext): An output context for the operator. 47 | context (ExecutionContext): An execution context for the operator. 48 | """ 49 | pass 50 | 51 | # @abstractmethod 52 | def predict(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]: 53 | """Predicts results using the models(s) with input tensors. 54 | 55 | This method must be overridden by a derived class. 56 | 57 | Raises: 58 | NotImplementedError: When the subclass does not override this method. 59 | """ 60 | raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.") 61 | 62 | # @abstractmethod 63 | def post_process(self, data: Any, *args, **kwargs) -> Union[Image, Any, Tuple[Any, ...], Dict[Any, Any]]: 64 | """Transform the prediction results from the model(s). 65 | 66 | This method must be overridden by a derived class. 67 | 68 | Raises: 69 | NotImplementedError: When the subclass does not override this method. 70 | """ 71 | raise NotImplementedError(f"Subclass {self.__class__.__name__} must implement this method.") 72 | -------------------------------------------------------------------------------- /monai/deploy/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/monai/deploy/py.typed -------------------------------------------------------------------------------- /monai/deploy/resources/__init__.py: -------------------------------------------------------------------------------- 1 | from holoscan.resources import * 2 | -------------------------------------------------------------------------------- /monai/deploy/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/monai/deploy/utils/__init__.py -------------------------------------------------------------------------------- /monai/deploy/utils/argparse_types.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import argparse 13 | import logging 14 | from pathlib import Path 15 | 16 | logger = logging.getLogger(__name__) 17 | 18 | 19 | def valid_dir_path(path: str) -> Path: 20 | """Helper type checking and type converting method for ArgumentParser.add_argument 21 | to convert string input to pathlib.Path if the given path exists and it is a directory path. 22 | If directory does not exist, create the directory and convert string input to pathlib.Path. 23 | 24 | Args: 25 | path: string input path 26 | 27 | Returns: 28 | If path exists and is a directory, return absolute path as a pathlib.Path object. 29 | 30 | If path exists and is not a directory, raises argparse.ArgumentTypeError. 31 | 32 | If path doesn't exist, create the directory and return absolute path as a pathlib.Path object. 33 | """ 34 | dir_path = Path(path).absolute() 35 | if dir_path.exists(): 36 | if dir_path.is_dir(): 37 | return dir_path 38 | else: 39 | raise argparse.ArgumentTypeError(f"Expected directory path: {dir_path!r} is not a directory") 40 | 41 | # create directory 42 | dir_path.mkdir(parents=True) 43 | return dir_path 44 | 45 | 46 | def valid_existing_dir_path(path: str) -> Path: 47 | """Helper type checking and type converting method for ArgumentParser.add_argument 48 | to convert string input to pathlib.Path if the given path exists and it is a directory path. 49 | 50 | Args: 51 | path: string input path 52 | 53 | Returns: 54 | If path exists and is a directory, return absolute path as a pathlib.Path object. 55 | 56 | If path doesn't exist or it is not a directory, raises argparse.ArgumentTypeError. 57 | """ 58 | dir_path = Path(path).absolute() 59 | if dir_path.exists() and dir_path.is_dir(): 60 | return dir_path 61 | raise argparse.ArgumentTypeError(f"No such directory: {dir_path!r}") 62 | 63 | 64 | def valid_existing_path(path: str) -> Path: 65 | """Helper type checking and type converting method for ArgumentParser.add_argument 66 | to convert string input to pathlib.Path if the given file/folder path exists. 67 | 68 | Args: 69 | path: string input path 70 | 71 | Returns: 72 | If path exists, return absolute path as a pathlib.Path object. 73 | 74 | If path doesn't exist, raises argparse.ArgumentTypeError. 75 | """ 76 | file_path = Path(path).absolute() 77 | if file_path.exists(): 78 | return file_path 79 | raise argparse.ArgumentTypeError(f"No such file/folder: {file_path!r}") 80 | -------------------------------------------------------------------------------- /monai/deploy/utils/deviceutil.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import subprocess 13 | 14 | 15 | def has_rocm(): 16 | """Return True if ROCm is installed and GPU device is detected. 17 | 18 | Args: 19 | 20 | Returns: 21 | True if ROCm is installed and GPU device is detected, otherwise False. 22 | """ 23 | cmd = "rocminfo" 24 | try: 25 | process = subprocess.run([cmd], stdout=subprocess.PIPE) 26 | for line_in in process.stdout.decode().splitlines(): 27 | if "Device Type" in line_in and "GPU" in line_in: 28 | return True 29 | except Exception: 30 | pass 31 | 32 | return False 33 | 34 | 35 | if __name__ == "__main__": 36 | print(has_rocm()) 37 | -------------------------------------------------------------------------------- /monai/deploy/utils/fileutil.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import hashlib 13 | from pathlib import Path 14 | from typing import Callable, Union 15 | 16 | 17 | def checksum(path: Union[str, Path], hash_fn: str = "sha256", chunk_num_blocks=8192, **kwargs) -> str: 18 | """Return checksum of file or directory. 19 | 20 | Args: 21 | path (Union[str, Path]): A path to file or directory. 22 | hash_fn (str): A hash function to use. Defaults to 'sha256'. 23 | chunk_num_blocks (int): A number of blocks to read at once. Defaults to 8192. 24 | **kwargs: Additional arguments to pass to hash function. 25 | 26 | Returns: 27 | str: checksum of file or directory 28 | """ 29 | 30 | if hasattr(hashlib, hash_fn): 31 | hash_func: Callable = getattr(hashlib, hash_fn) 32 | else: 33 | raise ValueError("Unknown hash function") 34 | 35 | hashlib.blake2b 36 | h: hashlib._Hash = hash_func(**kwargs) 37 | path = Path(path) 38 | 39 | if path.is_file(): 40 | path_list = [path] 41 | else: 42 | path_list = sorted(path.glob("**/*")) 43 | 44 | for path in path_list: 45 | if not path.is_file(): 46 | continue 47 | 48 | with path.open("rb") as f: 49 | for chunk in iter(lambda: f.read(chunk_num_blocks * h.block_size), b""): 50 | h.update(chunk) 51 | return h.hexdigest() 52 | 53 | 54 | if __name__ == "__main__": 55 | import sys 56 | 57 | print(checksum(sys.argv[1])) 58 | -------------------------------------------------------------------------------- /monai/deploy/utils/spinner.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import itertools 13 | import sys 14 | from multiprocessing import Event, Lock, Process 15 | 16 | 17 | class ProgressSpinner: 18 | """ 19 | Progress spinner for console. 20 | """ 21 | 22 | def __init__(self, message, delay=0.2): 23 | self.spinner_symbols = itertools.cycle(["-", "\\", "|", "/"]) 24 | self.delay = delay 25 | self.stop_event = Event() 26 | self.spinner_visible = False 27 | sys.stdout.write(message) 28 | 29 | def __enter__(self): 30 | self.start() 31 | 32 | def __exit__(self, exception, value, traceback): 33 | self.stop() 34 | 35 | def _spinner_task(self): 36 | while not self.stop_event.wait(self.delay): 37 | self._remove_spinner() 38 | self._write_next_symbol() 39 | 40 | def _write_next_symbol(self): 41 | with self._spinner_lock: 42 | if not self.spinner_visible: 43 | sys.stdout.write(next(self.spinner_symbols)) 44 | self.spinner_visible = True 45 | sys.stdout.flush() 46 | 47 | def _remove_spinner(self, cleanup=False): 48 | with self._spinner_lock: 49 | if self.spinner_visible: 50 | sys.stdout.write("\b") 51 | self.spinner_visible = False 52 | if cleanup: 53 | # overwrite spinner symbol with whitespace 54 | sys.stdout.write(" ") 55 | sys.stdout.write("\r") 56 | sys.stdout.flush() 57 | 58 | def start(self): 59 | """ 60 | Start spinner as a separate process. 61 | """ 62 | if sys.stdout.isatty(): 63 | self._spinner_lock = Lock() 64 | self.stop_event.clear() 65 | self.spinner_process = Process(target=self._spinner_task) 66 | self.spinner_process.start() 67 | 68 | def stop(self): 69 | """ 70 | Stop spinner process. 71 | """ 72 | sys.stdout.write("\b") 73 | sys.stdout.write("Done") 74 | if sys.stdout.isatty(): 75 | self.stop_event.set() 76 | self._remove_spinner(cleanup=True) 77 | self.spinner_process.join() 78 | sys.stdout.write("\n") 79 | else: 80 | sys.stdout.write("\r") 81 | -------------------------------------------------------------------------------- /platforms/aws_healthimaging/README.md: -------------------------------------------------------------------------------- 1 | [AWS HealthImaging](https://aws.amazon.com/healthimaging/) (AHI) is a HIPAA-eligible, highly scalable, performant, and cost effective medical imagery store. 2 | 3 | We have developed a [MONAI Deploy connector](https://github.com/aws-samples/healthlake-imaging-to-dicom-python-module/tree/main) to AWS HealthImaging to integrate medical imaging AI applications with sub-second image retrieval latencies at scale powered by cloud-native APIs. 4 | 5 | The MONAI AI models and applications can be hosted on [Amazon SageMaker](https://aws.amazon.com/sagemaker/), which is a fully managed service to deploy Machine Learning (ML) models at scale. Amazon SageMaker takes care of setting up and managing instances for inference and provides built-in metrics and logs for endpoints that you can use to monitor and receive alerts. It also offers a variety of NVIDIA GPU instances for ML inference, as well as multiple model deployment options with automatic scaling, including real-time inference, serverless inference, asynchronous inference and batch transform. 6 | 7 | The sample Jupyter notebooks in [this workshop](https://github.com/aws-samples/monai-on-aws-workshop) will walk you through how to deploy [MONAI Application Package (MAP)](https://github.com/Project-MONAI/monai-deploy/blob/main/guidelines/monai-application-package.md) on Amazon Sagemaker, which leverage the MONAI Deploy connector to retrieve image data from AHI and make AI prediction, as showned in this architecture diagram: 8 | 9 | ![MONAI Deploy Arch Diagram](monaideploy_arch.png) 10 | -------------------------------------------------------------------------------- /platforms/aws_healthimaging/monaideploy_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/platforms/aws_healthimaging/monaideploy_arch.png -------------------------------------------------------------------------------- /platforms/london_aicentre_aide/README.md: -------------------------------------------------------------------------------- 1 | # AIDE 2 | AIDE is an intelligent tool that allows healthcare providers to deploy AI models safely, effectively, and efficiently by enabling the integration of AI models into clinical workflows. 3 | 4 | One of the unique features of AIDE is that it was designed by the community, for the community, and will be released as open-source. AIDE is a comprehensive system, encompassing administrative and clinical tasks as well as regulatory compliance. 5 | 6 | AIDE provides opportunities for data scientists to deploy applications in hospital settings and in September 2021 the first instance of AIDE went live at King's College Hospital NHS Foundation Trust, with a stroke AI tool to support NHS clinicians to help improve direct patient care. 7 | 8 | AIDE 1.0, available on December 2022, is the first release built on MONAI Deploy. 9 | 10 | ## How it works 11 | AIDE connects any AI product to the entire patient record without requiring additional hardware or installation each time a new product is delivered into the clinical workflow. 12 | 13 | Deploying AI often involves installing separate hardware and bespoke connectivity for each algorithm. In comparison, AIDE provides a harmonised hardware and software layer, that facilitates the deployment and use of any AI product. 14 | 15 | Once clinical data has been analysed by an AI, the results are sent to the electronic patient record to support clinical decision making, such as prioritising reporting or diagnosis 16 | 17 | ![AIDE](aide_md.png) 18 | 19 | The platform can receive a live stream of clinical data, allowing clinicians to access near real-time AI analysis within seconds. 20 | 21 | MONAI Deploy Informatics Gateway provides the DICOM, FHIR and HL7 I/O, and MONAI Deploy Workflow Manager provides the AI orchestration, identifying the next best task to execute based on the incoming patient study. 22 | 23 | ## How AIDE adds value 24 | AIDE’s dedicated IT infrastructure allows multiple algorithms to run simultaneously through bespoke Application Programming Interfaces (APIs). This provides NHS Trusts with the capability to run multiple AI solutions for day-to-day clinical care. 25 | 26 | AIDE lowers the barrier to deploying clinical AI allowing individual Trusts to speed up the AI transformation of patient pathways. 27 | 28 | By September 2023, we aim to deploy AIDE across all 10 NHS Trust partners and provide access to candidate AI applications. 29 | -------------------------------------------------------------------------------- /platforms/london_aicentre_aide/aide_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/platforms/london_aicentre_aide/aide_md.png -------------------------------------------------------------------------------- /platforms/mayo_cai_viewer: -------------------------------------------------------------------------------- 1 | WIP 2 | -------------------------------------------------------------------------------- /platforms/nuance_pin/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile* 2 | docker-compose.yml 3 | README.md 4 | README* 5 | -------------------------------------------------------------------------------- /platforms/nuance_pin/Dockerfile: -------------------------------------------------------------------------------- 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 | 23 | FROM nvcr.io/nvidia/pytorch:21.07-py3 AS application 24 | 25 | ARG PARTNER_NAME 26 | ARG SERVICE_NAME 27 | ARG VERSION 28 | ARG MONAI_APP_MODULE 29 | ARG MODEL_PATH 30 | 31 | ENV TZ=Etc/UTC 32 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 33 | 34 | # python3-gdcm or python-gdcm is required for decompression 35 | RUN apt-get -y update && \ 36 | apt-get -y install --no-install-recommends python3-gdcm && \ 37 | apt-get autoclean && \ 38 | apt-get clean && \ 39 | rm -rf /var/lib/apt/lists/* 40 | 41 | # copy model file to model folder 42 | RUN wget -q https://github.com/Project-MONAI/model-zoo/releases/download/hosting_storage_v1/lung_nodule_ct_detection_v0.2.0.zip && \ 43 | unzip lung_nodule_ct_detection_v0.2.0.zip -d /tmp/ && \ 44 | mkdir -p /app/model && \ 45 | cp /tmp/lung_nodule_ct_detection/models/model.ts /app/model/ && \ 46 | rm -rf /tmp/lung_nodule_ct_detection && \ 47 | rm lung_nodule_ct_detection_v0.2.0.zip 48 | 49 | # non-root aiserviceuser in group aiserviceuser with UserID and GroupID as 20225 50 | RUN groupadd -g 20225 -r aiserviceuser && \ 51 | useradd -u 20225 -r -g aiserviceuser aiserviceuser && \ 52 | chown -R aiserviceuser:aiserviceuser /app /var 53 | USER aiserviceuser:aiserviceuser 54 | 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 66 | 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 71 | 72 | ENV AI_PARTNER_NAME ${PARTNER_NAME} 73 | ENV AI_SVC_NAME ${SERVICE_NAME} 74 | ENV AI_SVC_VERSION ${VERSION} 75 | ENV AI_MODEL_PATH ${MODEL_PATH} 76 | ENV MONAI_APP_CLASSPATH ${MONAI_APP_MODULE} 77 | 78 | ENV PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python 79 | 80 | ENV DEBUG=NO 81 | ENV KEEP_FILES=NO 82 | 83 | CMD ["python", "app_wrapper.py"] 84 | -------------------------------------------------------------------------------- /platforms/nuance_pin/app/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021-2022 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | -------------------------------------------------------------------------------- /platforms/nuance_pin/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | ai_service: 4 | container_name: aiservice 5 | image: ${PARTNER_NAME:-nvidia}-${SERVICE_NAME:-ai_lung_nodule_detection}:${VERSION:-0.1.0} 6 | build: 7 | context: ${CONTEXT:-.} 8 | args: 9 | PARTNER_NAME: MONAI 10 | SERVICE_NAME: ai_lung_nodule_detection 11 | VERSION: 0.1.0 12 | MODEL_PATH: /app/model/model.ts 13 | MONAI_APP_MODULE: app.lung_nodule.LungNoduleDetectionApp 14 | dns: 0.0.0.0 15 | environment: 16 | requestPort: ${PORT:-7777} 17 | subscriptionKey: AiSvcTestKey 18 | tempDir: /tmp/data 19 | ports: 20 | - "5000:${PORT:-7777}" 21 | tmpfs: 22 | - /tmp/data 23 | user: "${CONTAINER_UID:-20225}:${CONTAINER_GID:-20225}" 24 | -------------------------------------------------------------------------------- /platforms/nuance_pin/model/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/platforms/nuance_pin/model/.gitkeep -------------------------------------------------------------------------------- /platforms/nuance_pin/requirements.txt: -------------------------------------------------------------------------------- 1 | monai-deploy-app-sdk==0.4.0 2 | monai[all]==0.9.0 3 | pydicom==2.3.0 4 | highdicom==0.19.0 5 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=42", 4 | "wheel", 5 | "versioneer-518" 6 | ] 7 | build-backend = "setuptools.build_meta" 8 | 9 | [tool.black] 10 | line-length = 120 11 | target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] 12 | include = '\.pyi?$' 13 | exclude = ''' 14 | ( 15 | /( 16 | # exclude a few common directories in the root of the project 17 | \.eggs 18 | | \.git 19 | | \.hg 20 | | \.mypy_cache 21 | | \.tox 22 | | \.venv 23 | | \.pytype 24 | | _build 25 | | buck-out 26 | | build 27 | | dist 28 | | docs/source/notebooks 29 | | notebooks 30 | )/ 31 | # also separately exclude a file named versioneer.py and _version.py 32 | | versioneer.py 33 | | .+/versioneer.py 34 | | .+/_version.py 35 | ) 36 | ''' 37 | 38 | # https://github.com/microsoft/pyright/blob/main/docs/configuration.md 39 | # NOTE: All relative paths are relative to the location of this file. 40 | [tool.pyright] 41 | ignore = ["versioneer.py", "_version.py"] 42 | 43 | # https://google.github.io/pytype/ 44 | [tool.pytype] 45 | # Space-separated list of files or directories to exclude. 46 | exclude = [ 47 | 'versioneer.py', 48 | '_version.py', 49 | '**/_version.py', 50 | ] 51 | # Space-separated list of files or directories to process. 52 | inputs = [ 53 | 'monai', 54 | ] 55 | # Keep going past errors to analyze as many files as possible. 56 | keep_going = true 57 | # Run N jobs in parallel. When 'auto' is used, this will be equivalent to the 58 | # number of CPUs on the host system. 59 | jobs = 8 60 | # All pytype output goes here. 61 | output = '.pytype' 62 | # Platform (e.g., "linux", "win32") that the target code runs on. 63 | platform = 'linux' 64 | # Paths to source code directories, separated by ':'. 65 | pythonpath = '.' 66 | 67 | # Always use function return type annotations. This flag is temporary and will 68 | # be removed once this behavior is enabled by default. 69 | always_use_return_annotations = false 70 | 71 | # Enable parameter count checks for overriding methods. This flag is temporary 72 | # and will be removed once this behavior is enabled by default. 73 | overriding_parameter_count_checks = false 74 | 75 | # Enable return type checks for overriding methods. This flag is temporary and 76 | # will be removed once this behavior is enabled by default. 77 | overriding_return_type_checks = true 78 | 79 | # Use the enum overlay for more precise enum checking. This flag is temporary 80 | # and will be removed once this behavior is enabled by default. 81 | use_enum_overlay = false 82 | 83 | # Opt-in: Do not allow Any as a return type. 84 | no_return_any = false 85 | 86 | # Experimental: Support pyglib's @cached.property. 87 | enable_cached_property = false 88 | 89 | # Experimental: Infer precise return types even for invalid function calls. 90 | precise_return = false 91 | 92 | # Experimental: Solve unknown types to label with structural types. 93 | protocols = false 94 | 95 | # Experimental: Only load submodules that are explicitly imported. 96 | strict_import = false 97 | 98 | # Experimental: Enable exhaustive checking of function parameter types. 99 | strict_parameter_checks = false 100 | 101 | # Experimental: Emit errors for comparisons between incompatible primitive 102 | # types. 103 | strict_primitive_comparisons = false 104 | 105 | # Space-separated list of error names to ignore. 106 | disable = [ 107 | 'pyi-error', 108 | 'container-type-mismatch', 109 | 'attribute-error', 110 | ] 111 | 112 | # Don't report errors. 113 | report_errors = true 114 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | # Full requirements for developments 2 | -r requirements-min.txt 3 | flake8>=3.8.1 4 | flake8-bugbear 5 | flake8-comprehensions 6 | flake8-executable 7 | flake8-pyi 8 | mccabe 9 | pep8-naming 10 | pycodestyle 11 | pyflakes 12 | black 13 | isort 14 | pytype>=2020.6.1; platform_system != "Windows" 15 | mypy>=0.790 16 | psutil 17 | Sphinx==4.1.2 18 | recommonmark==0.6.0 19 | sphinx-autodoc-typehints==1.12.0 20 | sphinx-rtd-theme==0.5.2 21 | pytest==7.4.0 22 | pytest-cov==4.1.0 23 | pytest-lazy-fixture==0.6.3 24 | cucim~=21.06; platform_system == "Linux" 25 | monai>=1.0.0 26 | docker>=5.0.0 27 | pydicom>=2.3.0 28 | PyPDF2>=2.11.1 29 | highdicom>=0.18.2 30 | SimpleITK>=2.0.0 31 | Pillow>=8.0.0 32 | bump2version==1.0.1 33 | scikit-image>=0.17.2 34 | nibabel>=3.2.1 35 | numpy-stl>=2.12.0 36 | trimesh>=3.8.11 37 | torch>=2.0.1 38 | -------------------------------------------------------------------------------- /requirements-examples.txt: -------------------------------------------------------------------------------- 1 | scikit-image>=0.17.2 2 | pydicom>=2.3.0 3 | PyPDF2>=2.11.1 4 | types-pytz>=2024.1.0.20240203 5 | highdicom>=0.18.2 6 | SimpleITK>=2.0.0 7 | Pillow>=8.4.0 8 | nibabel>=3.2.1 9 | numpy-stl>=2.12.0 10 | trimesh>=3.8.11 11 | torch>=2.0.1 12 | monai>=1.0.0 -------------------------------------------------------------------------------- /requirements-min.txt: -------------------------------------------------------------------------------- 1 | # Requirements for minimal tests 2 | -r requirements.txt 3 | setuptools>=59.5.0 4 | coverage>=5.5 5 | parameterized 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | holoscan~=3.0 2 | holoscan-cli~=3.0 3 | numpy>=1.21.6 4 | colorama>=0.4.1 5 | tritonclient[all]>=2.53.0 6 | typeguard>=3.0.0 7 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | 13 | import site 14 | import sys 15 | 16 | from setuptools import find_namespace_packages, setup 17 | 18 | import versioneer 19 | 20 | # Workaround for editable installs with system's Python venv. 21 | # error: can't create or remove files in install directory 22 | # (https://github.com/pypa/pip/issues/7953#issuecomment-645133255) 23 | site.ENABLE_USER_SITE = "--user" in sys.argv[1:] 24 | 25 | setup( 26 | version=versioneer.get_version(), 27 | cmdclass=versioneer.get_cmdclass(), 28 | packages=find_namespace_packages(include=["monai.*"]), 29 | include_package_data=True, 30 | zip_safe=False, 31 | # The following entry_points are for reference only as Holoscan sets them up 32 | # entry_points={ 33 | # "console_scripts": [ 34 | # "holoscan = holoscan.cli.__main__:main", 35 | # "monai-deploy = holoscan.cli.__main__:main", 36 | # ] 37 | # }, 38 | ) 39 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/tests/__init__.py -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # Fixtures 13 | from .fixtures.runner_fixtures import * # noqa 14 | -------------------------------------------------------------------------------- /tests/fixtures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/tests/fixtures/__init__.py -------------------------------------------------------------------------------- /tests/integration/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/tests/integration/__init__.py -------------------------------------------------------------------------------- /tests/performance/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/tests/performance/__init__.py -------------------------------------------------------------------------------- /tests/system/packager/test_packager.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | # import os 13 | # import subprocess 14 | 15 | # from monai.deploy.cli.main import main as monai_deploy 16 | 17 | 18 | # def test_packager(): 19 | # test_map_tag = "monaitest:latest" 20 | # test_app_path_rel = "examples/apps/simple_imaging_app/" 21 | # test_app_path = os.path.abspath(test_app_path_rel) 22 | # args = ["monai-deploy", "package", "-t", test_map_tag, test_app_path] 23 | # monai_deploy(args) 24 | 25 | # # Delete MONAI application package image 26 | # docker_rmi_cmd = ["docker", "rmi", "-f", test_map_tag] 27 | # subprocess.Popen(docker_rmi_cmd) 28 | -------------------------------------------------------------------------------- /tests/unit/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/tests/unit/__init__.py -------------------------------------------------------------------------------- /tests/unit/test_runner_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | from contextlib import contextmanager 13 | 14 | import pytest 15 | 16 | # from unittest.mock import patch 17 | 18 | # from pytest_lazyfixture import lazy_fixture 19 | 20 | 21 | class ContainsString(str): 22 | def __eq__(self, other): 23 | return self in other 24 | 25 | 26 | class DoesntContainsString(str): 27 | def __eq__(self, other): 28 | return self not in other 29 | 30 | 31 | @contextmanager 32 | def not_raises(exception): 33 | try: 34 | yield 35 | except exception as err: 36 | raise pytest.fail(f"DID RAISE {exception}") from err 37 | 38 | 39 | # @pytest.mark.parametrize("cmd, expected_returncode", [("my correct test command", 0), ("my errored test command", 125)]) 40 | # @patch("subprocess.Popen") 41 | # def test_run_cmd(mock_popen, cmd, expected_returncode): 42 | # from monai.deploy.runner import utils 43 | 44 | # mock_popen.return_value.wait.return_value = expected_returncode 45 | 46 | # actual_returncode = utils.run_cmd(cmd) 47 | 48 | # assert actual_returncode == expected_returncode 49 | 50 | 51 | # @pytest.mark.parametrize("image_name", [lazy_fixture("sample_map_name")]) 52 | # @pytest.mark.parametrize( 53 | # "docker_images_output, image_present, image_pulled", 54 | # [(lazy_fixture("sample_map_name"), True, 0), ("", False, 0), ("", False, 1)], 55 | # ) 56 | # @patch("subprocess.check_output") 57 | # @patch("monai.deploy.runner.utils.run_cmd") 58 | # def test_verify_image(mock_run_cmd, mock_check_output, image_name, docker_images_output, image_present, image_pulled): 59 | # from monai.deploy.runner import utils 60 | 61 | # mock_run_cmd.return_value = image_pulled 62 | # mock_check_output.return_value = docker_images_output 63 | 64 | # actual_response = utils.verify_image(image_name) 65 | 66 | # assert actual_response == image_present or (image_pulled == 0) 67 | 68 | # if not image_present: 69 | # mock_run_cmd.assert_called_once_with(ContainsString("docker pull")) 70 | -------------------------------------------------------------------------------- /tests/unit/test_sizeutil.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 MONAI Consortium 2 | # Licensed under the Apache License, Version 2.0 (the "License"); 3 | # you may not use this file except in compliance with the License. 4 | # You may obtain a copy of the License at 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # Unless required by applicable law or agreed to in writing, software 7 | # distributed under the License is distributed on an "AS IS" BASIS, 8 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | # See the License for the specific language governing permissions and 10 | # limitations under the License. 11 | 12 | import pytest 13 | 14 | from monai.deploy.utils.sizeutil import convert_bytes, get_bytes 15 | 16 | 17 | def test_get_bytes(): 18 | assert get_bytes(1024) == 1024 19 | assert get_bytes("1024") == 1024 20 | with pytest.raises(ValueError): 21 | get_bytes(-1) 22 | with pytest.raises(TypeError): 23 | get_bytes(0.3) 24 | with pytest.raises(ValueError): 25 | get_bytes("2.3 unknownlongunit") 26 | with pytest.raises(ValueError): 27 | get_bytes("2.3jb") 28 | assert get_bytes("2kb") == 2 * 1000 29 | assert get_bytes(" 2 KiB ") == 2 * 1024 30 | with pytest.raises(ValueError): 31 | get_bytes("-2.3Gb") 32 | 33 | 34 | def test_convert_bytes(): 35 | with pytest.raises(ValueError): 36 | convert_bytes(-1) 37 | with pytest.raises(TypeError): 38 | convert_bytes(0.3) 39 | with pytest.raises(ValueError): 40 | convert_bytes(1024, "unknownunit") 41 | assert convert_bytes(1024 * 1024) == "1Mi" 42 | assert convert_bytes(1024, "b") == 1024 43 | assert convert_bytes(1024 * 1024 * 1024, "Mi") == "1024Mi" 44 | assert convert_bytes(1024 * 1024, "kib") == "1024kib" 45 | assert convert_bytes(int(1024 * 0.211), "kib") == "0.2kib" 46 | -------------------------------------------------------------------------------- /tests/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-MONAI/monai-deploy-app-sdk/c3100f53e3c3adca3b30f225a3f98e26d6fba3e6/tests/util/__init__.py --------------------------------------------------------------------------------