From 7ca364157a95e3040fa65d088dc5256a8db93661 Mon Sep 17 00:00:00 2001 From: Tejas Ganesh Naik <“tejasgn@amazon.com”> Date: Fri, 26 Sep 2025 13:59:55 -0700 Subject: [PATCH 1/4] healthimaging sample code updates --- .../start_dicom_import_job.cpp | 18 ++++- .../actions/start-dicom-import-job.js | 28 ++++---- .../medicalimaging/StartDicomImportJob.java | 67 +++++++++++++------ .../medical-imaging/medical_imaging_basics.py | 59 ++++++++-------- 4 files changed, 106 insertions(+), 66 deletions(-) diff --git a/cpp/example_code/medical-imaging/start_dicom_import_job.cpp b/cpp/example_code/medical-imaging/start_dicom_import_job.cpp index 72b893789cd..f22b485f60a 100644 --- a/cpp/example_code/medical-imaging/start_dicom_import_job.cpp +++ b/cpp/example_code/medical-imaging/start_dicom_import_job.cpp @@ -29,6 +29,7 @@ \param outputBucketName: The name of the S3 bucket for the output. \param outputDirectory: The directory in the S3 bucket to store the output. \param roleArn: The ARN of the IAM role with permissions for the import. + \param importConfigJson: The import configuration JSON string (optional). \param importJobId: A string to receive the import job ID. \param clientConfig: Aws client configuration. \return bool: Function succeeded. @@ -37,6 +38,7 @@ bool AwsDoc::Medical_Imaging::startDICOMImportJob( const Aws::String &dataStoreID, const Aws::String &inputBucketName, const Aws::String &inputDirectory, const Aws::String &outputBucketName, const Aws::String &outputDirectory, const Aws::String &roleArn, + const Aws::String &importConfigJson, Aws::String &importJobId, const Aws::Client::ClientConfiguration &clientConfig) { Aws::MedicalImaging::MedicalImagingClient medicalImagingClient(clientConfig); @@ -48,8 +50,20 @@ bool AwsDoc::Medical_Imaging::startDICOMImportJob( startDICOMImportJobRequest.SetInputS3Uri(inputURI); startDICOMImportJobRequest.SetOutputS3Uri(outputURI); - Aws::MedicalImaging::Model::StartDICOMImportJobOutcome startDICOMImportJobOutcome = medicalImagingClient.StartDICOMImportJob( - startDICOMImportJobRequest); + if (!importConfigJson.empty()) { + Aws::Utils::Json::JsonValue jsonValue(importConfigJson); + if (jsonValue.WasParseSuccessful()) { + startDICOMImportJobRequest.SetImportConfiguration( + Aws::MedicalImaging::Model::ImportConfiguration(jsonValue)); + } + else { + std::cerr << "Failed to parse import configuration JSON" << std::endl; + return false; + } + } + + Aws::MedicalImaging::Model::StartDICOMImportJobOutcome startDICOMImportJobOutcome = + medicalImagingClient.StartDICOMImportJob(startDICOMImportJobRequest); if (startDICOMImportJobOutcome.IsSuccess()) { importJobId = startDICOMImportJobOutcome.GetResult().GetJobId(); diff --git a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js index 692ed3cb11e..af76345b36f 100644 --- a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js +++ b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js @@ -13,6 +13,7 @@ import { medicalImagingClient } from "../libs/medicalImagingClient.js"; * @param {string} dataAccessRoleArn - The Amazon Resource Name (ARN) of the role that grants permission. * @param {string} inputS3Uri - The URI of the S3 bucket containing the input files. * @param {string} outputS3Uri - The URI of the S3 bucket where the output files are stored. + * @param {Object} importConfiguration - The configuration for digital pathology import. */ export const startDicomImportJob = async ( jobName = "test-1", @@ -20,6 +21,17 @@ export const startDicomImportJob = async ( dataAccessRoleArn = "arn:aws:iam::xxxxxxxxxxxx:role/ImportJobDataAccessRole", inputS3Uri = "s3://medical-imaging-dicom-input/dicom_input/", outputS3Uri = "s3://medical-imaging-output/job_output/", + importConfiguration = { + digitalPathologyImportConfiguration: { + qualityFactor: 85, + fileMetadataMappings: [ + { + imageFilePath: "image.svs", + metadataFilePath: "metadata.json" + } + ] + } + } ) => { const response = await medicalImagingClient.send( new StartDICOMImportJobCommand({ @@ -28,23 +40,11 @@ export const startDicomImportJob = async ( dataAccessRoleArn: dataAccessRoleArn, inputS3Uri: inputS3Uri, outputS3Uri: outputS3Uri, + importConfiguration: importConfiguration, }), ); console.log(response); - // { - // '$metadata': { - // httpStatusCode: 200, - // requestId: '6e81d191-d46b-4e48-a08a-cdcc7e11eb79', - // extendedRequestId: undefined, - // cfId: undefined, - // attempts: 1, - // totalRetryDelay: 0 - // }, - // datastoreId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - // jobId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - // jobStatus: 'SUBMITTED', - // submittedAt: 2023-09-22T14:48:45.767Z - // } + // {// '$metadata': {// httpStatusCode: 200,// requestId: '6e81d191-d46b-4e48-a08a-cdcc7e11eb79',// extendedRequestId: undefined,// cfId: undefined,// attempts: 1,// totalRetryDelay: 0// },// datastoreId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',// jobId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',// jobStatus: 'SUBMITTED',// submittedAt: 2023-09-22T14:48:45.767Z// } return response; }; // snippet-end:[medical-imaging.JavaScript.dicom.startDicomImportJobV3] diff --git a/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/StartDicomImportJob.java b/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/StartDicomImportJob.java index a87b4c8340f..1fedda819a8 100644 --- a/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/StartDicomImportJob.java +++ b/javav2/example_code/medicalimaging/src/main/java/com/example/medicalimaging/StartDicomImportJob.java @@ -64,28 +64,53 @@ public static void main(String[] args) { // snippet-start:[medicalimaging.java2.start_dicom_import_job.main] public static String startDicomImportJob(MedicalImagingClient medicalImagingClient, - String jobName, - String datastoreId, - String dataAccessRoleArn, - String inputS3Uri, - String outputS3Uri) { - - try { - StartDicomImportJobRequest startDicomImportJobRequest = StartDicomImportJobRequest.builder() - .jobName(jobName) - .datastoreId(datastoreId) - .dataAccessRoleArn(dataAccessRoleArn) - .inputS3Uri(inputS3Uri) - .outputS3Uri(outputS3Uri) + String jobName, + String datastoreId, + String dataAccessRoleArn, + String inputS3Uri, + String outputS3Uri, + String importConfigJson) { + + try { + software.amazon.awssdk.utils.json.JsonNode jsonNode = + software.amazon.awssdk.utils.json.JsonFactory.jsonParser().parse(importConfigJson); + + ImportConfiguration importConfiguration = ImportConfiguration.builder() + .digitalPathologyImportConfiguration( + DigitalPathologyImportConfiguration.builder() + .qualityFactor(jsonNode.get("digitalPathologyImportConfiguration") + .get("qualityFactor").asInt()) + .fileMetadataMappings( + jsonNode.get("digitalPathologyImportConfiguration") + .get("fileMetadataMappings") + .elements() + .map(mapping -> FileMetadataMapping.builder() + .imageFilePath(mapping.get("imageFilePath").asString()) + .metadataFilePath(mapping.get("metadataFilePath").asString()) + .build()) + .collect(java.util.stream.Collectors.toList()) + ) + .build() + ) .build(); - StartDicomImportJobResponse response = medicalImagingClient.startDICOMImportJob(startDicomImportJobRequest); - return response.jobId(); - } catch (MedicalImagingException e) { - System.err.println(e.awsErrorDetails().errorMessage()); - System.exit(1); - } - return ""; - } + StartDicomImportJobRequest startDicomImportJobRequest = StartDicomImportJobRequest.builder() + .jobName(jobName) + .datastoreId(datastoreId) + .dataAccessRoleArn(dataAccessRoleArn) + .inputS3Uri(inputS3Uri) + .outputS3Uri(outputS3Uri) + .importConfiguration(importConfiguration) + .build(); + + StartDicomImportJobResponse response = medicalImagingClient.startDICOMImportJob(startDicomImportJobRequest); + return response.jobId(); + } catch (MedicalImagingException e) { + System.err.println(e.awsErrorDetails().errorMessage()); + System.exit(1); + } + + return ""; + } // snippet-end:[medicalimaging.java2.start_dicom_import_job.main] } diff --git a/python/example_code/medical-imaging/medical_imaging_basics.py b/python/example_code/medical-imaging/medical_imaging_basics.py index 2773041e1ba..37e2118f126 100644 --- a/python/example_code/medical-imaging/medical_imaging_basics.py +++ b/python/example_code/medical-imaging/medical_imaging_basics.py @@ -123,35 +123,36 @@ def delete_datastore(self, datastore_id): # snippet-start:[python.example_code.medical-imaging.StartDICOMImportJob] def start_dicom_import_job( - self, job_name, datastore_id, role_arn, input_s3_uri, output_s3_uri - ): - """ - Start a DICOM import job. - - :param job_name: The name of the job. - :param datastore_id: The ID of the data store. - :param role_arn: The Amazon Resource Name (ARN) of the role to use for the job. - :param input_s3_uri: The S3 bucket input prefix path containing the DICOM files. - :param output_s3_uri: The S3 bucket output prefix path for the result. - :return: The job ID. - """ - try: - job = self.health_imaging_client.start_dicom_import_job( - jobName=job_name, - datastoreId=datastore_id, - dataAccessRoleArn=role_arn, - inputS3Uri=input_s3_uri, - outputS3Uri=output_s3_uri, - ) - except ClientError as err: - logger.error( - "Couldn't start DICOM import job. Here's why: %s: %s", - err.response["Error"]["Code"], - err.response["Error"]["Message"], - ) - raise - else: - return job["jobId"] + self, job_name, datastore_id, role_arn, input_s3_uri, output_s3_uri, import_configuration + ): + """ + Start a DICOM import job. + + :param job_name: The name of the job. + :param datastore_id: The ID of the data store. + :param role_arn: The Amazon Resource Name (ARN) of the role to use for the job. + :param input_s3_uri: The S3 bucket input prefix path containing the DICOM files. + :param output_s3_uri: The S3 bucket output prefix path for the result. + :return: The job ID. + """ + try: + job = self.health_imaging_client.start_dicom_import_job( + jobName=job_name, + datastoreId=datastore_id, + dataAccessRoleArn=role_arn, + inputS3Uri=input_s3_uri, + outputS3Uri=output_s3_uri, + importConfiguration=import_configuration + ) + except ClientError as err: + logger.error( + "Couldn't start DICOM import job. Here's why: %s: %s", + err.response["Error"]["Code"], + err.response["Error"]["Message"], + ) + raise + else: + return job["jobId"] # snippet-end:[python.example_code.medical-imaging.StartDICOMImportJob] From 6e8acab4ef2faa33ba090589ca7c2b40ef7f34b9 Mon Sep 17 00:00:00 2001 From: Tejas Ganesh Naik <“tejasgn@amazon.com”> Date: Fri, 26 Sep 2025 14:18:32 -0700 Subject: [PATCH 2/4] making lint fixes in jsv3 and python --- .../actions/start-dicom-import-job.js | 15 ++++- .../medical-imaging/medical_imaging_basics.py | 57 +++++++++---------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js index af76345b36f..9960512a2ab 100644 --- a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js +++ b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js @@ -44,7 +44,20 @@ export const startDicomImportJob = async ( }), ); console.log(response); - // {// '$metadata': {// httpStatusCode: 200,// requestId: '6e81d191-d46b-4e48-a08a-cdcc7e11eb79',// extendedRequestId: undefined,// cfId: undefined,// attempts: 1,// totalRetryDelay: 0// },// datastoreId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',// jobId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',// jobStatus: 'SUBMITTED',// submittedAt: 2023-09-22T14:48:45.767Z// } + // { + // '$metadata': { + // httpStatusCode: 200, + // requestId: '6e81d191-d46b-4e48-a08a-cdcc7e11eb79', + // extendedRequestId: undefined, + // cfId: undefined, + // attempts: 1, + // totalRetryDelay: 0 + // }, + // datastoreId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + // jobId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', + // jobStatus: 'SUBMITTED', + // submittedAt: 2023-09-22T14:48:45.767Z + // } return response; }; // snippet-end:[medical-imaging.JavaScript.dicom.startDicomImportJobV3] diff --git a/python/example_code/medical-imaging/medical_imaging_basics.py b/python/example_code/medical-imaging/medical_imaging_basics.py index 37e2118f126..45e6970a91a 100644 --- a/python/example_code/medical-imaging/medical_imaging_basics.py +++ b/python/example_code/medical-imaging/medical_imaging_basics.py @@ -125,35 +125,34 @@ def delete_datastore(self, datastore_id): def start_dicom_import_job( self, job_name, datastore_id, role_arn, input_s3_uri, output_s3_uri, import_configuration ): - """ - Start a DICOM import job. - - :param job_name: The name of the job. - :param datastore_id: The ID of the data store. - :param role_arn: The Amazon Resource Name (ARN) of the role to use for the job. - :param input_s3_uri: The S3 bucket input prefix path containing the DICOM files. - :param output_s3_uri: The S3 bucket output prefix path for the result. - :return: The job ID. - """ - try: - job = self.health_imaging_client.start_dicom_import_job( - jobName=job_name, - datastoreId=datastore_id, - dataAccessRoleArn=role_arn, - inputS3Uri=input_s3_uri, - outputS3Uri=output_s3_uri, - importConfiguration=import_configuration - ) - except ClientError as err: - logger.error( - "Couldn't start DICOM import job. Here's why: %s: %s", - err.response["Error"]["Code"], - err.response["Error"]["Message"], - ) - raise - else: - return job["jobId"] + """ + Start a DICOM import job. + :param job_name: The name of the job. + :param datastore_id: The ID of the data store. + :param role_arn: The Amazon Resource Name (ARN) of the role to use for the job. + :param input_s3_uri: The S3 bucket input prefix path containing the DICOM files. + :param output_s3_uri: The S3 bucket output prefix path for the result. + :return: The job ID. + """ + try: + job = self.health_imaging_client.start_dicom_import_job( + jobName=job_name, + datastoreId=datastore_id, + dataAccessRoleArn=role_arn, + inputS3Uri=input_s3_uri, + outputS3Uri=output_s3_uri, + importConfiguration=import_configuration + ) + except ClientError as err: + logger.error( + "Couldn't start DICOM import job. Here's why: %s: %s", + err.response["Error"]["Code"], + err.response["Error"]["Message"], + ) + raise + else: + return job["jobId"] # snippet-end:[python.example_code.medical-imaging.StartDICOMImportJob] # snippet-start:[python.example_code.medical-imaging.GetDICOMImportJob] @@ -711,7 +710,7 @@ def usage_demo(self, source_s3_uri, dest_s3_uri, data_access_role_arn): job_name = "python_usage_demo_job" job_id = self.start_dicom_import_job( - job_name, data_store_id, data_access_role_arn, source_s3_uri, dest_s3_uri + job_name, data_store_id, data_access_role_arn, source_s3_uri, dest_s3_uri, import_configuration ) print(f"Started import job with id: {job_id}") From 2838ad92e4e3c728c061bf3033e4ca2a15c81ba1 Mon Sep 17 00:00:00 2001 From: Tejas Ganesh Naik <“tejasgn@amazon.com”> Date: Fri, 26 Sep 2025 15:35:30 -0700 Subject: [PATCH 3/4] fixed js linting issue and added import_config in python --- .../medical-imaging/actions/start-dicom-import-job.js | 6 +++--- .../medical-imaging/medical_imaging_basics.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js index 9960512a2ab..6051dbdb80e 100644 --- a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js +++ b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js @@ -27,9 +27,9 @@ export const startDicomImportJob = async ( fileMetadataMappings: [ { imageFilePath: "image.svs", - metadataFilePath: "metadata.json" - } - ] + metadataFilePath: "metadata.json", + }, + ], } } ) => { diff --git a/python/example_code/medical-imaging/medical_imaging_basics.py b/python/example_code/medical-imaging/medical_imaging_basics.py index 45e6970a91a..9b1b0bf3f4b 100644 --- a/python/example_code/medical-imaging/medical_imaging_basics.py +++ b/python/example_code/medical-imaging/medical_imaging_basics.py @@ -709,6 +709,17 @@ def usage_demo(self, source_s3_uri, dest_s3_uri, data_access_role_arn): print(f"datastores : {datastores}") job_name = "python_usage_demo_job" + import_configuration = { + "digitalPathologyImportConfiguration": { + "qualityFactor": 85, + "fileMetadataMappings": [ + { + "imageFilePath": "image.svs", + "metadataFilePath": "metadata.json" + } + ] + } + } job_id = self.start_dicom_import_job( job_name, data_store_id, data_access_role_arn, source_s3_uri, dest_s3_uri, import_configuration ) From 3a51bfeb62ff51ef440e8fcda3aeee4abcd1e2d4 Mon Sep 17 00:00:00 2001 From: Tejas Ganesh Naik <“tejasgn@amazon.com”> Date: Fri, 26 Sep 2025 15:38:56 -0700 Subject: [PATCH 4/4] added commas for js lint fix --- .../medical-imaging/actions/start-dicom-import-job.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js index 6051dbdb80e..beba224233d 100644 --- a/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js +++ b/javascriptv3/example_code/medical-imaging/actions/start-dicom-import-job.js @@ -30,8 +30,8 @@ export const startDicomImportJob = async ( metadataFilePath: "metadata.json", }, ], - } - } + }, + }, ) => { const response = await medicalImagingClient.send( new StartDICOMImportJobCommand({