Spaces:
Running
Running
molecule visualizing, requests->httpx, support multiple molecules
Browse files- examples/Generative drug screening.lynxkite.json +0 -0
- lynxkite-app/web/package-lock.json +55 -2
- lynxkite-app/web/package.json +2 -0
- lynxkite-app/web/src/workspace/Workspace.tsx +2 -0
- lynxkite-app/web/src/workspace/nodes/NodeWithPy3DMol.tsx +67 -0
- lynxkite-bio/src/lynxkite_bio/nims.py +72 -71
- lynxkite-core/src/lynxkite/core/ops.py +1 -0
examples/Generative drug screening.lynxkite.json
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
lynxkite-app/web/package-lock.json
CHANGED
|
@@ -18,11 +18,13 @@
|
|
| 18 |
"@syncedstore/react": "^0.6.0",
|
| 19 |
"@types/node": "^22.10.1",
|
| 20 |
"@xyflow/react": "^12.3.5",
|
|
|
|
| 21 |
"axios": "^1.8.2",
|
| 22 |
"daisyui": "^4.12.20",
|
| 23 |
"echarts": "^5.5.1",
|
| 24 |
"fuse.js": "^7.0.0",
|
| 25 |
"json-schema-to-typescript": "^15.0.3",
|
|
|
|
| 26 |
"react": "^18.3.1",
|
| 27 |
"react-dom": "^18.3.1",
|
| 28 |
"react-markdown": "^9.0.1",
|
|
@@ -2366,6 +2368,22 @@
|
|
| 2366 |
"d3-zoom": "^3.0.0"
|
| 2367 |
}
|
| 2368 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2369 |
"node_modules/abstract-leveldown": {
|
| 2370 |
"version": "6.2.3",
|
| 2371 |
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz",
|
|
@@ -4187,6 +4205,12 @@
|
|
| 4187 |
"integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==",
|
| 4188 |
"license": "MIT"
|
| 4189 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4190 |
"node_modules/is-alphabetical": {
|
| 4191 |
"version": "2.0.1",
|
| 4192 |
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
|
|
@@ -5465,8 +5489,7 @@
|
|
| 5465 |
"version": "0.52.2",
|
| 5466 |
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz",
|
| 5467 |
"integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==",
|
| 5468 |
-
"license": "MIT"
|
| 5469 |
-
"peer": true
|
| 5470 |
},
|
| 5471 |
"node_modules/ms": {
|
| 5472 |
"version": "2.1.3",
|
|
@@ -5518,6 +5541,15 @@
|
|
| 5518 |
"dev": true,
|
| 5519 |
"license": "MIT"
|
| 5520 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5521 |
"node_modules/no-case": {
|
| 5522 |
"version": "3.0.4",
|
| 5523 |
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
|
@@ -5649,6 +5681,12 @@
|
|
| 5649 |
"integrity": "sha512-g4+387DXDKlZzHkP+9FLt8yKj8+/3tOkPv7DVTJGGRm00RkEWgqbFstX1mXJ4M0VDYhUqsTOiISqNOJnhAu3PQ==",
|
| 5650 |
"license": "MIT"
|
| 5651 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5652 |
"node_modules/parent-module": {
|
| 5653 |
"version": "1.0.1",
|
| 5654 |
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
|
@@ -7107,6 +7145,21 @@
|
|
| 7107 |
"browserslist": ">= 4.21.0"
|
| 7108 |
}
|
| 7109 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7110 |
"node_modules/uri-js": {
|
| 7111 |
"version": "4.4.1",
|
| 7112 |
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
|
|
|
| 18 |
"@syncedstore/react": "^0.6.0",
|
| 19 |
"@types/node": "^22.10.1",
|
| 20 |
"@xyflow/react": "^12.3.5",
|
| 21 |
+
"3dmol": "^2.4.2",
|
| 22 |
"axios": "^1.8.2",
|
| 23 |
"daisyui": "^4.12.20",
|
| 24 |
"echarts": "^5.5.1",
|
| 25 |
"fuse.js": "^7.0.0",
|
| 26 |
"json-schema-to-typescript": "^15.0.3",
|
| 27 |
+
"monaco-editor": "^0.52.2",
|
| 28 |
"react": "^18.3.1",
|
| 29 |
"react-dom": "^18.3.1",
|
| 30 |
"react-markdown": "^9.0.1",
|
|
|
|
| 2368 |
"d3-zoom": "^3.0.0"
|
| 2369 |
}
|
| 2370 |
},
|
| 2371 |
+
"node_modules/3dmol": {
|
| 2372 |
+
"version": "2.4.2",
|
| 2373 |
+
"resolved": "https://registry.npmjs.org/3dmol/-/3dmol-2.4.2.tgz",
|
| 2374 |
+
"integrity": "sha512-7R6uFaF5++s9EpO+R0a3bs6igi5idI+sgrVhtozaZlOGHg6oourYkAlAwYxWRaeBGlNcAd+oEIhbhJYhNxGyZA==",
|
| 2375 |
+
"license": "BSD-3-Clause",
|
| 2376 |
+
"dependencies": {
|
| 2377 |
+
"iobuffer": "^5.3.1",
|
| 2378 |
+
"netcdfjs": "^3.0.0",
|
| 2379 |
+
"pako": "^2.1.0",
|
| 2380 |
+
"upng-js": "^2.1.0"
|
| 2381 |
+
},
|
| 2382 |
+
"engines": {
|
| 2383 |
+
"node": ">=16.16.0",
|
| 2384 |
+
"npm": ">=8.11"
|
| 2385 |
+
}
|
| 2386 |
+
},
|
| 2387 |
"node_modules/abstract-leveldown": {
|
| 2388 |
"version": "6.2.3",
|
| 2389 |
"resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-6.2.3.tgz",
|
|
|
|
| 4205 |
"integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==",
|
| 4206 |
"license": "MIT"
|
| 4207 |
},
|
| 4208 |
+
"node_modules/iobuffer": {
|
| 4209 |
+
"version": "5.4.0",
|
| 4210 |
+
"resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz",
|
| 4211 |
+
"integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==",
|
| 4212 |
+
"license": "MIT"
|
| 4213 |
+
},
|
| 4214 |
"node_modules/is-alphabetical": {
|
| 4215 |
"version": "2.0.1",
|
| 4216 |
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
|
|
|
|
| 5489 |
"version": "0.52.2",
|
| 5490 |
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz",
|
| 5491 |
"integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==",
|
| 5492 |
+
"license": "MIT"
|
|
|
|
| 5493 |
},
|
| 5494 |
"node_modules/ms": {
|
| 5495 |
"version": "2.1.3",
|
|
|
|
| 5541 |
"dev": true,
|
| 5542 |
"license": "MIT"
|
| 5543 |
},
|
| 5544 |
+
"node_modules/netcdfjs": {
|
| 5545 |
+
"version": "3.0.0",
|
| 5546 |
+
"resolved": "https://registry.npmjs.org/netcdfjs/-/netcdfjs-3.0.0.tgz",
|
| 5547 |
+
"integrity": "sha512-LOvT8KkC308qtpUkcBPiCMBtii7ZQCN6LxcVheWgyUeZ6DQWcpSRFV9dcVXLj/2eHZ/bre9tV5HTH4Sf93vrFw==",
|
| 5548 |
+
"license": "MIT",
|
| 5549 |
+
"dependencies": {
|
| 5550 |
+
"iobuffer": "^5.3.2"
|
| 5551 |
+
}
|
| 5552 |
+
},
|
| 5553 |
"node_modules/no-case": {
|
| 5554 |
"version": "3.0.4",
|
| 5555 |
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
|
|
|
| 5681 |
"integrity": "sha512-g4+387DXDKlZzHkP+9FLt8yKj8+/3tOkPv7DVTJGGRm00RkEWgqbFstX1mXJ4M0VDYhUqsTOiISqNOJnhAu3PQ==",
|
| 5682 |
"license": "MIT"
|
| 5683 |
},
|
| 5684 |
+
"node_modules/pako": {
|
| 5685 |
+
"version": "2.1.0",
|
| 5686 |
+
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
| 5687 |
+
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
| 5688 |
+
"license": "(MIT AND Zlib)"
|
| 5689 |
+
},
|
| 5690 |
"node_modules/parent-module": {
|
| 5691 |
"version": "1.0.1",
|
| 5692 |
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
|
|
|
| 7145 |
"browserslist": ">= 4.21.0"
|
| 7146 |
}
|
| 7147 |
},
|
| 7148 |
+
"node_modules/upng-js": {
|
| 7149 |
+
"version": "2.1.0",
|
| 7150 |
+
"resolved": "https://registry.npmjs.org/upng-js/-/upng-js-2.1.0.tgz",
|
| 7151 |
+
"integrity": "sha512-d3xzZzpMP64YkjP5pr8gNyvBt7dLk/uGI67EctzDuVp4lCZyVMo0aJO6l/VDlgbInJYDY6cnClLoBp29eKWI6g==",
|
| 7152 |
+
"license": "MIT",
|
| 7153 |
+
"dependencies": {
|
| 7154 |
+
"pako": "^1.0.5"
|
| 7155 |
+
}
|
| 7156 |
+
},
|
| 7157 |
+
"node_modules/upng-js/node_modules/pako": {
|
| 7158 |
+
"version": "1.0.11",
|
| 7159 |
+
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
| 7160 |
+
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
| 7161 |
+
"license": "(MIT AND Zlib)"
|
| 7162 |
+
},
|
| 7163 |
"node_modules/uri-js": {
|
| 7164 |
"version": "4.4.1",
|
| 7165 |
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
lynxkite-app/web/package.json
CHANGED
|
@@ -21,11 +21,13 @@
|
|
| 21 |
"@syncedstore/react": "^0.6.0",
|
| 22 |
"@types/node": "^22.10.1",
|
| 23 |
"@xyflow/react": "^12.3.5",
|
|
|
|
| 24 |
"axios": "^1.8.2",
|
| 25 |
"daisyui": "^4.12.20",
|
| 26 |
"echarts": "^5.5.1",
|
| 27 |
"fuse.js": "^7.0.0",
|
| 28 |
"json-schema-to-typescript": "^15.0.3",
|
|
|
|
| 29 |
"react": "^18.3.1",
|
| 30 |
"react-dom": "^18.3.1",
|
| 31 |
"react-markdown": "^9.0.1",
|
|
|
|
| 21 |
"@syncedstore/react": "^0.6.0",
|
| 22 |
"@types/node": "^22.10.1",
|
| 23 |
"@xyflow/react": "^12.3.5",
|
| 24 |
+
"3dmol": "^2.4.2",
|
| 25 |
"axios": "^1.8.2",
|
| 26 |
"daisyui": "^4.12.20",
|
| 27 |
"echarts": "^5.5.1",
|
| 28 |
"fuse.js": "^7.0.0",
|
| 29 |
"json-schema-to-typescript": "^15.0.3",
|
| 30 |
+
"monaco-editor": "^0.52.2",
|
| 31 |
"react": "^18.3.1",
|
| 32 |
"react-dom": "^18.3.1",
|
| 33 |
"react-markdown": "^9.0.1",
|
lynxkite-app/web/src/workspace/Workspace.tsx
CHANGED
|
@@ -36,6 +36,7 @@ import NodeSearch, { type OpsOp, type Catalog, type Catalogs } from "./NodeSearc
|
|
| 36 |
import NodeWithGraphCreationView from "./nodes/GraphCreationNode.tsx";
|
| 37 |
import NodeWithImage from "./nodes/NodeWithImage.tsx";
|
| 38 |
import NodeWithParams from "./nodes/NodeWithParams";
|
|
|
|
| 39 |
import NodeWithTableView from "./nodes/NodeWithTableView.tsx";
|
| 40 |
import NodeWithVisualization from "./nodes/NodeWithVisualization.tsx";
|
| 41 |
|
|
@@ -173,6 +174,7 @@ function LynxKiteFlow() {
|
|
| 173 |
image: NodeWithImage,
|
| 174 |
table_view: NodeWithTableView,
|
| 175 |
graph_creation_view: NodeWithGraphCreationView,
|
|
|
|
| 176 |
}),
|
| 177 |
[],
|
| 178 |
);
|
|
|
|
| 36 |
import NodeWithGraphCreationView from "./nodes/GraphCreationNode.tsx";
|
| 37 |
import NodeWithImage from "./nodes/NodeWithImage.tsx";
|
| 38 |
import NodeWithParams from "./nodes/NodeWithParams";
|
| 39 |
+
import NodeWithPy3Dmol from "./nodes/NodeWithPy3DMol.tsx";
|
| 40 |
import NodeWithTableView from "./nodes/NodeWithTableView.tsx";
|
| 41 |
import NodeWithVisualization from "./nodes/NodeWithVisualization.tsx";
|
| 42 |
|
|
|
|
| 174 |
image: NodeWithImage,
|
| 175 |
table_view: NodeWithTableView,
|
| 176 |
graph_creation_view: NodeWithGraphCreationView,
|
| 177 |
+
py3dmol: NodeWithPy3Dmol,
|
| 178 |
}),
|
| 179 |
[],
|
| 180 |
);
|
lynxkite-app/web/src/workspace/nodes/NodeWithPy3DMol.tsx
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { useEffect } from "react";
|
| 2 |
+
import NodeWithParams from "./NodeWithParams";
|
| 3 |
+
const $3Dmol = await import("3dmol");
|
| 4 |
+
|
| 5 |
+
const NodeWithPy3Dmol = (props: any) => {
|
| 6 |
+
const containerRef = React.useRef<HTMLDivElement>(null);
|
| 7 |
+
const viewerRef = React.useRef<any>(null);
|
| 8 |
+
|
| 9 |
+
useEffect(() => {
|
| 10 |
+
const config = props.data?.display?.value;
|
| 11 |
+
if (!config || !containerRef.current) return;
|
| 12 |
+
|
| 13 |
+
try {
|
| 14 |
+
// Initialize viewer only once
|
| 15 |
+
if (!viewerRef.current) {
|
| 16 |
+
viewerRef.current = $3Dmol.createViewer(containerRef.current, {
|
| 17 |
+
backgroundColor: "white",
|
| 18 |
+
});
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
const viewer = viewerRef.current;
|
| 22 |
+
|
| 23 |
+
// Clear previous models
|
| 24 |
+
viewer.clear();
|
| 25 |
+
|
| 26 |
+
// Add new model and style it
|
| 27 |
+
viewer.addModel(config.data, config.format);
|
| 28 |
+
viewer.setStyle({}, { stick: {} });
|
| 29 |
+
viewer.zoomTo();
|
| 30 |
+
viewer.render();
|
| 31 |
+
} catch (error) {
|
| 32 |
+
console.error("Error rendering 3D molecule:", error);
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
const resizeObserver = new ResizeObserver(() => {
|
| 36 |
+
viewerRef.current?.resize();
|
| 37 |
+
});
|
| 38 |
+
|
| 39 |
+
const observed = containerRef.current;
|
| 40 |
+
resizeObserver.observe(observed);
|
| 41 |
+
|
| 42 |
+
return () => {
|
| 43 |
+
resizeObserver.unobserve(observed);
|
| 44 |
+
if (viewerRef.current) {
|
| 45 |
+
viewerRef.current.clear();
|
| 46 |
+
}
|
| 47 |
+
};
|
| 48 |
+
}, [props.data?.display?.value]);
|
| 49 |
+
|
| 50 |
+
const nodeStyle = { display: "flex", flexDirection: "column", height: "100%" };
|
| 51 |
+
const vizStyle = {
|
| 52 |
+
flex: 1,
|
| 53 |
+
minHeight: "300px",
|
| 54 |
+
border: "1px solid #ddd",
|
| 55 |
+
borderRadius: "4px",
|
| 56 |
+
overflow: "hidden",
|
| 57 |
+
position: "relative",
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
return (
|
| 61 |
+
<NodeWithParams nodeStyle={nodeStyle} collapsed {...props}>
|
| 62 |
+
<div style={vizStyle} ref={containerRef} />
|
| 63 |
+
</NodeWithParams>
|
| 64 |
+
);
|
| 65 |
+
};
|
| 66 |
+
|
| 67 |
+
export default NodeWithPy3Dmol;
|
lynxkite-bio/src/lynxkite_bio/nims.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
from lynxkite_graph_analytics import Bundle
|
| 4 |
from lynxkite.core import ops
|
| 5 |
import joblib
|
| 6 |
-
import
|
| 7 |
import pandas as pd
|
| 8 |
import os
|
| 9 |
|
|
@@ -15,7 +15,7 @@ op = ops.op_registration(ENV)
|
|
| 15 |
key = os.getenv("NVCF_RUN_KEY")
|
| 16 |
|
| 17 |
|
| 18 |
-
def query_bionemo_nim(
|
| 19 |
url: str,
|
| 20 |
payload: dict,
|
| 21 |
):
|
|
@@ -26,17 +26,18 @@ def query_bionemo_nim(
|
|
| 26 |
}
|
| 27 |
try:
|
| 28 |
print(f"Sending request to {url}")
|
| 29 |
-
|
|
|
|
| 30 |
print(f"Received response from {url}", response.status_code)
|
| 31 |
response.raise_for_status()
|
| 32 |
return response.json()
|
| 33 |
-
except
|
| 34 |
raise ValueError(f"Query failed: {e}")
|
| 35 |
|
| 36 |
|
| 37 |
@op("MSA-search")
|
| 38 |
@mem.cache
|
| 39 |
-
def msa_search(
|
| 40 |
bundle: Bundle,
|
| 41 |
*,
|
| 42 |
protein_table: str,
|
|
@@ -48,26 +49,34 @@ def msa_search(
|
|
| 48 |
databases: str = "Uniref30_2302,colabfold_envdb_202108",
|
| 49 |
):
|
| 50 |
bundle = bundle.copy()
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
return bundle
|
| 66 |
|
| 67 |
|
| 68 |
@op("Query OpenFold2")
|
| 69 |
@mem.cache
|
| 70 |
-
def query_openfold2(
|
| 71 |
bundle: Bundle,
|
| 72 |
*,
|
| 73 |
protein_table: str,
|
|
@@ -78,59 +87,57 @@ def query_openfold2(
|
|
| 78 |
relax_prediction: bool = False,
|
| 79 |
):
|
| 80 |
bundle = bundle.copy()
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
return bundle
|
| 96 |
|
| 97 |
|
| 98 |
-
@op("View
|
| 99 |
-
def
|
| 100 |
bundle: Bundle,
|
| 101 |
*,
|
| 102 |
molecule_table: str,
|
| 103 |
molecule_column: str,
|
| 104 |
-
|
| 105 |
):
|
|
|
|
|
|
|
| 106 |
return {
|
| 107 |
-
"
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
"borderColor": "#fff",
|
| 114 |
-
"borderWidth": 2,
|
| 115 |
-
},
|
| 116 |
-
"data": [
|
| 117 |
-
{"value": 2, "name": "Hydrogen"},
|
| 118 |
-
{"value": 1, "name": "Sulfur"},
|
| 119 |
-
{"value": 4, "name": "Oxygen"},
|
| 120 |
-
],
|
| 121 |
-
}
|
| 122 |
-
]
|
| 123 |
}
|
| 124 |
|
| 125 |
|
| 126 |
-
@op("Known drug")
|
| 127 |
-
def known_drug(*, drug_name: str):
|
| 128 |
-
return Bundle()
|
| 129 |
-
|
| 130 |
-
|
| 131 |
@op("Query GenMol")
|
| 132 |
@mem.cache
|
| 133 |
-
def query_genmol(
|
| 134 |
bundle: Bundle,
|
| 135 |
*,
|
| 136 |
molecule_table: str,
|
|
@@ -143,7 +150,7 @@ def query_genmol(
|
|
| 143 |
):
|
| 144 |
bundle = bundle.copy()
|
| 145 |
|
| 146 |
-
response = query_bionemo_nim(
|
| 147 |
url="https://health.api.nvidia.com/v1/biology/nvidia/genmol/generate",
|
| 148 |
payload={
|
| 149 |
"smiles": bundle.dfs[molecule_table][molecule_column].iloc[0],
|
|
@@ -161,7 +168,7 @@ def query_genmol(
|
|
| 161 |
|
| 162 |
@op("Query DiffDock")
|
| 163 |
@mem.cache
|
| 164 |
-
def query_diffdock(
|
| 165 |
proteins: Bundle,
|
| 166 |
ligands: Bundle,
|
| 167 |
*,
|
|
@@ -174,7 +181,7 @@ def query_diffdock(
|
|
| 174 |
time_divisions=20,
|
| 175 |
num_steps=18,
|
| 176 |
):
|
| 177 |
-
response = query_bionemo_nim(
|
| 178 |
url="https://health.api.nvidia.com/v1/biology/mit/diffdock",
|
| 179 |
payload={
|
| 180 |
"protein": proteins.dfs[protein_table][protein_column].iloc[0],
|
|
@@ -187,17 +194,11 @@ def query_diffdock(
|
|
| 187 |
)
|
| 188 |
bundle = Bundle()
|
| 189 |
bundle.dfs["diffdock_table"] = pd.DataFrame()
|
| 190 |
-
bundle.dfs["diffdock_table"]["protein"] = [response["protein"]] * len(
|
| 191 |
-
|
| 192 |
-
)
|
| 193 |
-
bundle.dfs["diffdock_table"]["ligand"] = [response["ligand"]] * len(
|
| 194 |
-
response["status"]
|
| 195 |
-
)
|
| 196 |
bundle.dfs["diffdock_table"]["trajectory"] = response["trajectory"]
|
| 197 |
bundle.dfs["diffdock_table"]["ligand_positions"] = response["ligand_positions"]
|
| 198 |
-
bundle.dfs["diffdock_table"]["position_confidence"] = response[
|
| 199 |
-
"position_confidence"
|
| 200 |
-
]
|
| 201 |
bundle.dfs["diffdock_table"]["status"] = response["status"]
|
| 202 |
|
| 203 |
return bundle
|
|
|
|
| 3 |
from lynxkite_graph_analytics import Bundle
|
| 4 |
from lynxkite.core import ops
|
| 5 |
import joblib
|
| 6 |
+
import httpx
|
| 7 |
import pandas as pd
|
| 8 |
import os
|
| 9 |
|
|
|
|
| 15 |
key = os.getenv("NVCF_RUN_KEY")
|
| 16 |
|
| 17 |
|
| 18 |
+
async def query_bionemo_nim(
|
| 19 |
url: str,
|
| 20 |
payload: dict,
|
| 21 |
):
|
|
|
|
| 26 |
}
|
| 27 |
try:
|
| 28 |
print(f"Sending request to {url}")
|
| 29 |
+
async with httpx.AsyncClient(timeout=600) as client:
|
| 30 |
+
response = await client.post(url, json=payload, headers=headers)
|
| 31 |
print(f"Received response from {url}", response.status_code)
|
| 32 |
response.raise_for_status()
|
| 33 |
return response.json()
|
| 34 |
+
except httpx.RequestError as e:
|
| 35 |
raise ValueError(f"Query failed: {e}")
|
| 36 |
|
| 37 |
|
| 38 |
@op("MSA-search")
|
| 39 |
@mem.cache
|
| 40 |
+
async def msa_search(
|
| 41 |
bundle: Bundle,
|
| 42 |
*,
|
| 43 |
protein_table: str,
|
|
|
|
| 49 |
databases: str = "Uniref30_2302,colabfold_envdb_202108",
|
| 50 |
):
|
| 51 |
bundle = bundle.copy()
|
| 52 |
+
bundle.dfs[protein_table]["alignments"] = None
|
| 53 |
+
|
| 54 |
+
formats = [format.strip() for format in output_alignment_formats.split(",")]
|
| 55 |
+
dbs = [db.strip() for db in databases.split(",")]
|
| 56 |
+
|
| 57 |
+
for idx, protein_sequence in enumerate(bundle.dfs[protein_table][protein_column]):
|
| 58 |
+
print(f"Processing protein {idx + 1}/{len(bundle.dfs[protein_table])}")
|
| 59 |
+
|
| 60 |
+
response = await query_bionemo_nim(
|
| 61 |
+
url="https://health.api.nvidia.com/v1/biology/colabfold/msa-search/predict",
|
| 62 |
+
payload={
|
| 63 |
+
"sequence": protein_sequence,
|
| 64 |
+
"e_value": e_value,
|
| 65 |
+
"iterations": iterations,
|
| 66 |
+
"search_type": search_type,
|
| 67 |
+
"output_alignment_formats": formats,
|
| 68 |
+
"databases": dbs,
|
| 69 |
+
},
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
bundle.dfs[protein_table].at[idx, "alignments"] = response["alignments"]
|
| 73 |
+
|
| 74 |
return bundle
|
| 75 |
|
| 76 |
|
| 77 |
@op("Query OpenFold2")
|
| 78 |
@mem.cache
|
| 79 |
+
async def query_openfold2(
|
| 80 |
bundle: Bundle,
|
| 81 |
*,
|
| 82 |
protein_table: str,
|
|
|
|
| 87 |
relax_prediction: bool = False,
|
| 88 |
):
|
| 89 |
bundle = bundle.copy()
|
| 90 |
+
|
| 91 |
+
bundle.dfs[protein_table]["folded_protein"] = None
|
| 92 |
+
selected_models_list = [int(model) for model in selected_models.split(",")]
|
| 93 |
+
|
| 94 |
+
for idx in range(len(bundle.dfs[protein_table])):
|
| 95 |
+
print(f"Processing protein {idx + 1}/{len(bundle.dfs[protein_table])}")
|
| 96 |
+
|
| 97 |
+
protein = bundle.dfs[protein_table][protein_column].iloc[idx]
|
| 98 |
+
alignments = bundle.dfs[alignment_table][alignment_column].iloc[idx]
|
| 99 |
+
|
| 100 |
+
response = await query_bionemo_nim(
|
| 101 |
+
url="https://health.api.nvidia.com/v1/biology/openfold/openfold2/predict-structure-from-msa-and-template",
|
| 102 |
+
payload={
|
| 103 |
+
"sequence": protein,
|
| 104 |
+
"alignments": alignments,
|
| 105 |
+
"selected_models": selected_models_list,
|
| 106 |
+
"relax_prediction": relax_prediction,
|
| 107 |
+
},
|
| 108 |
+
)
|
| 109 |
+
|
| 110 |
+
folded_protein = response["structures_in_ranked_order"].pop(0)["structure"]
|
| 111 |
+
bundle.dfs[protein_table].at[idx, "folded_protein"] = folded_protein
|
| 112 |
+
|
| 113 |
+
bundle.dfs["openfold"] = pd.DataFrame()
|
| 114 |
+
|
| 115 |
return bundle
|
| 116 |
|
| 117 |
|
| 118 |
+
@op("View molecule", view="py3dmol")
|
| 119 |
+
def view_molecule(
|
| 120 |
bundle: Bundle,
|
| 121 |
*,
|
| 122 |
molecule_table: str,
|
| 123 |
molecule_column: str,
|
| 124 |
+
row_index: int = 0,
|
| 125 |
):
|
| 126 |
+
molecule_data = bundle.dfs[molecule_table][molecule_column].iloc[row_index]
|
| 127 |
+
|
| 128 |
return {
|
| 129 |
+
"data": molecule_data,
|
| 130 |
+
"format": "pdb"
|
| 131 |
+
if molecule_data.startswith("ATOM")
|
| 132 |
+
else "sdf"
|
| 133 |
+
if molecule_data.startswith("CTfile")
|
| 134 |
+
else "smiles",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
}
|
| 136 |
|
| 137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 138 |
@op("Query GenMol")
|
| 139 |
@mem.cache
|
| 140 |
+
async def query_genmol(
|
| 141 |
bundle: Bundle,
|
| 142 |
*,
|
| 143 |
molecule_table: str,
|
|
|
|
| 150 |
):
|
| 151 |
bundle = bundle.copy()
|
| 152 |
|
| 153 |
+
response = await query_bionemo_nim(
|
| 154 |
url="https://health.api.nvidia.com/v1/biology/nvidia/genmol/generate",
|
| 155 |
payload={
|
| 156 |
"smiles": bundle.dfs[molecule_table][molecule_column].iloc[0],
|
|
|
|
| 168 |
|
| 169 |
@op("Query DiffDock")
|
| 170 |
@mem.cache
|
| 171 |
+
async def query_diffdock(
|
| 172 |
proteins: Bundle,
|
| 173 |
ligands: Bundle,
|
| 174 |
*,
|
|
|
|
| 181 |
time_divisions=20,
|
| 182 |
num_steps=18,
|
| 183 |
):
|
| 184 |
+
response = await query_bionemo_nim(
|
| 185 |
url="https://health.api.nvidia.com/v1/biology/mit/diffdock",
|
| 186 |
payload={
|
| 187 |
"protein": proteins.dfs[protein_table][protein_column].iloc[0],
|
|
|
|
| 194 |
)
|
| 195 |
bundle = Bundle()
|
| 196 |
bundle.dfs["diffdock_table"] = pd.DataFrame()
|
| 197 |
+
bundle.dfs["diffdock_table"]["protein"] = [response["protein"]] * len(response["status"])
|
| 198 |
+
bundle.dfs["diffdock_table"]["ligand"] = [response["ligand"]] * len(response["status"])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
bundle.dfs["diffdock_table"]["trajectory"] = response["trajectory"]
|
| 200 |
bundle.dfs["diffdock_table"]["ligand_positions"] = response["ligand_positions"]
|
| 201 |
+
bundle.dfs["diffdock_table"]["position_confidence"] = response["position_confidence"]
|
|
|
|
|
|
|
| 202 |
bundle.dfs["diffdock_table"]["status"] = response["status"]
|
| 203 |
|
| 204 |
return bundle
|
lynxkite-core/src/lynxkite/core/ops.py
CHANGED
|
@@ -180,6 +180,7 @@ class Op(BaseConfig):
|
|
| 180 |
"table_view",
|
| 181 |
"graph_creation_view",
|
| 182 |
"image",
|
|
|
|
| 183 |
]:
|
| 184 |
# If the operation is some kind of visualization, we use the output as the
|
| 185 |
# value to display by default.
|
|
|
|
| 180 |
"table_view",
|
| 181 |
"graph_creation_view",
|
| 182 |
"image",
|
| 183 |
+
"py3dmol",
|
| 184 |
]:
|
| 185 |
# If the operation is some kind of visualization, we use the output as the
|
| 186 |
# value to display by default.
|