diff --git a/Dockerfile b/Dockerfile index 6518e5d..be2d9f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,4 +43,10 @@ RUN python3 -m pip install uvicorn[standard] COPY ./app /code/app +RUN curl -sL https://deb.nodesource.com/setup_current.x | bash - +RUN apt-get install -y nodejs +RUN npm install -g npm@latest + +RUN npm install -g /code/app/scripts/nmr-cli + CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--workers", "4", "--reload"] \ No newline at end of file diff --git a/README.md b/README.md index 69884ba..d23b77b 100644 --- a/README.md +++ b/README.md @@ -49,5 +49,5 @@ NMRKit is developed and maintained by the [NFDI4Chem partners](https://www.nfdi4 The code for this web application is released under the [MIT license](https://opensource.org/licenses/MIT). -

NFDI4Chem Logo

+

NFDI4Chem Logo

NFDI4Chem Logo

diff --git a/app/main.py b/app/main.py index 0de3ab0..c74c68c 100644 --- a/app/main.py +++ b/app/main.py @@ -5,6 +5,7 @@ from .routers import registration from .routers import chem +from .routers import spectra from fastapi.middleware.cors import CORSMiddleware from app.core import config, tasks @@ -29,6 +30,7 @@ app.include_router(registration.router) app.include_router(chem.router) +app.include_router(spectra.router) app.add_event_handler("startup", tasks.create_start_app_handler(app)) app.add_event_handler("shutdown", tasks.create_stop_app_handler(app)) diff --git a/app/routers/chem.py b/app/routers/chem.py index 20fd730..29dbff8 100644 --- a/app/routers/chem.py +++ b/app/routers/chem.py @@ -38,7 +38,7 @@ def get_health() -> HealthCheck: @router.get( "/hosecode", - tags=["registration"], + tags=["chem"], summary="Generates HOSE codes of molecule", response_model=list[str], response_description="Returns an array of hose codes generated", diff --git a/app/routers/spectra.py b/app/routers/spectra.py new file mode 100644 index 0000000..fa2fd9b --- /dev/null +++ b/app/routers/spectra.py @@ -0,0 +1,70 @@ +from typing import Annotated +from fastapi import APIRouter, HTTPException, status, FastAPI, File, UploadFile +from fastapi.responses import Response +from app.schemas import HealthCheck +import subprocess +import json + +router = APIRouter( + prefix="/spectra", + tags=["spectra"], + dependencies=[], + responses={404: {"description": "Not found"}}, +) + +@router.get("/", include_in_schema=False) +@router.get( + "/health", + tags=["healthcheck"], + summary="Perform a Health Check on Chem Module", + response_description="Return HTTP Status Code 200 (OK)", + status_code=status.HTTP_200_OK, + include_in_schema=False, + response_model=HealthCheck, +) +def get_health() -> HealthCheck: + """ + ## Perform a Health Check + Endpoint to perform a healthcheck on. This endpoint can primarily be used Docker + to ensure a robust container orchestration and management is in place. Other + services which rely on proper functioning of the API service will not deploy if this + endpoint returns any other HTTP status code except 200 (OK). + Returns: + HealthCheck: Returns a JSON response with the health status + """ + return HealthCheck(status="OK") + + +@router.post( + "/parse", + tags=["spectra"], + summary="Parse the input spectra format and extract metadata", + response_description="", + status_code=status.HTTP_200_OK, + +) +async def parse_spectra(file: UploadFile): + """ + ## Parse the spectra file and extract meta-data + Endpoint to uses nmr-load-save to read the input spectra file (.jdx,.nmredata,.dx) and extracts metadata + + Returns: + data: spectra data in json format + """ + try: + contents = file.file.read() + file_path = "/tmp/" + file.filename + with open(file_path, 'wb') as f: + f.write(contents) + p = subprocess.Popen("npx nmr-cli -p " + file_path, stdout=subprocess.PIPE, shell=True) + (output, err) = p.communicate() + p_status = p.wait() + return output + except Exception as e: + raise HTTPException( + status_code=422, + detail="Error paring the structure " + e.message + ". Error: " + err + ". Status:" + p_status, + headers={"X-Error": "RDKit molecule input parse error"}, + ) + finally: + file.file.close() \ No newline at end of file diff --git a/app/scripts/nmr-cli/bin/index.js b/app/scripts/nmr-cli/bin/index.js new file mode 100755 index 0000000..7556d97 --- /dev/null +++ b/app/scripts/nmr-cli/bin/index.js @@ -0,0 +1,69 @@ +#!/usr/bin/env node +const {join,isAbsolute}= require("path"); +const yargs = require("yargs"); +const loader = require("nmr-load-save"); +const fileUtils = require("filelist-utils"); + +const usageMessage ="Usage: nmr-cli -u or -p " + +const options = yargs + .usage(usageMessage) + .option("u", { alias: "url", describe: "File URL", type: "string",nargs:1}) + .option("p", { alias: "path", describe: "Directory path", type: "string",nargs:1}).showHelpOnFail(); + + async function loadSpectrumFromURL(url) { + const {pathname:relativePath,origin:baseURL} = new URL(url); + const source = { + entries: [ + { + relativePath, + } + ], + baseURL + }; + const fileCollection = await fileUtils.fileCollectionFromWebSource(source,{}); + + const { + nmriumState: { data }, + } = await loader.read(fileCollection); + return data; + } + + + async function loadSpectrumFromFilePath(path) { + const dirPath = isAbsolute(path)?path:join(process.cwd(),path) + + const fileCollection = await fileUtils.fileCollectionFromPath(dirPath,{}); + + const { + nmriumState: { data }, + } = await loader.read(fileCollection); + return data; + } + + + const parameters = options.argv; + +if(parameters.u && parameters.p){ + options.showHelp(); +}else{ + + if(parameters.u){ + loadSpectrumFromURL(parameters.u).then((result)=>{ + console.log(JSON.stringify(result)) + }) + + } + + if(parameters.p){ + loadSpectrumFromFilePath(parameters.p).then((result)=>{ + console.log(JSON.stringify(result)) + }) + } + +} + + + + + diff --git a/app/scripts/nmr-load-save/package-lock.json b/app/scripts/nmr-cli/package-lock.json similarity index 99% rename from app/scripts/nmr-load-save/package-lock.json rename to app/scripts/nmr-cli/package-lock.json index 990dd41..c9fe27c 100644 --- a/app/scripts/nmr-load-save/package-lock.json +++ b/app/scripts/nmr-cli/package-lock.json @@ -233,9 +233,9 @@ "integrity": "sha512-f9c00hphOgeQTlDyavwTtu6RiK8AIFjD6+jvXkNkpeQ7rirK3uFWVpalkoS4LAwbdX7mfZ8aoBfFVQX1Re/8aw==" }, "node_modules/filelist-utils": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/filelist-utils/-/filelist-utils-1.10.0.tgz", - "integrity": "sha512-PItlcphlQWSWQaxLw7sjdiCQJSL4hrUh0h8pfniBJzlnC23RTRaGKZpv70cdGGIKToo+1PPJwKTCBo1BipAE0Q==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/filelist-utils/-/filelist-utils-1.10.1.tgz", + "integrity": "sha512-LClsm6vCsMmE6Eg7achDC9dR7QBnLhvlf8oKSy5Wl4194BbpCz0GBMfoS1mC8bOfiE48RAi0jxQdlR9G4kO9Cg==", "dependencies": { "cheminfo-types": "^1.7.2", "cross-fetch": "^3.1.6", diff --git a/app/scripts/nmr-load-save/package.json b/app/scripts/nmr-cli/package.json similarity index 100% rename from app/scripts/nmr-load-save/package.json rename to app/scripts/nmr-cli/package.json diff --git a/app/scripts/nmr-load-save/bin/index.js b/app/scripts/nmr-load-save/bin/index.js deleted file mode 100755 index 043fe85..0000000 --- a/app/scripts/nmr-load-save/bin/index.js +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env node - -const yargs = require("yargs"); -const loader = require("nmr-load-save"); -const fileUtils = require("filelist-utils"); - -const options = yargs - .usage("Usage: -u ") - .option("u", { alias: "url", describe: "File URL", type: "string", demandOption: true }) - .argv; - - async function loadSpectrum(url) { - const {pathname:relativePath,origin:baseURL} = new URL(url); - const source = { - entries: [ - { - relativePath, - } - ], - baseURL - }; - const fileCollection = await fileUtils.fileCollectionFromWebSource(source,{}); - - const { - nmriumState: { data }, - } = await loader.read(fileCollection); - return data; - } - - - - const url = options.u.split(" "); - - - loadSpectrum(options.u).then((result)=>{ - console.log(JSON.stringify(result)) - }) - - diff --git a/requirements.txt b/requirements.txt index 9047513..71ee463 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,5 @@ prometheus-fastapi-instrumentator databases[postgresql]==0.4.2 SQLAlchemy==2.0.19 alembic==1.11.1 -psycopg2-binary \ No newline at end of file +psycopg2-binary +python-multipart \ No newline at end of file