Skip to content

Commit 8e327a4

Browse files
authored
Merge pull request #42 from NFDI4Chem/development
Development
2 parents 23d9bc4 + d9d89f8 commit 8e327a4

29 files changed

+661
-110
lines changed

.github/workflows/dev-build.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# This worklflow will perform following actions when the code is pushed to development branch:
33
# - Build the latest docker image in development which needs test to pass first.
4-
# - Push the docker image to Docker Hub under namespace - caffeinejena with tag:dev-latest.
4+
# - Push the docker image to Docker Hub under namespace - nfdi4chem with tag:dev-latest.
55
#
66
# Maintainers:
77
# - name: Nisha Sharma
@@ -17,7 +17,8 @@ env:
1717
DOCKER_HUB_USERNAME : ${{ secrets.DOCKER_USERNAME }}
1818
DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_PASSWORD }}
1919
REPOSITORY_NAME: nmrkit
20-
REPOSITORY_NAMESPACE: caffeinejena
20+
REPOSITORY_NAMESPACE: nfdi4chem
21+
RELEASE_TAG: dev-latest
2122

2223
jobs:
2324
test:
@@ -64,6 +65,6 @@ jobs:
6465
push: true
6566
build-args: |
6667
RELEASE_VERSION=dev-latest
67-
tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:dev-latest
68+
tags: ${{ env.REPOSITORY_NAMESPACE }}/${{ env.REPOSITORY_NAME }}:${{ env.RELEASE_TAG }}
6869
username: ${{ env.DOCKER_HUB_USERNAME }}
6970
password: ${{ env.DOCKER_HUB_PASSWORD }}

.github/workflows/prod-build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
# This worklflow will perform following actions when the code is pushed to main branch:
33
# - Build the latest docker image in development which needs test to pass first.
4-
# - Push the docker image to Docker Hub under namespace - caffeinejena with tag:[release_version].
4+
# - Push the docker image to Docker Hub under namespace - nfdi4chem with tag:[release_version].
55
#
66
# Maintainers:
77
# - name: Nisha Sharma
@@ -17,7 +17,7 @@ env:
1717
DOCKER_HUB_USERNAME : ${{ secrets.DOCKER_USERNAME }}
1818
DOCKER_HUB_PASSWORD : ${{ secrets.DOCKER_PASSWORD }}
1919
REPOSITORY_NAME: nmrkit
20-
REPOSITORY_NAMESPACE: caffeinejena
20+
REPOSITORY_NAMESPACE: nfdi4chem
2121

2222
jobs:
2323
push_to_registry:

Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,10 @@ RUN python3 -m pip install uvicorn[standard]
4343

4444
COPY ./app /code/app
4545

46+
RUN curl -sL https://deb.nodesource.com/setup_current.x | bash -
47+
RUN apt-get install -y nodejs
48+
RUN npm install -g npm@latest
49+
50+
RUN npm install -g /code/app/scripts/nmr-cli
51+
4652
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80", "--workers", "4", "--reload"]

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<p align="center"><a href="#" target="_blank"><img src="/public/img/logo.svg" width="400" alt="NMRKit Logo"></a></p>
1+
<p align="center"><a href="#" target="_blank"><img src="/public/img/logo.svg" width="400" alt="NMRKit Logo"></a></p>
22

33
[![License](https://img.shields.io/badge/License-MIT%202.0-blue.svg)](https://opensource.org/licenses/MIT)
44
[![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-blue.svg)](https://github.com/NFDI4Chem/nmrkit/graphs/commit-activity)
@@ -49,5 +49,5 @@ NMRKit is developed and maintained by the [NFDI4Chem partners](https://www.nfdi4
4949
The code for this web application is released under the [MIT license](https://opensource.org/licenses/MIT).
5050

5151

52-
<p align="left"><a href="https://nfdi4chem.de/" target="_blank"><img src="https://www.nfdi4chem.de/wp-content/themes/wptheme/assets/img/logo.svg" width="50%" alt="NFDI4Chem Logo"></a></p>
52+
<p align="left"><a href="https://nfdi4chem.de/" target="_blank"><img src="https://www.nfdi4chem.de/wp-content/themes/wptheme/assets/img/logo.svg" width="30%" alt="NFDI4Chem Logo"></a></p>
5353
<p align="left"><a href="https://cheminf.uni-jena.de/" target="_blank"><img src="/public/img/fsu-jena.jpg" width="30%" alt="NFDI4Chem Logo"></a></p>

app/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from .routers import registration
77
from .routers import chem
8+
from .routers import spectra
89
from fastapi.middleware.cors import CORSMiddleware
910

1011
from app.core import config, tasks
@@ -29,6 +30,7 @@
2930

3031
app.include_router(registration.router)
3132
app.include_router(chem.router)
33+
app.include_router(spectra.router)
3234

3335
app.add_event_handler("startup", tasks.create_start_app_handler(app))
3436
app.add_event_handler("shutdown", tasks.create_stop_app_handler(app))

app/routers/chem.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from typing import Annotated
22
from psycopg2.errors import UniqueViolation
33
from app.modules.cdkmodules import getCDKHOSECodes
4-
from fastapi import APIRouter, HTTPException, status, Query
4+
from fastapi import APIRouter, HTTPException, status, Query, Body
55
from app.modules.rdkitmodules import getRDKitHOSECodes
66
from app.schemas import HealthCheck
7+
from app.schemas.alatis import AlatisModel
8+
import requests
79

810
router = APIRouter(
911
prefix="/chem",
@@ -38,7 +40,7 @@ def get_health() -> HealthCheck:
3840

3941
@router.get(
4042
"/hosecode",
41-
tags=["registration"],
43+
tags=["chem"],
4244
summary="Generates HOSE codes of molecule",
4345
response_model=list[str],
4446
response_description="Returns an array of hose codes generated",
@@ -76,3 +78,36 @@ async def HOSE_Codes(
7678
detail="Error paring the structure " + e.message,
7779
headers={"X-Error": "RDKit molecule input parse error"},
7880
)
81+
82+
83+
@router.post(
84+
"/label-atoms",
85+
tags=["chem"],
86+
summary="Label atoms using ALATIS naming system",
87+
response_model=AlatisModel,
88+
response_description="",
89+
status_code=status.HTTP_200_OK,
90+
)
91+
async def label_atoms(
92+
data: Annotated[
93+
str,
94+
Body(embed=False, media_type="text/plain"),
95+
]
96+
):
97+
"""
98+
## Generates atom labels for a given molecule
99+
100+
Returns:
101+
JSON with various representations
102+
"""
103+
try:
104+
url = "http://alatis.nmrfam.wisc.edu/upload"
105+
payload = {"input_text": data, "format": "format_", "response_type": "json"}
106+
response = requests.request("POST", url, data=payload)
107+
return response.json()
108+
except Exception as e:
109+
raise HTTPException(
110+
status_code=422,
111+
detail="Error paring the structure " + e.message,
112+
headers={"X-Error": "RDKit molecule input parse error"},
113+
)

app/routers/spectra.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
from fastapi import APIRouter, HTTPException, status, UploadFile
2+
from app.schemas import HealthCheck
3+
import subprocess
4+
5+
router = APIRouter(
6+
prefix="/spectra",
7+
tags=["spectra"],
8+
dependencies=[],
9+
responses={404: {"description": "Not found"}},
10+
)
11+
12+
13+
@router.get("/", include_in_schema=False)
14+
@router.get(
15+
"/health",
16+
tags=["healthcheck"],
17+
summary="Perform a Health Check on Chem Module",
18+
response_description="Return HTTP Status Code 200 (OK)",
19+
status_code=status.HTTP_200_OK,
20+
include_in_schema=False,
21+
response_model=HealthCheck,
22+
)
23+
def get_health() -> HealthCheck:
24+
"""
25+
## Perform a Health Check
26+
Endpoint to perform a healthcheck on. This endpoint can primarily be used Docker
27+
to ensure a robust container orchestration and management is in place. Other
28+
services which rely on proper functioning of the API service will not deploy if this
29+
endpoint returns any other HTTP status code except 200 (OK).
30+
Returns:
31+
HealthCheck: Returns a JSON response with the health status
32+
"""
33+
return HealthCheck(status="OK")
34+
35+
36+
@router.post(
37+
"/parse",
38+
tags=["spectra"],
39+
summary="Parse the input spectra format and extract metadata",
40+
response_description="",
41+
status_code=status.HTTP_200_OK,
42+
)
43+
async def parse_spectra(file: UploadFile):
44+
"""
45+
## Parse the spectra file and extract meta-data
46+
Endpoint to uses nmr-load-save to read the input spectra file (.jdx,.nmredata,.dx) and extracts metadata
47+
48+
Returns:
49+
data: spectra data in json format
50+
"""
51+
try:
52+
contents = file.file.read()
53+
file_path = "/tmp/" + file.filename
54+
with open(file_path, "wb") as f:
55+
f.write(contents)
56+
p = subprocess.Popen(
57+
"npx nmr-cli -p " + file_path, stdout=subprocess.PIPE, shell=True
58+
)
59+
(output, err) = p.communicate()
60+
p_status = p.wait()
61+
return output
62+
except Exception as e:
63+
raise HTTPException(
64+
status_code=422,
65+
detail="Error paring the structure "
66+
+ e.message
67+
+ ". Error: "
68+
+ err
69+
+ ". Status:"
70+
+ p_status,
71+
headers={"X-Error": "RDKit molecule input parse error"},
72+
)
73+
finally:
74+
file.file.close()

app/schemas/alatis.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from __future__ import annotations
2+
3+
from pydantic import BaseModel
4+
5+
6+
class AlatisModel(BaseModel):
7+
html_url: str
8+
inchi: str
9+
key: str
10+
status: str
11+
structure: str

app/scripts/nmr-cli/bin/index.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env node
2+
const {join,isAbsolute}= require("path");
3+
const yargs = require("yargs");
4+
const loader = require("nmr-load-save");
5+
const fileUtils = require("filelist-utils");
6+
7+
const usageMessage ="Usage: nmr-cli -u <url> or -p <path>"
8+
9+
const options = yargs
10+
.usage(usageMessage)
11+
.option("u", { alias: "url", describe: "File URL", type: "string",nargs:1})
12+
.option("p", { alias: "path", describe: "Directory path", type: "string",nargs:1}).showHelpOnFail();
13+
14+
async function loadSpectrumFromURL(url) {
15+
const {pathname:relativePath,origin:baseURL} = new URL(url);
16+
const source = {
17+
entries: [
18+
{
19+
relativePath,
20+
}
21+
],
22+
baseURL
23+
};
24+
const fileCollection = await fileUtils.fileCollectionFromWebSource(source,{});
25+
26+
const {
27+
nmriumState: { data },
28+
} = await loader.read(fileCollection);
29+
return data;
30+
}
31+
32+
33+
async function loadSpectrumFromFilePath(path) {
34+
const dirPath = isAbsolute(path)?path:join(process.cwd(),path)
35+
36+
const fileCollection = await fileUtils.fileCollectionFromPath(dirPath,{});
37+
38+
const {
39+
nmriumState: { data },
40+
} = await loader.read(fileCollection);
41+
return data;
42+
}
43+
44+
45+
const parameters = options.argv;
46+
47+
if(parameters.u && parameters.p){
48+
options.showHelp();
49+
}else{
50+
51+
if(parameters.u){
52+
loadSpectrumFromURL(parameters.u).then((result)=>{
53+
console.log(JSON.stringify(result))
54+
})
55+
56+
}
57+
58+
if(parameters.p){
59+
loadSpectrumFromFilePath(parameters.p).then((result)=>{
60+
console.log(JSON.stringify(result))
61+
})
62+
}
63+
64+
}
65+
66+
67+
68+
69+

app/scripts/nmr-load-save/package-lock.json renamed to app/scripts/nmr-cli/package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)