diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..4c49bd7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +.env diff --git a/.example.env b/.example.env new file mode 100644 index 0000000..fc5f7a5 --- /dev/null +++ b/.example.env @@ -0,0 +1,4 @@ +WEBAPP_PORT=8501 +API_PORT=15400 +SHAPES_PATH=/shacl/data/shapes.ttl +SHAPES_URL='https://github.com/sdsc-ordes/imaging-plaza-ontology/releases/download/v0.8/ImagingOntologyCombined.ttl.gz' diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index e16b0bf..0000000 --- a/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM ghcr.io/ashleycaselli/shacl:1.4.3_89205df - - -ENV PYTHONUNBUFFERED=1 - -RUN apk update && apk add \ - bash \ - curl \ - python3 \ - py3-pip \ - py3-pyarrow \ - shadow \ - && rm -rf /var/lib/apt/lists/* - -RUN groupadd --gid 1000 appuser \ - && useradd --uid 1000 --gid 1000 -m appuser - -USER appuser -WORKDIR /shacl -COPY requirements.txt requirements.txt - -RUN pip3 install --break-system-packages -r requirements.txt && \ - pip3 install --break-system-packages python-multipart streamlit rdflib - -COPY ./app app -COPY ./tests tests - -ENV PATH="${PATH}:/home/appuser/.local/bin" - -ENTRYPOINT ["bash", "/shacl/app/entrypoint.sh"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bb51924 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +VERSION = latest +IMAGE = ghcr.io/sdsc-ordes/shacl-api +CONTAINER_RUNTIME ?= docker + +.PHONY: docker-build +docker-build: ## Build Docker images + @echo "🐋 Building docker image" + + $(CONTAINER_RUNTIME) build \ + -f tools/docker/Dockerfile \ + -t $(IMAGE):$(VERSION) \ + --build-arg VERSION=$(VERSION) \ + --target api . + + $(CONTAINER_RUNTIME) build \ + -f tools/docker/Dockerfile \ + -t $(IMAGE):$(VERSION)-webapp \ + --build-arg VERSION=$(VERSION) \ + --target webapp . + +.PHONY: docker-push +docker-push: docker-build ## Push Docker images + @echo "🐋 Pushing docker image" + $(CONTAINER_RUNTIME) push $(IMAGE):$(VERSION) + $(CONTAINER_RUNTIME) push $(IMAGE):$(VERSION)-webapp + +docker-compose-up: ## Run the Docker Compose stack + @echo "🐋 Running docker-compose" + $(CONTAINER_RUNTIME) compose \ + -f tools/docker/compose.yml \ + up --build + +.PHONY: format +format: install ## Format python code + ruff format src + +.PHONY: lint +lint: install ## Lint python code + ruff check src + +.PHONY: install +install: ## Setup project for development + pip install -e '.[webapp,test,dev]' + + +.PHONY: test +test: install ## Run unit tests + pytest + +.PHONY: help +help: + @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' + +.DEFAULT_GOAL := help diff --git a/README.md b/README.md index d0d6648..8823692 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,33 @@ # shaclAPI -Web server wrapping the TopBraid Shacl API tool. -Implementated for Imaging Plaza. +Web server for RDF data validation, wrapping the TopBraid Shacl API tool. Based on https://github.com/SDSC-ORD/shacl ## How to use it? +### With docker -## How to use docker? +We provide a helper make recipe to build two docker images, a small "headless" version with only the REST server, and a larger image that bundles the REST server and a streamlit web application. These two images are differentiated by their tag: `` vs `-webapp`. ``` -docker build -t sdsc-ordes/shacl-api:latest . +make docker-build ``` -``` -docker run -it --rm -p 8000:15400 -p 8501:8501 sdsc-ordes/shacl-api:latest -docker run -it --rm -p 7200:15400 -p 3000:8501 sdsc-ordes/shacl-api:latest -``` +The docker images can be run as follows: ``` -docker-compose up # add -d for detached +# Only REST API +docker run -it --rm -p 8000:15400 sdsc-ordes/shacl-api:latest +# REST API + web server +docker run -it --rm -p 8000:15400 -p 8501:8501 sdsc-ordes/shacl-api:latest-webapp ``` -## LOGS -``` -if [ $1 == validate ] ; then - set -- shaclvalidate.sh "$@" -elif [ $1 == infer ] ; then - set -- shaclinfer.sh "$@" -``` +## With docker compose + +For development, it may be more convenient to use our docker compose stack. ``` -root@cbb169b97823:/# shaclvalidate.sh -Missing -datafile, e.g.: -datafile myfile.ttl -root@cbb169b97823:/# shaclinfer.sh -Missing -datafile, e.g.: -datafile myfile.ttl +make docker-compose-up ``` diff --git a/app/entrypoint.sh b/app/entrypoint.sh deleted file mode 100644 index b907990..0000000 --- a/app/entrypoint.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -nohup streamlit run /shacl/app/webapp/main.py & -python3 -m uvicorn app.main:app --host 0.0.0.0 --port 15400 - diff --git a/app/main.py b/app/main.py deleted file mode 100644 index 9a57b1f..0000000 --- a/app/main.py +++ /dev/null @@ -1,170 +0,0 @@ -from fastapi import FastAPI, Request, Form -from fastapi.responses import JSONResponse -import subprocess -import os -import base64 - -from rdflib import Graph -from rdflib.namespace import Namespace, NamespaceManager - -import json - -app = FastAPI() - -@app.get("/") -def index(): - return {"title": "Hello, welcome to the SHACL API v0.0.5. Compatible with Ontology v0.8."} - -@app.post("/validate-jsonld") -async def validateJsonLD(item: Request, - jsonInput: bool | None = None, - jsonOutput: bool | None = None, - verbose: bool | None = None): - - data = await item.json() - data = data["data"] - if verbose: - print(data) - - if jsonInput: - if verbose: - print("Assuming json") - print(f"Type: {type(data)}") - print("Cleaning newlines") - data = json.dumps(data) - else: - if verbose: - print("Assuming string") - print(f"Type: {type(data)}") - print("Cleaning newlines") - data = data.splitlines() - data = ' '.join(data) - - # This is generating the datafile necesary to run inference. - graph = Graph() - graph.parse(data=data, format="json-ld") - - SCHEMA = Namespace("http://schema.org/") - graph.namespace_manager.bind('schema', SCHEMA, override=True, replace=True) - ttl_input = str(graph.serialize(destination='datafile.ttl',format='turtle')) - - - output = subprocess.run(["shaclvalidate.sh", "-datafile", "datafile.ttl", "-shapesfile", "/app/shapesfile.ttl"], stdout=subprocess.PIPE) - - os.remove("datafile.ttl") - - ### Read and provide JSON-LD - graph = Graph() - graph.parse(data=output.stdout, format="turtle") - SCHEMA = Namespace("http://schema.org/") - graph.namespace_manager.bind('schema', SCHEMA, override=True, replace=True) - jsonld = str(graph.serialize(format='json-ld')) - - if jsonOutput: - jsonld = json.loads(jsonld) - - return {"jsonldOutput": jsonld, - "ttlOutput": output.stdout, - "jsonldInput": data, - "ttlInput": ttl_input} - - -@app.post("/inference-jsonld") -async def inferenceJsonLD(item: Request, - jsonInput: bool | None = None, - jsonOutput: bool | None = None, - verbose: bool | None = None): - - data = await item.json() - data = data["data"] - if verbose: - print(data) - - if jsonInput: - if verbose: - print("Assuming json") - print(f"Type: {type(data)}") - print("Cleaning newlines") - data = json.dumps(data) - else: - if verbose: - print("Assuming string") - print(f"Type: {type(data)}") - print("Cleaning newlines") - data = data.splitlines() - data = ' '.join(data) - - # This is generating the datafile necesary to run inference. - graph = Graph() - graph.parse(data=data, format="json-ld") - - SCHEMA = Namespace("http://schema.org/") - graph.namespace_manager.bind('schema', SCHEMA, override=True, replace=True) - ttl_input= str(graph.serialize(destination='datafile.ttl',format='turtle')) - - output = subprocess.run(["shaclinfer.sh", "-datafile", "datafile.ttl", "-shapesfile", "/app/shapesfile.ttl"], stdout=subprocess.PIPE) - - os.remove("datafile.ttl") - - ### Read and provide JSON-LD - graph = Graph() - graph.parse(data=output.stdout, format="turtle") - SCHEMA = Namespace("http://schema.org/") - graph.namespace_manager.bind('schema', SCHEMA, override=True, replace=True) - jsonld = str(graph.serialize(format='json-ld')) - - if jsonOutput: - jsonld = json.loads(jsonld) - - return {"jsonldOutput": jsonld, - "ttlOutput": output.stdout, - "jsonldInput": data, - "ttlInput": ttl_input} - - - -@app.post("/validate") -def validate(datafile:str=Form(...), - shapesfile:str=Form(...)): - - datafile = base64.b64decode(str.encode(datafile)) - shapesfile = base64.b64decode(str.encode(shapesfile)) - - with open("datafile.ttl", 'wb') as f: - f.write(datafile) - - with open("shapesfile.ttl", 'wb') as f: - f.write(shapesfile) - - output = subprocess.run(["shaclvalidate.sh", "-datafile", "datafile.ttl", "-shapesfile", "shapesfile.ttl"], stdout=subprocess.PIPE) - - os.remove("datafile.ttl") - os.remove("shapesfile.ttl") - with open("validationTest.ttl", 'wb') as f: - f.write(output.stdout) - - return {"output": output.stdout} - - -@app.post("/inference") -def inference(datafile:str=Form(...), - shapesfile:str=Form(...)): - - datafile = base64.b64decode(str.encode(datafile)) - shapesfile = base64.b64decode(str.encode(shapesfile)) - print(datafile) - - with open("datafile.ttl", 'wb') as f: - f.write(datafile) - - with open("shapesfile.ttl", 'wb') as f: - f.write(shapesfile) - - output = subprocess.run(["shaclinfer.sh", "-datafile", "datafile.ttl", "-shapesfile", "shapesfile.ttl"], stdout=subprocess.PIPE) - - os.remove("datafile.ttl") - os.remove("shapesfile.ttl") - with open("validationTest.ttl", 'wb') as f: - f.write(output.stdout) - - return {"output": output.stdout} diff --git a/app/shapesfile.ttl b/app/shapesfile.ttl deleted file mode 100644 index 6a5a4f2..0000000 --- a/app/shapesfile.ttl +++ /dev/null @@ -1,1527 +0,0 @@ -prefix schema: -prefix sd: -prefix bio: -prefix spe: -prefix rdf: -prefix sh: -prefix xsd: -prefix shsh: -prefix owl: -prefix dcterms: -prefix imag: -prefix md4i: -prefix rdfs: -prefix dct: -prefix vann: - - - - a owl:Ontology ; - sh:entailment sh:Rules ; - sh:declare [ - sh:prefix "imag" ; - sh:namespace ; - ] . - imag:fairlevel0Shape a sh:NodeShape - . - - imag:fairlevel1Shape a sh:NodeShape ; - sh:targetClass schema:SoftwareSourceCode ; - sh:property - [sh:path schema:license ; - sh:minCount 1; - sh:message "Fair level 1"] , - - [sh:path schema:citation ; - sh:minCount 1; - sh:message "Fair level 1"] , - - [sh:path schema:description ; - sh:minCount 1; - sh:message "Fair level 1"] , - - [sh:path schema:url ; - sh:minCount 1; - sh:message "Fair level 1"] , - - [sh:path schema:dateCreated ; - sh:minCount 1; - sh:message "Fair level 1"] , - - [sh:path schema:datePublished ; - sh:minCount 1; - sh:message "Fair level 1"] , - - [sh:path schema:image ; - sh:minCount 1; - sh:message "Fair level 1"] - . - - imag:fairlevel2Shape a sh:NodeShape ; - sh:targetClass schema:SoftwareSourceCode ; - sh:property - [sh:path sd:readme ; - sh:minCount 1 ; - sh:message "Fair level 2"] , - - [sh:path schema:programmingLanguage ; - sh:minCount 1 ; - sh:message "Fair level 2"] , - - [sh:path schema:featureList ; - sh:minCount 1 ; - sh:message "Fair level 2"] ; - sh:and (imag:fairlevel1Shape) - . - - imag:fairlevel3Shape a sh:NodeShape ; - sh:targetClass schema:SoftwareSourceCode ; - sh:property - [sh:path schema:softwareRequirements ; - sh:minCount 1 ; - sh:message "Fair level 3"] , - - [sh:path schema:supportingData ; - sh:minCount 1 ; - sh:message "Fair level 3"] ; - sh:and (imag:fairlevel2Shape) - . - - imag:fairlevel4Shape a sh:NodeShape ; - sh:targetClass schema:SoftwareSourceCode ; - sh:property - [sh:path schema:memoryRequirements ; - sh:minCount 1; - sh:message "Fair level 4"] , - - [sh:path sd:hasDocumentation ; - sh:minCount 1; - sh:message "Fair level 4"] , - - [sh:path sd:hasSoftwareImage ; - sh:minCount 1; - sh:message "Fair level 4"] ; - sh:and (imag:fairlevel3Shape) - . - - imag:fairlevel5Shape a sh:NodeShape ; - sh:targetClass schema:SoftwareSourceCode ; - sh:property - [sh:path sd:hasExecutableInstructions ; - sh:minCount 1; - sh:message "Fair level 5"] ; - sh:and (imag:fairlevel4Shape) - . - -imag:FeatureTaggerRule a sh:SPARQLRule ; - sh:name "Feature tagger" ; - sh:description "This shape is used to extend the initial tagging of a software with it's higher level tags, for ease of retrieval/filtering" ; - sh:construct """ - PREFIX rdfs: - PREFIX schema: - CONSTRUCT { - $this schema:featureList ?parentFeatureLabel . - $this schema:featureList ?feature . - } - WHERE { - $this schema:featureList ?feature . - ?featureClass rdfs:label ?feature . - ?featureClass rdfs:subClassOf ?parentFeature. - ?parentFeature rdfs:label ?parentFeatureLabel . - } - """ . - -schema:SoftwareSourceCode -a sh:NodeShape, rdfs:Class ; -sh:property schema:SoftwareApplication-applicationCategory , - schema:CreativeWork-citation , - schema:SoftwareSourceCode-codeRepository , - schema:CreativeWork-conditionsOfAccess , - schema:CreativeWork-dateCreated , - schema:CreativeWork-datePublished , - schema:Thing-description , - schema:SoftwareApplication-featureList , - schema:Thing-image , - schema:CreativeWork-isAccessibleForFree , - schema:CreativeWork-isBasedOn , - imag:isPluginModuleOfShape, - imag:relatedToOrganizationShape, - schema:CreativeWork-license , - schema:CreativeWork-maintainer , - schema:SoftwareApplication-memoryRequirements , - schema:Thing-name , - schema:SoftwareApplication-operatingSystem , - schema:CreativeWork-producer , - schema:SoftwareSourceCode-programmingLanguage , - schema:SoftwareApplication-softwareRequirements , - schema:SoftwareApplication-processorRequirements , - imag:SoftwareApplication-requiresGPUShape , - schema:SoftwareApplication-supportingData , - schema:Thing-url , - schema:Thing-identifier , - sd:SoftwareApplication-hasAcknowledgements , - sd:SoftwareApplication-hasDocumentation , - sd:SoftwareApplication-hasExecutableInstructions , - imag:SoftwareApplication-hasExecutableNotebook , - sd:SoftwareApplication-hasParameter , - sd:SoftwareApplication-readme , - sd:SoftwareApplication-hasFunding , - sd:SoftwareConfiguration-hasSoftwareImage , - imag:SoftwareApplication-imagingModalityShape , - imag:fairLevelShape ; - sh:rule [ - a sh:TripleRule ; - sh:subject sh:this ; - sh:predicate imag:fairLevel ; - sh:object "Fair level 0" ; - sh:condition imag:fairlevel0Shape ]; - sh:rule [ - a sh:TripleRule ; - sh:subject sh:this ; - sh:predicate imag:fairLevel ; - sh:object "Fair level 1" ; - sh:condition imag:fairlevel1Shape ]; - - sh:rule [ - a sh:TripleRule ; - sh:subject sh:this ; - sh:predicate imag:fairLevel ; - sh:object "Fair level 2" ; - sh:condition imag:fairlevel2Shape ; - ] ; - sh:rule [ - a sh:TripleRule ; - sh:subject sh:this ; - sh:predicate imag:fairLevel ; - sh:object "Fair level 3" ; - sh:condition imag:fairlevel3Shape ; - ] ; - sh:rule [ - a sh:TripleRule ; - sh:subject sh:this ; - sh:predicate imag:fairLevel ; - sh:object "Fair level 4" ; - sh:condition imag:fairlevel4Shape - ] ; - sh:rule [ - a sh:TripleRule ; - sh:subject sh:this ; - sh:predicate imag:fairLevel ; - sh:object "Fair level 5" ; - sh:condition imag:fairlevel5Shape - ] ; - sh:rule imag:FeatureTaggerRule ; -. -imag:fairLevelShape a sh:PropertyShape ; - sh:path imag:fairLevel ; - sh:datatype xsd:string ; - sh:minCount 1 ; - . - -imag:SoftwareApplication-imagingModalityShape - a sh:PropertyShape ; - sh:path imag:imagingModality ; - sh:datatype xsd:string ; - . - -schema:SoftwareApplication-applicationCategory - a sh:PropertyShape ; - sh:path schema:applicationCategory ; - sh:datatype xsd:string ; - . -schema:SoftwareApplication-processorRequirements - a sh:PropertyShape ; - sh:path schema:processorRequirements ; - sh:datatype xsd:string ; - sh:in ("ARM64" "AMD64" "None") - . - -imag:SoftwareApplication-requiresGPUShape - a sh:PropertyShape ; - sh:path imag:requiresGPU ; - sh:datatype xsd:boolean . - -schema:CreativeWork-citation - a sh:PropertyShape ; - sh:path schema:citation ; - sh:minCount 1 ; - sh:datatype xsd:string ; - sh:pattern "^http.*" ; -. -schema:SoftwareSourceCode-codeRepository - a sh:PropertyShape ; - sh:path schema:codeRepository ; - sh:pattern "^http.*" ; - sh:minCount 1 ; - sh:maxCount 1 ; -. - -schema:CreativeWork-conditionsOfAccess - a sh:PropertyShape ; - sh:path schema:conditionsOfAccess ; - sh:datatype xsd:string ; - -. - -schema:CreativeWork-dateCreated - a sh:PropertyShape ; - sh:path schema:dateCreated ; - sh:minCount 1 ; - sh:maxCount 1 ; - sh:datatype xsd:date ; - . - -schema:CreativeWork-datePublished - a sh:PropertyShape ; - sh:path schema:datePublished ; - sh:datatype xsd:date ; - sh:minCount 1 ; -. - -schema:Thing-description - a sh:PropertyShape ; - sh:path schema:description ; - sh:datatype xsd:string ; - sh:maxLength 2000 ; - sh:minCount 1 ; -. - -schema:SoftwareApplication-featureList - a sh:PropertyShape ; - sh:path schema:featureList ; - sh:datatype xsd:string ; -. - -schema:Thing-image - a sh:PropertyShape ; - sh:path schema:image ; - sh:class schema:ImageObject ; - sh:minCount 1 ; -. - -schema:ImagingObject - a sh:NodeShape, rdfs:Class ; - sh:property schema:Thing-url ; - sh:property schema:CreativeWork-keywords ; - . - - -schema:CreativeWork-isAccessibleForFree - a sh:PropertyShape ; - sh:path schema:isAccessibleForFree ; - sh:datatype xsd:boolean ; -. - -schema:CreativeWork-isBasedOn - a sh:PropertyShape ; - sh:path schema:isBasedOn ; - sh:pattern "^http.*" ; - . - -imag:isPluginModuleOfShape - a sh:PropertyShape ; - sh:path imag:isPluginModuleOf ; - sh:datatype xsd:string ; - . - -imag:relatedToOrganizationShape - a sh:PropertyShape ; - sh:path imag:relatedToOrganization ; - sh:datatype xsd:string ; - . - -schema:CreativeWork-keywords - a sh:PropertyShape ; - sh:path schema:keywords ; - sh:datatype xsd:string ; - sh:in ("logo" "illustrative image" "before image" "after image") ; - sh:minCount 1 ; - sh:maxCount 1 ; -. - -schema:CreativeWork-license - a sh:PropertyShape ; - sh:path schema:license ; - sh:pattern ".*spdx\\.org.*" ; - sh:minCount 1 ; -. - -schema:CreativeWork-maintainer - a sh:PropertyShape ; - sh:path schema:maintainer ; - sh:minCount 1 ; - sh:or ( - [ - sh:class schema:Organization ; - ] - [ - sh:class schema:Person ; - ] - ) ; -. - -schema:Person -a sh:NodeShape ; - sh:property schema:Thing-name ; - sh:property md4i:orcidIdShape ; - sh:property schema:Person-affiliation -. - -schema:Person-email - a sh:PropertyShape ; - sh:path schema:email ; - sh:datatype xsd:string ; -. - -schema:Person-familyName - a sh:PropertyShape ; - sh:path schema:familyName ; - sh:datatype xsd:string ; - sh:minCount 1 ; - . - -schema:Person-givenName - a sh:PropertyShape ; - sh:path schema:givenName ; - sh:datatype xsd:string ; - sh:minCount 1 ; -. - -md4i:orcidIdShape - a sh:PropertyShape ; - sh:path md4i:orcidId ; - sh:datatype xsd:string ; - . - -schema:Person-affiliation - a sh:PropertyShape ; - sh:path schema:affiliation ; - sh:datatype xsd:string ; -. - -schema:Organization -a sh:NodeShape ; -sh:property schema:Organization-legalName ; -sh:property md4i:hasRorIdShape ; -. - -schema:SoftwareApplication-memoryRequirements - a sh:PropertyShape ; - sh:path schema:memoryRequirements ; - sh:or ( - [sh:datatype xsd:string ] - [sh:hasValue "None"]) -. - -schema:Thing-name - a sh:PropertyShape ; - sh:path schema:name ; - sh:datatype xsd:string ; - sh:minCount 1 ; - sh:maxLength 60 -. - -schema:SoftwareApplication-operatingSystem - a sh:PropertyShape ; - sh:path schema:operatingSystem ; - sh:in ("Linux" "Windows" "MacOS" "Other") ; -. - -schema:CreativeWork-producer - a sh:PropertyShape ; - sh:path schema:producer ; - sh:minCount 1 ; - sh:or ( - [ - sh:class schema:Organization ; - ] - [ - sh:class schema:Person ; - ] - ) ; -. - -schema:SoftwareSourceCode-programmingLanguage - a sh:PropertyShape ; - sh:path schema:programmingLanguage ; - sh:datatype xsd:string ; -. - - -schema:SoftwareApplication-softwareRequirements - a sh:PropertyShape ; - sh:path schema:softwareRequirements ; - sh:datatype xsd:string ; -. - -schema:SoftwareApplication-softwareVersion - a sh:PropertyShape ; - sh:path schema:softwareVersion ; - sh:datatype xsd:string ; - sh:pattern "[0-9]+\\.[0-9]+\\.[0-9]+" ; - sh:minCount 1 ; - . - -schema:SoftwareApplication-supportingData - a sh:PropertyShape ; - sh:path schema:supportingData ; - sh:class schema:DataFeed ; -. - -schema:Thing-url - a sh:PropertyShape ; - sh:path schema:url ; - sh:pattern "^http.*" ; -. - -sd:SoftwareApplication-hasAcknowledgements - a sh:PropertyShape ; - sh:path sd:hasAcknowledgements ; - sh:datatype xsd:string ; - . - -sd:SoftwareApplication-hasDocumentation - a sh:PropertyShape ; - sh:path sd:hasDocumentation ; - sh:pattern "^http.*" ; - . - -sd:SoftwareApplication-hasExecutableInstructions - a sh:PropertyShape ; - sh:path sd:hasExecutableInstructions ; - sh:datatype xsd:string ; - . - -imag:SoftwareApplication-hasExecutableNotebook - a sh:PropertyShape ; - sh:path imag:hasExecutableNotebook ; - sh:class imag:ExecutableNotebook ; - . - -sd:SoftwareApplication-hasParameter - a sh:PropertyShape ; - sh:path sd:hasParameter ; - sh:class bio:FormalParameter ; - . - -sd:SoftwareApplication-readme - a sh:PropertyShape ; - sh:path sd:readme ; - sh:pattern "^http.*" ; - . - -schema:DataFeed - a sh:NodeShape ; - sh:property schema:Thing-description , - schema:DataDownload-contentURL , - schema:Dataset-measurementTechnique , - schema:Thing-name , - schema:Dataset-variableMeasured ; - . - -schema:DataDownload-contentURL - a sh:PropertyShape ; - sh:path schema:contentUrl ; - sh:pattern "^http.*" ; - sh:minCount 1 ; - . - - - -sd:SoftwareApplication-hasFunding - a sh:PropertyShape ; - sh:path sd:hasFunding ; - sh:class sd:FundingInformation ; - . - - -schema:Thing-identifier - a sh:PropertyShape ; - sh:path schema:identifier ; - sh:datatype xsd:string ; - sh:minCount 1 ; -. - -sd:FundingInformation-fundingSource - a sh:PropertyShape ; - sh:path sd:fundingSource ; - sh:class schema:Organization ; - sh:minCount 1 ; - . -sd:FundingInformation-fundingGrant a sh:PropertyShape ; - sh:path sd:fundingGrant ; - sh:datatype xsd:string ; - sh:minCount 1. - -sd:FundingInformation - a sh:NodeShape ; - sh:property schema:Thing-identifier, - sd:FundingInformation-fundingGrant, - sd:FundingInformation-fundingSource ; - . - - - -bio:FormalParameter - a sh:NodeShape ; - sh:property schema:Thing-description , - schema:CreativeWork-encodingFormat, - schema:Thing-name, - sd:DatasetSpecification-hasDimensionality, - sd:DatasetSpecification-hasFormat , - schema:PropertyValueSpecification-defaultValue, - schema:PropertyValueSpecification-valueRequired - . - -schema:CreativeWork-encodingFormat - a sh:PropertyShape ; - sh:path schema:encodingFormat ; - sh:pattern ".*iana.org/assignments/media-types/.*" ; -. - -sd:DatasetSpecification-hasDimensionality - a sh:PropertyShape ; - sh:path sd:hasDimensionality ; - sh:datatype xsd:integer ; - sh:minExclusive 0 ; - . - -sd:DatasetSpecification-hasFormat - a sh:PropertyShape ; - sh:path sd:hasFormat ; - sh:datatype xsd:string ; - . - -schema:PropertyValueSpecification-defaultValue - a sh:PropertyShape ; - sh:path schema:defaultValue ; - sh:datatype xsd:string ; - -. - -schema:PropertyValueSpecification-valueRequired - a sh:PropertyShape ; - sh:path schema:valueRequired ; - sh:datatype xsd:boolean ; -. - -sd:SoftwareConfiguration-hasSoftwareImage - a sh:PropertyShape ; - sh:path sd:hasSoftwareImage ; - sh:class sd:SoftwareImage; - . - -sd:SoftwareImage a sh:NodeShape ; - sh:property schema:Thing-name , - schema:Thing-description , - schema:SoftwareApplication-softwareVersion , - sd:SoftwareImage-availableInRegistry ; - . - -imag:ExecutableNotebook a sh:NodeShape ; - sh:property schema:Thing-name , - schema:Thing-description , - schema:Thing-url . - - - - -sd:SoftwareImage-availableInRegistry - a sh:PropertyShape ; - sh:pattern "^http.*" ; - sh:path sd:availableInRegistry ; - . - -schema:Dataset-measurementTechnique - a sh:PropertyShape ; - sh:path schema:measurementTechnique ; - sh:datatype xsd:string ; -. - -schema:Dataset-variableMeasured - a sh:PropertyShape ; - sh:path schema:variableMeasured ; - sh:datatype xsd:string ; -. - -schema:Organization-legalName - a sh:PropertyShape ; - sh:path schema:legalName ; - sh:datatype xsd:string ; - sh:minCount 1 ; -. - -md4i:hasRorIdShape - a sh:PropertyShape ; - sh:path md4i:hasRorId ; - sh:pattern "^http.*" ; - . - - - a owl:Ontology ; - dct:abstract "The Imaging Plaza ontology provides concepts (classes and properties) to model human and machine readable imaging software metadata. It is the result of re-using external pre-existing vocabularies such as schema.org and the software description ontology, together with custom imaging specific objects and properties." ; - dct:contributor "Robin Franken", "Carlos Vivar Rios" ; - dct:created "2024-04-01"^^xsd:date ; - dct:creator "Robin Franken" ; - dct:description "The Imaging Plaza ontology provides concepts (classes and properties) to model human and machine readable imaging software metadata. It is the result of re-using external pre-existing vocabularies such as schema.org and the software description ontology, together with custom imaging specific objects and properties. The ontology contains purely semantic information (labels, definitions etc.) and is meant to be used in conjuction with a graph of enumeration values and a graph containing SHACL shapes to provide more machine readable restrictions on values of properties." ; - dct:license ; - dct:modified "2024-08-15"^^xsd:date ; - dct:title "Imaging Plaza Ontology" ; - vann:preferredNamespacePrefix "imag" ; - vann:preferredNamespaceUri "https://imaging-plaza.epfl.ch/ontology#"^^xsd:string ; - owl:versionInfo "0.7.0"^^xsd:string - . - -schema:SoftwareSourceCode - a rdfs:Class ; - rdfs:comment "A software application." ; - rdfs:label "Software application" ; - rdfs:subClassOf schema:CreativeWork . - -schema:license a rdf:Property; - rdfs:comment "A license document that applies to this content, typically indicated by URL."; - rdfs:label "License" . - -schema:citation a rdf:Property; - rdfs:comment "A DOI https URL citation to publication about this software. Use Zenodo to generate if needed. e.g. https://doi.org/10.1016/j.procs.2017.03.009"; - rdfs:label "Citation DOI" . - -schema:contentURL a rdf:Property; - rdfs:comment "Actual bytes of the media object, for example the image file or video file."; - rdfs:label "Content URL". - -schema:dateCreated a rdf:Property; - rdfs:comment "The date on which the repository was created."; - rdfs:label "Date created" . - -schema:datePublished a rdf:Property; - rdfs:comment "Latest published git release date, else, the publish date of the doi."; - rdfs:label "Date published" . - -schema:maintainer a rdf:Property; - rdfs:comment "A maintainer of a Dataset, software package or other Project. A maintainer is a Person or Organization that manages contributions to, and/or publication of, some (typically complex) artifact."; - rdfs:label "Maintainer" . - -schema:memoryRequirements a rdf:Property; - rdfs:comment "Minimum RAM requirements in GB to run the software, 0 if not applicable."; - rdfs:label "Memory requirements" . - -imag:fairLevel a rdf:Property; - rdfs:comment "A score of 1-5 rating the Findability, Accessibility, Interoperability and Reusability of a piece of software based on the presence of certain properties for an instance of software"; - rdfs:label "FAIR Level" . - -schema:affiliation a rdf:Property; - rdfs:comment "An organization that this person is affiliated with. For example, a university (EPFL/ETHZ), lab, company." ; - rdfs:label "Affiliation". - -schema:applicationCategory a rdf:Property; - rdfs:comment "Type of software application, e.g. 'Plugin, gui, desktop app, library'."; - rdfs:label "Application category" . - -schema:codeRepository a rdf:Property; - rdfs:comment "Primary link to the repository where the un-compiled, human readable code and related code is located (GitLab, GitHub, CodePlex etc.)."; - rdfs:label "Code repository" . - -schema:conditionsOfAccess a rdf:Property; - rdfs:comment "Conditions that affect the availability of, or method(s) of access to, an item. e.g. log-in required "; - rdfs:label "Conditions of access" . - -schema:description a rdf:Property; - rdfs:comment "A description of the item."; - rdfs:label "Description" . - -schema:featureList a rdf:Property; - rdfs:comment "Features or modules provided by this application (and possibly required by other applications)."; - rdfs:label "Feature list" . - -schema:image a rdf:Property; - rdfs:comment "An image of the item."; - rdfs:label "Image" . - -schema:isAccessibleForFree a rdf:Property; - rdfs:comment "A flag to signal that the item, event, or place is accessible for free."; - rdfs:label "Is accessible for free" . - -schema:isBasedOn a rdf:Property; - rdfs:comment "A resource from which this work is derived or from which it is a modification or adaption."; - rdfs:label "Is based on" . - -imag:isPluginModuleOf a rdf:Property; - rdfs:comment "The resource for which this tool is a plugin or module." ; - rdfs:label "Is plugin/module of" . - -imag:relatedToOrganization a rdf:Property ; - rdfs:comment "The lab/institution/group/project/organization to which a software is related and/or affiliated to" ; - rdfs:label "Related to organization" . - -schema:familyName a rdf:Property; - rdfs:comment "Family name. In the U.S., the last name of a Person."; - rdfs:label "Family name" . - -schema:givenName a rdf:Property; - rdfs:comment "Given name. In the U.S., the first name of a Person."; - rdfs:label "Given name" . - -schema:name a rdf:Property; - rdfs:comment "The name of a person, in the US their first and last name(s) seperated by spaces"; - rdfs:label "Name" . - -md4i:orcidId a rdf:Property ; - rdfs:comment "The ORCID ID of a person" ; - rdfs:label "Has ORCID ID" . - -md4i:hasRorId a rdf:Property ; - rdfs:comment "A Research Organization Registry identifier, that points to a research organization" ; - rdfs:label "Has ROR ID" . - -schema:legalName a rdf:Property; - rdfs:comment "The official name of the organization, e.g. the registered company name."; - rdfs:label "Legal name" . - -schema:operatingSystem a rdf:Property; - rdfs:comment "Operating systems supported (Windows 7/10/11, OS X 10.6, Android 1.6)."; - rdfs:label "Operating system" . - -schema:producer a rdf:Property; - rdfs:comment "The person or organization who produced the work (e.g. music album, movie, TV/radio series etc.)."; - rdfs:label "Producer" . - -schema:programmingLanguage a rdf:Property; - rdfs:comment "The computer programming language."; - rdfs:label "Programming Language" . - -schema:softwareRequirements a rdf:Property; - rdfs:comment "Special third party dependencies (e.g. CUDA, Tensorflow etc. related requirements)."; - rdfs:label "Software requirements" . - -schema:softwareVersion a rdf:Property; - rdfs:comment "Version of the software instance."; - rdfs:label "Software version" . - -schema:url a rdf:Property; - rdfs:comment "Fill in any URL related to this repository. e.g. related lab or project website."; - rdfs:label "URL" . - -schema:identifier a rdf:Property; - rdfs:comment "Represents any kind of unique string to identify something, such as ISBNs, GTIN codes, UUIDs etc."; - rdfs:label "Identifier" . - -schema:defaultValue a rdf:Property; - rdfs:comment "The default value of the input. For properties that expect a literal, the default is a literal value, for properties that expect an object, it's an ID reference to one of the current values."; - rdfs:label "Default value" . - -schema:valueRequired a rdf:Property; - rdfs:comment "Whether the property must be filled in to complete the action. Default is false."; - rdfs:label "Value required" . - -schema:supportingData a rdf:Property; - rdfs:comment "Supporting data for a SoftwareApplication."; - rdfs:label "Supporting data" . - -schema:distribution a rdf:Property; - rdfs:comment "A downloadable form of this dataset, at a specific location, in a specific format." ; - rdfs:label "Distribution" . - -schema:encodingFormat a rdf:Property; - rdfs:comment "Expressed using a MIME format (http://www.iana.org/assignments/media-types/media-types.xhtml)."; - rdfs:label "Encoding format" . - -schema:measurementTechnique a rdf:Property; - rdfs:comment "A technique or technology used in a Dataset corresponding to the method used for measuring the corresponding variable(s)." ; - rdfs:label "Measurement technique" . - -schema:variableMeasured a rdf:Property; - rdfs:comment "The variables that are measured in some dataset, described as text."; - rdfs:label "Variable measured" . - -imag:imagingModality a rdf:Property; - rdfs:comment "Technique or method used to create images of the interior of a body or an object for which this software was designed."; - rdfs:label "Imaging modality" . - -schema:keywords a rdf:Property; - rdfs:comment "The keywords/tags used to describe this content."@en; - rdfs:label "Keywords"@en . - -imag:requiresGPU a rdf:Property; - rdfs:comment "Stipulates whether something requires a graphical processing unit such as a NVIDEA or AMD graphics card"; - rdfs:label "Requires GPU" . - -schema:processorRequirements a rdf:Property; - rdfs:comment "Processor architecture required to run the application."; - rdfs:label "Processor requirements" . - -sd:hasInput a rdf:Property; - rdfs:comment "Property that links a model configuration to the input types expected by it."@en; - rdfs:label "Has input"@en . - -sd:hasOutput a rdf:Property; - rdfs:comment "Property that expresses what the outputs of a model are"@en; - rdfs:label "Has output"@en . - -sd:hasParameter a rdf:Property; - rdfs:comment "Property that indicates the parameters of a model configuration"@en; - rdfs:label "Has parameter"@en . - -sd:hasFunding a rdf:Property; - rdfs:comment "Property that links a software project to its funding information"@en; - rdfs:label "Has funding information"@en . - -sd:hasSoftwareImage a rdf:Property; - rdfs:comment "Function to link a function with its corresponding container"@en; - rdfs:label "Has software image"@en . - -sd:fundingSource a rdf:Property; - rdfs:comment "Link to an organization funding a software/component"@en; - rdfs:label "Funding source"@en; - rdfs:subPropertyOf owl:topObjectProperty . - -sd:readme a rdf:Property; - rdfs:comment "URL to the Readme file of a software component"@en; - rdfs:label "Readme"@en; - rdfs:subPropertyOf . - -sd:hasDocumentation a rdf:Property; - rdfs:comment "Pointer to the documentation of the model"@en; - rdfs:label "Has documentation"@en . - -sd:hasExecutableInstructions a rdf:Property; - rdfs:comment "URL to Human-readable instructions that indicate how a software component should be executed."@en; - rdfs:label "Has executable instructions"@en . - -imag:hasExecutableNotebook a rdf:Property; - rdfs:comment "Property that links a software component with an executable notebook (e.g., Jupyter notebook)."@en; - rdfs:label "Has executable notebook"@en . - -sd:hasAcknowledgements a rdf:Property; - rdfs:comment "String with the people, organizations and other contributors acknowledged by the authors."@en; - rdfs:label "Has acknowledgements"@en . - -sd:fundingGrant a rdf:Property; - rdfs:comment "Grant number used for funding"@en; - rdfs:label "Funding grant"@en; - rdfs:subPropertyOf . - -sd:hasFormat a rdf:Property; - rdfs:comment "Format followed by a file. For example, txt, nc, etc."@en; - rdfs:label "Has format"@en . - -sd:availableInRegistry a rdf:Property; - rdfs:comment "URL to registry of where software image can be found. For example, https://hub.docker.com/r/pytorch/pytorch"@en; - rdfs:label "Available in registry"@en . - -sd:hasDimensionality a rdf:Property; - rdfs:comment "Property to indicate dimensionality of the input or output of a dataset specification"@en; - rdfs:label "Has dimensionality"@en . - - -#_________________________________________# - - - -schema:Person - a rdfs:Class ; - rdfs:comment "A person (alive, dead, undead, or fictional)." ; - rdfs:label "Person" ; - rdfs:subClassOf schema:Thing ; - owl:equivalentClass ; -. - -schema:Organization - a rdfs:Class ; - rdfs:comment "An organization such as a school, NGO, corporation, club, etc." ; - rdfs:label "Organization" ; - rdfs:subClassOf schema:Thing ; -. - -schema:ComputerLanguage - a rdfs:Class ; - rdfs:comment "This type covers computer programming languages such as Scheme and Lisp, as well as other language-like computer representations. Natural languages are best represented with the Language type." ; - rdfs:label "Computer language" ; - rdfs:subClassOf schema:Intangible ; -. - - -schema:DataFeed - a rdfs:Class ; - rdfs:comment "A single feed providing structured information about one or more entities or topics." ; - rdfs:label "Data feed" ; - rdfs:subClassOf schema:Dataset ; -. - - -schema:Grant - a rdfs:Class ; - rdfs:comment "A grant, typically financial or otherwise quantifiable, of resources." ; - rdfs:label "Grant" ; - rdfs:subClassOf schema:Intangible ; -. - -sd:FundingInformation a rdfs:Class ; - rdfs:comment "A class to represent the funding information of a software project"@en ; - rdfs:label "Funding Information"@en ; - . - - -sd:DatasetSpecification a rdfs:Class ; - rdfs:subClassOf ; - rdfs:comment "Class designed to describe a type of input or output used or produced by a model. For example, Topoflow has several inputs. One of them is a text file with precipitation values. The representation of this input is an instance of a dataset specification."@en ; - rdfs:label "Dataset Specification"@en ; - . - -bio:FormalParameter a rdfs:Class ; - rdfs:subClassOf ; - rdfs:comment "A FormalParameter is an identified variable used to stand for the actual value(s) that are consumed/produced by a set of steps"@en ; - rdfs:label "Formal Parameter"@en ; - - . -imag:ExecutableNotebook a rdfs:Class ; - rdfs:comment "An object representing an executable notebook such as Jupyter Notebook" ; - rdfs:label "Executable Notebook"@en ; - . - -sd:SoftwareImage - a rdfs:Class ; - rdfs:subClassOf sd:Software ; - rdfs:comment "An image that virtualizes the functionality of a given software. For example, a Docker container."@en ; - rdfs:label "Software Image"@en ; - . - - - -imag:EnumerationType a rdfs:Class ; - rdfs:subClassOf schema:Enumeration ; - rdfs:comment "EnumerationType class used to group all enumeration classes under" ; - rdfs:label "Enumeration Type" ; -. - -imag:ImagingModalityEnum a rdfs:Class ; - rdfs:comment "Enumeration class for imaging modality" ; - rdfs:label "Imaging Modality Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:MRI a imag:ImagingModalityEnum ; - rdfs:label "MRI" ; -. - -imag:CAT a imag:ImagingModalityEnum ; - rdfs:label "CAT" ; -. - -imag:XRay a imag:ImagingModalityEnum ; - rdfs:label "X-ray" ; -. - -imag:Any a imag:ImagingModalityEnum ; - rdfs:label "Any" ; -. - -imag:AffiliationEnum a rdfs:Class ; - rdfs:comment "Enumeration class for affiliation" ; - rdfs:label "Affiliation Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:EPFL a imag:AffiliationEnum ; - rdfs:label "EPFL" ; -. - -imag:UNIL a imag:AffiliationEnum ; - rdfs:label "UNIL" ; -. - -imag:ETHZ a imag:AffiliationEnum ; - rdfs:label "ETHZ" ; -. - -imag:UZH a imag:AffiliationEnum ; - rdfs:label "UZH" ; -. - -imag:NoneAffiliation a imag:AffiliationEnum ; - rdfs:label "None" ; -. - -imag:IsPluginModuleOfEnum a rdfs:Class ; - rdfs:comment "Enumeration class for plugin module" ; - rdfs:label "Plugin Module Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:Fiji a imag:IsPluginModuleOfEnum ; - rdfs:label "Fiji" ; -. - -imag:Napari a imag:IsPluginModuleOfEnum ; - rdfs:label "napari" ; -. - -imag:Icy a imag:IsPluginModuleOfEnum ; - rdfs:label "icy" ; -. - -imag:QuPath a imag:IsPluginModuleOfEnum ; - rdfs:label "qupath" ; -. - -imag:OMERO a imag:IsPluginModuleOfEnum ; - rdfs:label "OMERO" ; -. - -imag:Pyxu a imag:IsPluginModuleOfEnum ; - rdfs:label "pyxu" ; -. - -imag:NonePluginModule a imag:IsPluginModuleOfEnum ; - rdfs:label "None" ; -. - -imag:ApplicationCategoryEnum a rdfs:Class ; - rdfs:comment "Enumeration class for application category" ; - rdfs:label "Application Category Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:DesktopApp a imag:ApplicationCategoryEnum ; - rdfs:label "Desktop app" ; -. - -imag:Plugin a imag:ApplicationCategoryEnum ; - rdfs:label "Plugin" ; -. - -imag:WebApp a imag:ApplicationCategoryEnum ; - rdfs:label "Web app" ; -. - -imag:Notebook a imag:ApplicationCategoryEnum ; - rdfs:label "Notebook" ; -. - -imag:Library a imag:ApplicationCategoryEnum ; - rdfs:label "Library" ; -. - -imag:ImageObjectTagEnum a rdfs:Class ; - rdfs:comment "Enumeration class for image object tag" ; - rdfs:label "Image Object Tag Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:Logo a imag:ImageObjectTagEnum ; - rdfs:label "logo" ; -. - -imag:IllustrativeImage a imag:ImageObjectTagEnum ; - rdfs:label "illustrative image" ; -. - -imag:BeforeImage a imag:ImageObjectTagEnum ; - rdfs:label "before image" ; -. - -imag:AfterImage a imag:ImageObjectTagEnum ; - rdfs:label "after image" ; -. - -imag:AnimatedImage a imag:ImageObjectTagEnum ; - rdfs:label "animated image" ; -. - -imag:OperatingSystemEnum a rdfs:Class ; - rdfs:comment "Enumeration class for operating system" ; - rdfs:label "Operating System Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:Windows a imag:OperatingSystemEnum ; - rdfs:label "Windows" ; -. - -imag:Linux a imag:OperatingSystemEnum ; - rdfs:label "Linux" ; -. - -imag:MacOS a imag:OperatingSystemEnum ; - rdfs:label "MacOS" ; -. - -imag:OtherOS a imag:OperatingSystemEnum ; - rdfs:label "Other" ; -. - -imag:ProcessorRequirementsEnum a rdfs:Class ; - rdfs:comment "Enumeration class for processor requirements" ; - rdfs:label "Processor Requirements Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:ARM64 a imag:ProcessorRequirementsEnum ; - rdfs:label "ARM64" ; -. - -imag:AMD64 a imag:ProcessorRequirementsEnum ; - rdfs:label "AMD64" ; -. - -imag:NoneProcessorRequirement a imag:ProcessorRequirementsEnum ; - rdfs:label "None" ; -. - -imag:FeatureEnum a rdfs:Class ; - rdfs:comment "Enumeration class for software features" ; - rdfs:label "Feature Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:Annotation a imag:FeatureEnum ; - rdfs:label "Annotation" ; -. - -imag:Labelling a imag:FeatureEnum ; - rdfs:label "Labelling" ; -. - -imag:Drawing a imag:FeatureEnum ; - rdfs:label "Drawing" ; -. - -imag:OpticalFlow a imag:FeatureEnum ; - rdfs:label "Optical flow" ; -. - -imag:DigitalImageCorrelation a imag:FeatureEnum ; - rdfs:label "Digital image correlation" ; -. - -imag:MotionEstimation a imag:FeatureEnum ; - rdfs:label "Motion estimation" ; -. - -imag:Registration a imag:FeatureEnum ; - rdfs:label "Registration" ; -. - -imag:Stitching a imag:FeatureEnum ; - rdfs:label "Stitching" ; -. - -imag:DriftCorrection a imag:FeatureEnum ; - rdfs:label "Drift correction" ; -. - -imag:Denoising a imag:FeatureEnum ; - rdfs:label "Denoising" ; -. - -imag:Deblurring a imag:FeatureEnum ; - rdfs:label "Deblurring" ; -. - -imag:Smoothing a imag:FeatureEnum ; - rdfs:label "Smoothing" ; -. - -imag:Deconvolution a imag:FeatureEnum ; - rdfs:label "Deconvolution" ; -. - -imag:Preprocessing a imag:FeatureEnum ; - rdfs:label "Preprocessing" ; -. - -imag:Filtering a imag:FeatureEnum ; - rdfs:label "Filtering" ; -. - -imag:ImageSimplification a imag:FeatureEnum ; - rdfs:label "Image simplification" ; -. - -imag:ImageEnhancement a imag:FeatureEnum ; - rdfs:label "Image enhancement" ; -. - -imag:Segmentation a imag:FeatureEnum ; - rdfs:label "Segmentation" ; -. - -imag:Classification a imag:FeatureEnum ; - rdfs:label "Classification" ; -. - -imag:ObjectDetection a imag:FeatureEnum ; - rdfs:label "Object detection" ; -. - -imag:ObjectRecognition a imag:FeatureEnum ; - rdfs:label "Object recognition" ; -. - -imag:Clustering a imag:FeatureEnum ; - rdfs:label "Clustering" ; -. - -imag:Grouping a imag:FeatureEnum ; - rdfs:label "Grouping" ; -. - -imag:PatternRecognition a imag:FeatureEnum ; - rdfs:label "Pattern recognition" ; -. - -imag:TemplateMatching a imag:FeatureEnum ; - rdfs:label "Template matching" ; -. - -imag:InstanceSegmentation a imag:FeatureEnum ; - rdfs:label "Instance segmentation" ; -. - -imag:PixelClassification a imag:FeatureEnum ; - rdfs:label "Pixel classification" ; -. - -imag:FeatureExtraction a imag:FeatureEnum ; - rdfs:label "Feature extraction" ; -. - -imag:DimensionalityReduction a imag:FeatureEnum ; - rdfs:label "Dimensionality reduction" ; -. - -imag:DirectionalImageAnalysis a imag:FeatureEnum ; - rdfs:label "Directional image analysis" ; -. - -imag:PoseEstimation a imag:FeatureEnum ; - rdfs:label "Pose estimation" ; -. - -imag:PoseInformation a imag:FeatureEnum ; - rdfs:label "Pose information" ; -. - -imag:PoseDetection a imag:FeatureEnum ; - rdfs:label "Pose detection" ; -. - -imag:OrientationAnalysis a imag:FeatureEnum ; - rdfs:label "Orientation analysis" ; -. - -imag:SceneReconstruction a imag:FeatureEnum ; - rdfs:label "Scene reconstruction" ; -. - -imag:Reconstruction3d a imag:FeatureEnum ; - rdfs:label "3d reconstruction" ; -. - -imag:ModelGeneration3d a imag:FeatureEnum ; - rdfs:label "3d model generation" ; -. - -imag:MorphologicalReconstruction a imag:FeatureEnum ; - rdfs:label "Morphological reconstruction" ; -. - -imag:DepthEstimation a imag:FeatureEnum ; - rdfs:label "Depth estimation" ; -. - -imag:CurvatureEstimation a imag:FeatureEnum ; - rdfs:label "Curvature estimation" ; -. - -imag:ShadingEstimation a imag:FeatureEnum ; - rdfs:label "Shading estimation" ; -. - -imag:Modelling a imag:FeatureEnum ; - rdfs:label "Modelling" ; -. - -imag:Simulation a imag:FeatureEnum ; - rdfs:label "Simulation" ; -. - -imag:Visualization a imag:FeatureEnum ; - rdfs:label "Visualization" ; -. - -imag:Rendering a imag:FeatureEnum ; - rdfs:label "Rendering" ; -. - -imag:StatisticsMeasurement a imag:FeatureEnum ; - rdfs:label "Statistics measurement" ; -. - -imag:QualityMetricMeasurement a imag:FeatureEnum ; - rdfs:label "Quality metric measurement" ; -. - -imag:DistributionMeasurements a imag:FeatureEnum ; - rdfs:label "Distribution measurements" ; -. - -imag:ImageQualityAssessment a imag:FeatureEnum ; - rdfs:label "Image quality assessment" ; -. - -imag:MeshGeneration a imag:FeatureEnum ; - rdfs:label "Mesh generation" ; -. - -imag:Voxelization a imag:FeatureEnum ; - rdfs:label "Voxelization" ; -. - -imag:SurfaceParameterisation a imag:FeatureEnum ; - rdfs:label "Surface parameterisation" ; -. - -imag:MorphologicalAnalysis a imag:FeatureEnum ; - rdfs:label "Morphological analysis" ; -. - -imag:FeatureDetection a imag:FeatureEnum ; - rdfs:label "Feature detection" ; -. - -imag:Tracking a imag:FeatureEnum ; - rdfs:label "Tracking" ; -. - -imag:VisualQuestionAnswering a imag:FeatureEnum ; - rdfs:label "Visual question answering" ; -. - -imag:SoftwareRequirementsEnum a rdfs:Class ; - rdfs:comment "Enumeration class for software requirements" ; - rdfs:label "Software Requirements Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:PyTorch_2_2 a imag:SoftwareRequirementsEnum ; - rdfs:label "PyTorch 2.2" ; -. - -imag:PyTorch_2_1 a imag:SoftwareRequirementsEnum ; - rdfs:label "PyTorch 2.1" ; -. - -imag:PyTorch_2_0 a imag:SoftwareRequirementsEnum ; - rdfs:label "PyTorch 2.0" ; -. - -imag:PyTorch_1_13 a imag:SoftwareRequirementsEnum ; - rdfs:label "PyTorch 1.13" ; -. - -imag:Tensorflow_2_15 a imag:SoftwareRequirementsEnum ; - rdfs:label "Tensorflow 2.15" ; -. - -imag:Tensorflow_2_4 a imag:SoftwareRequirementsEnum ; - rdfs:label "Tensorflow 2.4" ; -. - -imag:Tensorflow_2_2 a imag:SoftwareRequirementsEnum ; - rdfs:label "Tensorflow 2.2" ; -. - -imag:Tensorflow_2_0 a imag:SoftwareRequirementsEnum ; - rdfs:label "Tensorflow 2.0" ; -. - -imag:Tensorflow_1_8 a imag:SoftwareRequirementsEnum ; - rdfs:label "Tensorflow 1.8" ; -. - -imag:Tensorflow_1_5 a imag:SoftwareRequirementsEnum ; - rdfs:label "Tensorflow 1.5" ; -. - -imag:Tensorflow_1_4 a imag:SoftwareRequirementsEnum ; - rdfs:label "Tensorflow 1.4" ; -. - -imag:CUDA_11_8 a imag:SoftwareRequirementsEnum ; - rdfs:label "CUDA 11.8" ; -. - -imag:CUDA_12_1 a imag:SoftwareRequirementsEnum ; - rdfs:label "CUDA 12.1" ; -. - -imag:CUDA_10_1 a imag:SoftwareRequirementsEnum ; - rdfs:label "CUDA 10.1" ; -. - -imag:CUDA_9_0 a imag:SoftwareRequirementsEnum ; - rdfs:label "CUDA 9.0" ; -. - -imag:NoneSoftwareRequirement a imag:SoftwareRequirementsEnum ; - rdfs:label "None" ; -. - -imag:ComputerLanguageEnum a rdfs:Class ; - rdfs:comment "Enumeration class for computer languages" ; - rdfs:label "Computer Language Enumeration" ; - rdfs:subClassOf imag:EnumerationType ; -. - -imag:Python a imag:ComputerLanguageEnum ; - rdfs:label "Python" ; -. - -imag:Scala a imag:ComputerLanguageEnum ; - rdfs:label "Scala" ; -. - -imag:Java a imag:ComputerLanguageEnum ; - rdfs:label "Java" ; -. - -imag:JavaScript a imag:ComputerLanguageEnum ; - rdfs:label "JavaScript" ; -. - -imag:GoLang a imag:ComputerLanguageEnum ; - rdfs:label "GoLang" ; -. - -imag:Csharp a imag:ComputerLanguageEnum ; - rdfs:label "C#" ; -. - -imag:C a imag:ComputerLanguageEnum ; - rdfs:label "C" ; -. - -imag:Bash a imag:ComputerLanguageEnum ; - rdfs:label "bash" ; -. - -imag:Shell a imag:ComputerLanguageEnum ; - rdfs:label "shell" ; -. - -imag:R a imag:ComputerLanguageEnum ; - rdfs:label "R" ; -. - -imag:Rust a imag:ComputerLanguageEnum ; - rdfs:label "Rust" ; -. - -imag:Cplusplus a imag:ComputerLanguageEnum ; - rdfs:label "C++" ; -. - -imag:MatLab a imag:ComputerLanguageEnum ; - rdfs:label "MATLAB" ; -. diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index fd44f7d..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: '3' -services: - core_api: - build: . - container_name: "shacl-api" - ports: - - "8000:15400" - volumes: - - ./app/:/shacl/app diff --git a/bench/example.json b/examples/data/example.json similarity index 100% rename from bench/example.json rename to examples/data/example.json diff --git a/bench/example.ttl b/examples/data/example.ttl similarity index 100% rename from bench/example.ttl rename to examples/data/example.ttl diff --git a/bench/test.json b/examples/data/test.json similarity index 100% rename from bench/test.json rename to examples/data/test.json diff --git a/bench/SPAQLrequests.ipynb b/examples/notebooks/SPAQLrequests.ipynb similarity index 100% rename from bench/SPAQLrequests.ipynb rename to examples/notebooks/SPAQLrequests.ipynb diff --git a/bench/SPARQLConstructor.ipynb b/examples/notebooks/SPARQLConstructor.ipynb similarity index 100% rename from bench/SPARQLConstructor.ipynb rename to examples/notebooks/SPARQLConstructor.ipynb diff --git a/bench/jsonld-ttl.ipynb b/examples/notebooks/jsonld-ttl.ipynb similarity index 100% rename from bench/jsonld-ttl.ipynb rename to examples/notebooks/jsonld-ttl.ipynb diff --git a/bench/requests.ipynb b/examples/notebooks/requests.ipynb similarity index 100% rename from bench/requests.ipynb rename to examples/notebooks/requests.ipynb diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..cd7abf5 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,45 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "shacl-api" +version = "0.1.0" +authors = [ + { name="Swiss Data Science Center", email="contact@datascience.ch" }, +] +description = "Web service for the TopBraid SHACL validator." +readme = "README.md" +requires-python = ">=3.11" +classifiers = [ + "Programming Language :: Python :: 3", + "Operating System :: OS Independent", +] +license = "AGPL-3.0" +license-files = ["LICEN[CS]E*"] + +dependencies = [ + "fastapi", + "python-multipart", + "rdflib", + "uvicorn", +] + +[project.urls] +Homepage = "https://github.com/sdsc-ordes/shacl-api" +Issues = "https://github.com/sdsc-ordes/shacl-api/issues" + +[project.optional-dependencies] +dev = [ + "ruff", + "pre-commit", +] +test = [ + "pytest", +] +webapp = [ + "streamlit", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/shacl-api"] diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index d1f80a3..0000000 --- a/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -uvicorn -fastapi \ No newline at end of file diff --git a/src/shacl-api/server.py b/src/shacl-api/server.py new file mode 100644 index 0000000..9dacc6c --- /dev/null +++ b/src/shacl-api/server.py @@ -0,0 +1,194 @@ +from fastapi import FastAPI, Request, Form +import subprocess +import os +import base64 + +from rdflib import Graph +from rdflib.namespace import Namespace + +import json + +app = FastAPI() +SHAPES_PATH = os.getenv("SHAPES_PATH", "shapesfile.ttl") + + +@app.get("/") +def index(): + return { + "title": "Hello, welcome to the SHACL API v0.0.5. Compatible with Ontology v0.8." + } + + +@app.post("/validate-jsonld") +async def validateJsonLD( + item: Request, + jsonInput: bool | None = None, + jsonOutput: bool | None = None, + verbose: bool | None = None, +): + data = await item.json() + data = data["data"] + if verbose: + print(data) + + if jsonInput: + if verbose: + print("Assuming json") + print(f"Type: {type(data)}") + print("Cleaning newlines") + data = json.dumps(data) + else: + if verbose: + print("Assuming string") + print(f"Type: {type(data)}") + print("Cleaning newlines") + data = data.splitlines() + data = " ".join(data) + + # This is generating the datafile necesary to run inference. + graph = Graph() + graph.parse(data=data, format="json-ld") + + SCHEMA = Namespace("http://schema.org/") + graph.namespace_manager.bind("schema", SCHEMA, override=True, replace=True) + ttl_input = str(graph.serialize(destination="datafile.ttl", format="turtle")) + + output = subprocess.run( + ["shaclvalidate.sh", "-datafile", "datafile.ttl", "-shapesfile", SHAPES_PATH], + stdout=subprocess.PIPE, + ) + + os.remove("datafile.ttl") + + ### Read and provide JSON-LD + graph = Graph() + graph.parse(data=output.stdout, format="turtle") + SCHEMA = Namespace("http://schema.org/") + graph.namespace_manager.bind("schema", SCHEMA, override=True, replace=True) + jsonld = str(graph.serialize(format="json-ld")) + + if jsonOutput: + jsonld = json.loads(jsonld) + + return { + "jsonldOutput": jsonld, + "ttlOutput": output.stdout, + "jsonldInput": data, + "ttlInput": ttl_input, + } + + +@app.post("/inference-jsonld") +async def inferenceJsonLD( + item: Request, + jsonInput: bool | None = None, + jsonOutput: bool | None = None, + verbose: bool | None = None, +): + data = await item.json() + data = data["data"] + if verbose: + print(data) + + if jsonInput: + if verbose: + print("Assuming json") + print(f"Type: {type(data)}") + print("Cleaning newlines") + data = json.dumps(data) + else: + if verbose: + print("Assuming string") + print(f"Type: {type(data)}") + print("Cleaning newlines") + data = data.splitlines() + data = " ".join(data) + + # This is generating the datafile necesary to run inference. + graph = Graph() + graph.parse(data=data, format="json-ld") + + SCHEMA = Namespace("http://schema.org/") + graph.namespace_manager.bind("schema", SCHEMA, override=True, replace=True) + ttl_input = str(graph.serialize(destination="datafile.ttl", format="turtle")) + + output = subprocess.run( + ["shaclinfer.sh", "-datafile", "datafile.ttl", "-shapesfile", "SHAPES_PATH"], + stdout=subprocess.PIPE, + ) + + os.remove("datafile.ttl") + + ### Read and provide JSON-LD + graph = Graph() + graph.parse(data=output.stdout, format="turtle") + SCHEMA = Namespace("http://schema.org/") + graph.namespace_manager.bind("schema", SCHEMA, override=True, replace=True) + jsonld = str(graph.serialize(format="json-ld")) + + if jsonOutput: + jsonld = json.loads(jsonld) + + return { + "jsonldOutput": jsonld, + "ttlOutput": output.stdout, + "jsonldInput": data, + "ttlInput": ttl_input, + } + + +@app.post("/validate") +def validate(datafile: str = Form(...), shapesfile: str = Form(...)): + datafile = base64.b64decode(str.encode(datafile)) + shapesfile = base64.b64decode(str.encode(shapesfile)) + + # TODO: use tempfile package + with open("datafile.ttl", "wb") as f: + f.write(datafile) + + with open("shapesfile.ttl", "wb") as f: + f.write(shapesfile) + + output = subprocess.run( + [ + "shaclvalidate.sh", + "-datafile", + "datafile.ttl", + "-shapesfile", + "shapesfile.ttl", + ], + stdout=subprocess.PIPE, + ) + + os.remove("datafile.ttl") + os.remove("shapesfile.ttl") + with open("validationTest.ttl", "wb") as f: + f.write(output.stdout) + + return {"output": output.stdout} + + +@app.post("/inference") +def inference(datafile: str = Form(...), shapesfile: str = Form(...)): + datafile = base64.b64decode(str.encode(datafile)) + shapesfile = base64.b64decode(str.encode(shapesfile)) + print(datafile) + + # TODO: use tempfile package + with open("datafile.ttl", "wb") as f: + f.write(datafile) + + with open("shapesfile.ttl", "wb") as f: + f.write(shapesfile) + + output = subprocess.run( + ["shaclinfer.sh", "-datafile", "datafile.ttl", "-shapesfile", "shapesfile.ttl"], + stdout=subprocess.PIPE, + ) + + os.remove("datafile.ttl") + os.remove("shapesfile.ttl") + with open("validationTest.ttl", "wb") as f: + f.write(output.stdout) + + return {"output": output.stdout} diff --git a/app/webapp/main.py b/src/shacl-api/webapp.py similarity index 73% rename from app/webapp/main.py rename to src/shacl-api/webapp.py index 83f216b..6fee617 100644 --- a/app/webapp/main.py +++ b/src/shacl-api/webapp.py @@ -1,25 +1,31 @@ +import os import streamlit as st -import requests +import requests import base64 -# This interface is for uploading the files and getting the files back + +# This interface is for uploading the files and getting the files back +API_PORT = os.getenv("API_PORT", 15400) st.set_page_config(layout="wide") -st.image("https://datascience.ch/wp-content/uploads/2020/09/logo-SDSC-transparent.png", width=200) +st.image( + "https://datascience.ch/wp-content/uploads/2020/09/logo-SDSC-transparent.png", + width=200, +) st.title("shaclAPI") -cola, colb, colc, _,_,_,_ = st.columns(7) +cola, colb, colc, _, _, _, _ = st.columns(7) with cola: st.write("Validation and Inference") with colb: - option = st.radio("Which analysis would you like to do?", - ("Validation", "Inference")) - + option = st.radio( + "Which analysis would you like to do?", ("Validation", "Inference") + ) + with colc: - port = st.radio("Which port is the API using?", - ("15400", "8000")) + port = st.radio("Which port is the API using?", (f"{API_PORT}", "8000")) st.markdown("""---""") @@ -48,9 +54,8 @@ st.markdown("## SHACL Output") calculate = st.button("Calculate") - if calculate: - payload = {"datafile": datafile64, - "shapesfile": shapesfile64} + if calculate: + payload = {"datafile": datafile64, "shapesfile": shapesfile64} if option == "Validation": url = f"http://127.0.0.1:{port}/validate" @@ -60,9 +65,9 @@ r = requests.post(url, data=payload) output = r.json()["output"] with st.expander("See Output"): - st.code(output) #line_numbers + st.code(output) # line_numbers - st.download_button('Download TTL', output, file_name='output.ttl') + st.download_button("Download TTL", output, file_name="output.ttl") st.markdown("""---""") @@ -72,7 +77,8 @@ with col4: st.markdown("## How to use the API in python?") with st.expander("See Code"): - st.code(""" + st.code( + """ import requests import base64 with open('../tests/tests-files/val_imagingID.ttl', 'rb') as file: @@ -92,15 +98,20 @@ output = r.json()["output"] - """, language="python") + """, + language="python", + ) with col5: st.markdown("## How to use the API in javascript?") with st.expander("See Code"): - st.code(""" + st.code( + """ SOON - """, language="javascript") + """, + language="javascript", + ) st.markdown("""---""") st.markdown("Developed with <3 by ORDES SDSC Team.") diff --git a/tests/inference.py b/tests/inference.py index c3bd35a..b048ad8 100644 --- a/tests/inference.py +++ b/tests/inference.py @@ -1,10 +1,20 @@ import subprocess + def runInferenceTest(): - output = subprocess.run(["shaclinfer.sh", "-datafile", "tests-files/inf_imagingID.ttl", "-shapesfile", "tests-files/inf_ImagingOntologyShapes.ttl"], stdout=subprocess.PIPE) + output = subprocess.run( + [ + "shaclinfer.sh", + "-datafile", + "tests-files/inf_imagingID.ttl", + "-shapesfile", + "tests-files/inf_ImagingOntologyShapes.ttl", + ], + stdout=subprocess.PIPE, + ) - with open("inferenceTest.ttl", 'wb') as f: + with open("inferenceTest.ttl", "wb") as f: f.write(output.stdout) -runInferenceTest() \ No newline at end of file +runInferenceTest() diff --git a/tests/validation.py b/tests/validation.py index d557f0c..9d43ba1 100644 --- a/tests/validation.py +++ b/tests/validation.py @@ -1,17 +1,37 @@ import subprocess + def runValidationTest(): - output = subprocess.run(["shaclvalidate.sh", "-datafile", "tests-files/val_imagingID.ttl", "-shapesfile", "tests-files/val_ImagingOntologyShapes.ttl"], stdout=subprocess.PIPE) + output = subprocess.run( + [ + "shaclvalidate.sh", + "-datafile", + "tests-files/val_imagingID.ttl", + "-shapesfile", + "tests-files/val_ImagingOntologyShapes.ttl", + ], + stdout=subprocess.PIPE, + ) - with open("validationTest.ttl", 'wb') as f: + with open("validationTest.ttl", "wb") as f: f.write(output.stdout) + def runFailedInferenceTest(): - output = subprocess.run(["shaclvalidate.sh", "-datafile", "tests-files/val_fail_imagingID.ttl", "-shapesfile", "tests-files/val_fail_ImagingOntologyShapes.ttl"], stdout=subprocess.PIPE) + output = subprocess.run( + [ + "shaclvalidate.sh", + "-datafile", + "tests-files/val_fail_imagingID.ttl", + "-shapesfile", + "tests-files/val_fail_ImagingOntologyShapes.ttl", + ], + stdout=subprocess.PIPE, + ) - with open("validationFailTest.ttl", 'wb') as f: + with open("validationFailTest.ttl", "wb") as f: f.write(output.stdout) runValidationTest() -runFailedInferenceTest() \ No newline at end of file +runFailedInferenceTest() diff --git a/ci/develop_watcher.sh b/tools/ci/develop_watcher.sh similarity index 100% rename from ci/develop_watcher.sh rename to tools/ci/develop_watcher.sh diff --git a/ci/prod_watcher.sh b/tools/ci/prod_watcher.sh similarity index 100% rename from ci/prod_watcher.sh rename to tools/ci/prod_watcher.sh diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile new file mode 100644 index 0000000..f3bc53e --- /dev/null +++ b/tools/docker/Dockerfile @@ -0,0 +1,66 @@ +ARG VERSION=latest + +FROM ghcr.io/ashleycaselli/shacl:1.4.3_89205df AS base + +### API-only build-stage ### +FROM base AS api + +# Metadata +LABEL org.opencontainers.image.source https://github.com/sdsc-ordes/shacl-api +LABEL org.opencontainers.image.licenses AGPL-3.0 +LABEL org.opencontainers.image.title "SHACL API" +LABEL org.opencontainers.image.description "API for validating RDF data against SHACL shapes." +LABEL org.opencontainers.image.version ${VERSION} + +# Environment +ENV API_PORT=15400 +ENV WEBAPP_PORT=8501 +ENV SHAPES_PATH=/shacl/data/shapes.ttl +# unset or set to "" to disable shapes download +ENV SHAPES_URL='https://github.com/sdsc-ordes/imaging-plaza-ontology/releases/download/v0.8/ImagingOntologyCombined.ttl.gz' +ENV PATH="${PATH}:/home/appuser/.local/bin" + +RUN apk update && apk add \ + bash \ + curl \ + gzip \ + python3 \ + py3-pip \ + shadow \ + tar \ + zip \ + && rm -rf /var/lib/apt/lists/* + +RUN groupadd --gid 1000 appuser \ + && useradd --uid 1000 --gid 1000 -m appuser + +USER appuser +WORKDIR /shacl +COPY . . +COPY ./tools/docker/entrypoint.sh /entrypoint.sh + +ENV PYTHONUNBUFFERED=1 +RUN pip3 install --break-system-packages -e . + +EXPOSE ${API_PORT} + +ENTRYPOINT ["bash", "/entrypoint.sh", "api"] + +### API + Webapp build-stage ### +FROM api AS webapp + +LABEL org.opencontainers.image.version ${VERSION}-webapp + +USER root +RUN apk update && apk add \ + py3-pyarrow \ + && rm -rf /var/lib/apt/lists/* +USER appuser + +RUN pip3 install --break-system-packages -e '.[webapp]' + + +EXPOSE ${WEBAPP_PORT} + +ENTRYPOINT ["bash", "/entrypoint.sh", "webapp"] + diff --git a/tools/docker/compose.yml b/tools/docker/compose.yml new file mode 100644 index 0000000..535e2fd --- /dev/null +++ b/tools/docker/compose.yml @@ -0,0 +1,13 @@ +services: + shacl_api: + environment: + env_file: .example.env + build: + context: ../.. + dockerfile: ./tools/docker/Dockerfile + target: webapp + ports: + - "8001:15400" + - "8501:8501" + volumes: + - ../../src:/shacl/src diff --git a/tools/docker/entrypoint.sh b/tools/docker/entrypoint.sh new file mode 100644 index 0000000..c77c61d --- /dev/null +++ b/tools/docker/entrypoint.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +set -e + +extract_file() { + ARCHIVE="$1" + OUTPUT="$2" + + case "$ARCHIVE" in + *.gz) + gzip -dc "$ARCHIVE" > "$OUTPUT" + ;; + *.zip) + unzip -p "$ARCHIVE" > "$OUTPUT" + ;; + *.tar.gz|*.tgz) + tar -xzOf "$ARCHIVE" > "$OUTPUT" + ;; + *) + mv "$ARCHIVE" "$OUTPUT" + ;; + esac +} + +# Download and extract shapes +if [ -z "$SHAPES_URL" ]; then + mkdir -p "$(dirname "$SHAPES_PATH")" + TMP_FILE=$(mktemp) + curl -fsSL "$SHAPES_URL" -o "$TMP_FILE" + extract_file "$TMP_FILE" "$SHAPES_PATH" +fi + +# Start webapp if enabled +if [ "$1" == "webapp" ]; then + nohup streamlit run /shacl/src/shacl-api/webapp.py --server.port "${WEBAPP_PORT:-8501}" & +fi + +# Start API server +python3 -m uvicorn src.shacl-api.server:app --host 0.0.0.0 --port "${API_PORT:-15400}" +