-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cdeb69b
commit aa1cbb3
Showing
6 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
FROM stebo85/bet4 | ||
LABEL "com.siemens-healthineers.magneticresonance.openrecon.metadata:1.1.0"="ewogICJnZW5lcmFsIjogewogICAgIm5hbWUiOiB7CiAgICAgICJlbiI6ICJkZWZhY2luZyIKICAgIH0sCiAgICAidmVyc2lvbiI6ICIxLjAuMCIsCiAgICAidmVuZG9yIjogIm5ldXJvZGVzayIsCiAgICAiaW5mb3JtYXRpb24iOiB7CiAgICAgICJlbiI6ICJEZWZhY2luZyBwaXBlbGluZS4iCiAgICB9LAogICAgImlkIjogImRlZmFjaW5nIiwKICAgICJyZWd1bGF0b3J5X2luZm9ybWF0aW9uIjogewogICAgICAiZGV2aWNlX3RyYWRlX25hbWUiOiAiZGVmYWNpbmciLAogICAgICAicHJvZHVjdGlvbl9pZGVudGlmaWVyIjogIjEuMC4wIiwKICAgICAgIm1hbnVmYWN0dXJlcl9hZGRyZXNzIjogIkVybGFuZ2VuLCBHZXJtYW55IiwKICAgICAgIm1hZGVfaW4iOiAiREUiLAogICAgICAibWFudWZhY3R1cmVfZGF0ZSI6ICIyMDIzLzAyLzE0IiwKICAgICAgIm1hdGVyaWFsX251bWJlciI6ICJkZWZhY2luZ18yLjAuMCIsCiAgICAgICJndGluIjogIjAwODYwMDAwMTcxMjEyIiwKICAgICAgInVkaSI6ICIoMDEpMDA4NjAwMDAxNzEyMTIoMjEpMS4zLjAiLAogICAgICAic2FmZXR5X2FkdmljZXMiOiAiIiwKICAgICAgInNwZWNpYWxfb3BlcmF0aW5nX2luc3RydWN0aW9ucyI6ICJPcGVuIFJlY29uIERlZmFjaW5nIHBpcGVsaW5lIiwKICAgICAgImFkZGl0aW9uYWxfcmVsZXZhbnRfaW5mb3JtYXRpb24iOiAiIgogICAgfQogIH0sCiAgInJlY29uc3RydWN0aW9uIjogewogICAgInRyYW5zZmVyX3Byb3RvY29sIjogewogICAgICAicHJvdG9jb2wiOiAiSVNNUk1SRCIsCiAgICAgICJ2ZXJzaW9uIjogIjEuNC4xIgogICAgfSwKICAgICJwb3J0IjogOTAwMiwKICAgICJlbWl0dGVyIjogImltYWdlIiwKICAgICJpbmplY3RvciI6ICJpbWFnZSIsCiAgICAiY2FuX3Byb2Nlc3NfYWRqdXN0bWVudF9kYXRhIjogZmFsc2UsCiAgICAiY2FuX3VzZV9ncHUiOiBmYWxzZSwKICAgICJtaW5fY291bnRfcmVxdWlyZWRfZ3B1cyI6IDAsCiAgICAibWluX3JlcXVpcmVkX2dwdV9tZW1vcnkiOiAyMDQ4LAogICAgIm1pbl9yZXF1aXJlZF9tZW1vcnkiOiA0MDk2LAogICAgIm1pbl9jb3VudF9yZXF1aXJlZF9jcHVfY29yZXMiOiAxLAogICAgImNvbnRlbnRfcXVhbGlmaWNhdGlvbl90eXBlIjogIlBST0RVQ1QiCiAgfSwKICAicGFyYW1ldGVycyI6IFsKICAgIHsKICAgICAgImlkIjogImNvbmZpZyIsCiAgICAgICJsYWJlbCI6IHsKICAgICAgICAiZW4iOiAiY29uZmlnIgogICAgICB9LAogICAgICAidHlwZSI6ICJjaG9pY2UiLAogICAgICAidmFsdWVzIjogWwogICAgICAgIHsKICAgICAgICAgICJpZCI6ICJpbnZlcnRjb250cmFzdCIsCiAgICAgICAgICAibmFtZSI6IHsKICAgICAgICAgICAgImVuIjogImludmVydGNvbnRyYXN0IgogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImlkIjogInJnYiIsCiAgICAgICAgICAibmFtZSI6IHsKICAgICAgICAgICAgImVuIjogInJnYiIKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJpZCI6ICJzaW1wbGVmZnQiLAogICAgICAgICAgIm5hbWUiOiB7CiAgICAgICAgICAgICJlbiI6ICJzaW1wbGVmZnQiCiAgICAgICAgICB9CiAgICAgICAgfQogICAgICBdLAogICAgICAiZGVmYXVsdCI6ICJpbnZlcnRjb250cmFzdCIsCiAgICAgICJpbmZvcm1hdGlvbiI6IHsKICAgICAgICAiZW4iOiAiRGVmaW5lIHRoZSBjb25maWcgdG8gYmUgZXhlY3V0ZWQgYnkgTVJEIHNlcnZlciIKICAgICAgfQogICAgfSwKICAgIHsKICAgICAgImlkIjogImN1c3RvbWNvbmZpZyIsCiAgICAgICJsYWJlbCI6IHsKICAgICAgICAiZW4iOiAiQ3VzdG9tIENvbmZpZyIKICAgICAgfSwKICAgICAgInR5cGUiOiAic3RyaW5nIiwKICAgICAgImRlZmF1bHQiOiAiIiwKICAgICAgImluZm9ybWF0aW9uIjogewogICAgICAgICJlbiI6ICJDdXN0b20gY29uZmlnIGZpbGUgbm90IGxpc3RlZCBpbiBkcm9wLWRvd24gbWVudSIKICAgICAgfQogICAgfSwKICAgIHsKICAgICAgImlkIjogIm9wdGlvbnMiLAogICAgICAibGFiZWwiOiB7CiAgICAgICAgImVuIjogIm9wdGlvbnMiCiAgICAgIH0sCiAgICAgICJ0eXBlIjogImNob2ljZSIsCiAgICAgICJ2YWx1ZXMiOiBbCiAgICAgICAgewogICAgICAgICAgImlkIjogIm5vbmUiLAogICAgICAgICAgIm5hbWUiOiB7CiAgICAgICAgICAgICJlbiI6ICJub25lIgogICAgICAgICAgfQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgImlkIjogInJvaSIsCiAgICAgICAgICAibmFtZSI6IHsKICAgICAgICAgICAgImVuIjogInJvaSIKICAgICAgICAgIH0KICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICJpZCI6ICJjb2xvcm1hcCIsCiAgICAgICAgICAibmFtZSI6IHsKICAgICAgICAgICAgImVuIjogImNvbG9ybWFwIgogICAgICAgICAgfQogICAgICAgIH0KICAgICAgXSwKICAgICAgImRlZmF1bHQiOiAibm9uZSIsCiAgICAgICJpbmZvcm1hdGlvbiI6IHsKICAgICAgICAiZW4iOiAiRGVmaW5lIGFkZGl0aW9uYWwgb3B0aW9ucyIKICAgICAgfQogICAgfSwKICAgIHsKICAgICAgImlkIjogImRvdWJsZSIsCiAgICAgICJsYWJlbCI6IHsKICAgICAgICAiZW4iOiAiZG91YmxlIgogICAgICB9LAogICAgICAidHlwZSI6ICJkb3VibGUiLAogICAgICAibWluaW11bSI6IDAsCiAgICAgICJtYXhpbXVtIjogMTAwLAogICAgICAiZGVmYXVsdCI6IDEuMCwKICAgICAgImluZm9ybWF0aW9uIjogewogICAgICAgICJlbiI6ICJBIGRvdWJsZSBwYXJhbWV0ZXIiCiAgICAgIH0KICAgIH0sCiAgICB7CiAgICAgICJpZCI6ICJmcmVldGV4dCIsCiAgICAgICJsYWJlbCI6IHsKICAgICAgICAiZW4iOiAiZnJlZXRleHQiCiAgICAgIH0sCiAgICAgICJ0eXBlIjogInN0cmluZyIsCiAgICAgICJkZWZhdWx0IjogIiIsCiAgICAgICJpbmZvcm1hdGlvbiI6IHsKICAgICAgICAiZW4iOiAiRnJlZSB0ZXh0IGRhdGEiCiAgICAgIH0KICAgIH0KICBdCn0=" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
{ | ||
"general": { | ||
"name": { "en": "afib1" }, | ||
"version": "1.0.0", | ||
"vendor": "neurodesk", | ||
"information": { "en": "afib1 pipeline." }, | ||
"id": "afib1", | ||
"regulatory_information": { | ||
"device_trade_name":"afib1", | ||
"production_identifier":"1.0.0", | ||
"manufacturer_address":"Erlangen, Germany", | ||
"made_in":"DE", | ||
"manufacture_date":"2023/02/14", | ||
"material_number":"afib1_2.0.0", | ||
"gtin":"00860000171212", | ||
"udi":"(01)00860000171212(21)1.3.0", | ||
"safety_advices":"", | ||
"special_operating_instructions":"Open Recon afib1 pipeline", | ||
"additional_relevant_information":"" | ||
} | ||
}, | ||
"reconstruction": { | ||
"transfer_protocol": { | ||
"protocol": "ISMRMRD", | ||
"version": "1.4.1" | ||
}, | ||
"port": 9002, | ||
"emitter": "image", | ||
"injector": "image", | ||
"can_process_adjustment_data": false, | ||
"can_use_gpu": false, | ||
"min_count_required_gpus": 0, | ||
"min_required_gpu_memory": 2048, | ||
"min_required_memory": 4096, | ||
"min_count_required_cpu_cores": 1, | ||
"content_qualification_type": "PRODUCT" | ||
}, | ||
"parameters": [ | ||
{ | ||
"id": "config", | ||
"label": { "en": "config" }, | ||
"type": "choice", | ||
"values": [ | ||
{ | ||
"id": "invertcontrast", | ||
"name": { "en": "invertcontrast" } | ||
}, | ||
{ | ||
"id": "rgb", | ||
"name": { "en": "rgb" } | ||
}, | ||
{ | ||
"id": "simplefft", | ||
"name": { "en": "simplefft" } | ||
} | ||
], | ||
"default": "invertcontrast", | ||
"information": { "en": "Define the config to be executed by MRD server" } | ||
}, | ||
{ | ||
"id": "customconfig", | ||
"label": { "en":"Custom Config" }, | ||
"type": "string", | ||
"default": "", | ||
"information": { "en": "Custom config file not listed in drop-down menu" } | ||
}, | ||
{ | ||
"id": "options", | ||
"label": { "en": "options" }, | ||
"type": "choice", | ||
"values": [ | ||
{ | ||
"id": "none", | ||
"name": { "en": "none" } | ||
}, | ||
{ | ||
"id": "roi", | ||
"name": { "en": "roi" } | ||
}, | ||
{ | ||
"id": "colormap", | ||
"name": { "en": "colormap" } | ||
} | ||
], | ||
"default": "none", | ||
"information": { "en": "Define additional options" } | ||
}, | ||
{ | ||
"id": "double", | ||
"label": { "en": "double" }, | ||
"type": "double", | ||
"minimum": 0, | ||
"maximum": 100, | ||
"default": 1.0, | ||
"information": { "en": "A double parameter" } | ||
}, | ||
{ | ||
"id": "freetext", | ||
"label": { "en":"freetext" }, | ||
"type": "string", | ||
"default": "", | ||
"information": { "en": "Free text data" } | ||
} | ||
] | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Readme will be converted to PDF |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
|
||
|
||
import json | ||
import jsonschema | ||
import base64 | ||
import os | ||
|
||
# Validate JSON file against OpenRecon schema and write Dockerfile | ||
jsonFilePath = 'OpenReconLabel.json' | ||
schemaFilePath = '../OpenReconSchema_1.1.0.json' | ||
dockerfilePath = 'OpenRecon.dockerfile' | ||
baseDockerImage = 'kpinecbs/afib1' | ||
|
||
def validateJson(jsonFilePath, schemaFilePath): | ||
try: | ||
# Load the JSON data from the file | ||
with open(jsonFilePath, 'r') as jsonFile: | ||
jsonData = json.load(jsonFile) | ||
|
||
# Load the JSON schema from the file | ||
with open(schemaFilePath, 'r') as schemaFile: | ||
schemaData = json.load(schemaFile) | ||
|
||
# Create a JSON Schema validator | ||
validator = jsonschema.Draft7Validator(schemaData) | ||
|
||
# Validate the JSON data against the schema | ||
errors = list(validator.iter_errors(jsonData)) | ||
|
||
if not errors: | ||
print("JSON is valid against the schema.") | ||
return True | ||
else: | ||
print("JSON is not valid against the schema. Errors:") | ||
for error in errors: | ||
print(error) | ||
return False | ||
|
||
except Exception as e: | ||
print(f"An error occurred: {e}") | ||
|
||
# Write Dockerfile | ||
if validateJson(jsonFilePath, schemaFilePath): | ||
with open(jsonFilePath, 'r') as jsonFile: | ||
jsonData = json.load(jsonFile) | ||
jsonString = json.dumps(jsonData, indent=2) | ||
encodedJson = base64.b64encode(jsonString.encode('utf-8')).decode('utf-8') | ||
|
||
with open(dockerfilePath, 'w') as file: | ||
labelName = 'com.siemens-healthineers.magneticresonance.openrecon.metadata:1.1.0' | ||
labelStr = 'LABEL "' + labelName + '"="' + encodedJson + '"' | ||
|
||
file.writelines('FROM ' + baseDockerImage) | ||
file.writelines('\n' + labelStr) | ||
print('Wrote Dockerfile:', os.path.abspath(dockerfilePath)) | ||
else: | ||
raise Exception('Not writing Dockerfile because JSON is not valid') | ||
|
||
# Build Docker image, save to a .tar file, and package into a .zip file for OpenRecon | ||
# The documentation must be a valid PDF! | ||
# README.pdf is autogenerated from README.md, but if it should be overwritten with a dedicated docs.pdf thats's possible | ||
if os.path.isfile('docs.pdf'): | ||
docsFile = 'docs.pdf' | ||
else: | ||
docsFile = 'README.pdf' | ||
|
||
# Filename must match information contained in the JSON | ||
version = jsonData['general']['version'] | ||
vendor = jsonData['general']['vendor'] | ||
name = jsonData['general']['name']['en'] | ||
|
||
# Check documentation file exists | ||
if not os.path.isfile(docsFile): | ||
raise Exception('Could not find documentation file: ' + docsFile) | ||
|
||
# Check 7-zip exists | ||
zipExe = '/usr/bin/7z' | ||
|
||
if not os.path.isfile(zipExe): | ||
raise Exception('Could not find 7-Zip executable: ' + zipExe + '\nPlease download and install 7-Zip') | ||
|
||
dockerImagename = ('OpenRecon_' + vendor + '_' + name + ':' + 'V' + version).lower() | ||
baseFilename = 'OpenRecon_' + vendor + '_' + name + '_V' + version | ||
|
||
import subprocess | ||
import shutil | ||
|
||
try: | ||
# Build Docker image docker buildx build --platform linux/amd64 | ||
print('Attempting to create Docker image with tag:', dockerImagename, '...') | ||
output = subprocess.check_output(['docker', 'buildx', 'build', '--platform', 'linux/amd64', '--no-cache', '--progress=plain', '-t', dockerImagename, '-f', dockerfilePath, './'], stderr=subprocess.STDOUT) | ||
print('Docker build output:\n' + output.decode('utf-8')) | ||
|
||
# Save Docker image to a .tar file | ||
print('Saving Docker image file with name:', baseFilename + '.tar', '...') | ||
output = subprocess.check_output(['docker', 'save', '-o', baseFilename + '.tar', dockerImagename], stderr=subprocess.STDOUT) | ||
print('Docker save output:\n' + output.decode('utf-8')) | ||
|
||
# Copy documentation file with appropriate filename | ||
print('Copying documentation to file with name:', baseFilename + '.pdf', '...') | ||
try: | ||
shutil.copy(docsFile, baseFilename + '.pdf') | ||
print(f'File copied from {docsFile} to {baseFilename}.pdf') | ||
except IOError as e: | ||
print(f'An error occurred: {e}') | ||
|
||
# Zip into a package | ||
print('Packaging files into zip with name:', baseFilename + '.zip', '...') | ||
output = subprocess.check_output([zipExe, 'a', '-tzip', '-mm=Deflate', baseFilename + '.zip', baseFilename + '.tar', baseFilename + '.pdf'], stderr=subprocess.STDOUT) | ||
print('Zip packaging output:\n' + output.decode('utf-8')) | ||
|
||
except subprocess.CalledProcessError as e: | ||
# If the command returns a non-zero exit status, it will raise a CalledProcessError | ||
print('Command failed with return code:', e.returncode) | ||
print('Error output:\n' + e.output.decode('utf-8')) | ||
|