mirror of
https://github.com/obsidian-desci/Obsidian-Desci.git
synced 2026-07-22 08:50:32 +00:00
equibind
This commit is contained in:
parent
2b3df8035f
commit
3c1d4fc996
9 changed files with 393 additions and 7 deletions
23
main.tsx
23
main.tsx
|
|
@ -10,7 +10,9 @@ import {cat} from './src/ipfs/cat'
|
|||
import {add} from './src/ipfs/add'
|
||||
import { ethers, Signer, Provider, JsonRpcProvider, Wallet } from 'ethers';
|
||||
import ExampleClient from './artifacts/ExampleClient.json'
|
||||
|
||||
import { getMolecule} from './src/plex/getMolecule'
|
||||
import { getProtein} from './src/plex/getProtein'
|
||||
import { runEquibind } from './src/plex/runEquibind'
|
||||
import {
|
||||
ObsidianDesciSettings,
|
||||
ObsidianDesciSettingTab,
|
||||
|
|
@ -65,7 +67,26 @@ export default class ObsidianDesci extends Plugin {
|
|||
name: 'ipfsAdd - Add Json objects referenced by CID',
|
||||
callback: add.bind(this)
|
||||
});
|
||||
this.addCommand({
|
||||
id: 'getMolecule',
|
||||
name: 'getMolecule -fetch an .spf file for plex',
|
||||
callback: getMolecule.bind(this)
|
||||
}),
|
||||
this.addCommand({
|
||||
id: 'getProtein',
|
||||
name: 'getProtein - fetch a .pdb file for plex',
|
||||
callback: getProtein.bind(this)
|
||||
})
|
||||
this.addCommand({
|
||||
id: 'runEquibind',
|
||||
name: 'runEquibind - run equibind on a molecule and protein node',
|
||||
callback: runEquibind.bind(this)
|
||||
})
|
||||
this.addSettingTab(new ObsidianDesciSettingTab(this.app, this));
|
||||
|
||||
|
||||
this.registerExtensions(["sdf"], "markdown");
|
||||
this.registerExtensions(["pdb"], "markdown");
|
||||
}
|
||||
|
||||
onunload() {
|
||||
|
|
|
|||
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -31,7 +31,7 @@
|
|||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@types/node": "^16.18.61",
|
||||
"@types/pngjs": "^6.0.3",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
|
|
@ -3687,9 +3687,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.18.48",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.48.tgz",
|
||||
"integrity": "sha512-mlaecDKQ7rIZrYD7iiKNdzFb6e/qD5I9U1rAhq+Fd+DWvYVs+G2kv74UFHmSOlg5+i/vF3XxuR522V4u8BqO+Q=="
|
||||
"version": "16.18.61",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.61.tgz",
|
||||
"integrity": "sha512-k0N7BqGhJoJzdh6MuQg1V1ragJiXTh8VUBAZTWjJ9cUq23SG0F0xavOwZbhiP4J3y20xd6jxKx+xNUhkMAi76Q=="
|
||||
},
|
||||
"node_modules/@types/pbkdf2": {
|
||||
"version": "3.1.0",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^16.11.6",
|
||||
"@types/node": "^16.18.61",
|
||||
"@types/pngjs": "^6.0.3",
|
||||
"@types/react": "^18.2.21",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
|
|
|
|||
19
src/plex/equibind.py
Normal file
19
src/plex/equibind.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from plex import CoreTools, plex_init, plex_run
|
||||
import sys
|
||||
import json
|
||||
import os
|
||||
|
||||
dir_path = sys.argv[1]
|
||||
protein_path = [f"{dir_path}/{sys.argv[2]}"]
|
||||
small_molecule_path = [f"{dir_path}/{sys.argv[3]}"]
|
||||
wallet_address = sys.argv[4]
|
||||
|
||||
os.environ["RECIPIENT_WALLET"] = wallet_address
|
||||
|
||||
initial_io_cid = plex_init(
|
||||
CoreTools.EQUIBIND.value,
|
||||
protein=protein_path,
|
||||
small_molecule=small_molecule_path,
|
||||
)
|
||||
|
||||
completed_io_cid, io_local_filepath = plex_run(initial_io_cid, dir_path)
|
||||
97
src/plex/getMolecule.ts
Normal file
97
src/plex/getMolecule.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { requestUrl, Vault } from 'obsidian'
|
||||
import { CanvasNode } from 'src/utils/canvas-internal'
|
||||
import * as fs from 'fs'
|
||||
import {
|
||||
createNode,
|
||||
placeholderNoteHeight,
|
||||
assistantColor,
|
||||
getNodeText
|
||||
} from '../utils/canvas-util'
|
||||
|
||||
import { CID } from 'multiformats/cid'
|
||||
|
||||
export const getMolecule = async function () {
|
||||
if (this.unloaded) return
|
||||
|
||||
this.logDebug("attempting to fetch from ipfs")
|
||||
|
||||
const canvas = this.getActiveCanvas()
|
||||
if (!canvas) {
|
||||
this.logDebug('No active canvas')
|
||||
return
|
||||
}
|
||||
const selection = canvas.selection
|
||||
if (selection?.size !== 1) return
|
||||
const values: CanvasNode[] = Array.from(selection.values())
|
||||
const node: CanvasNode = values[0]
|
||||
if (node) {
|
||||
await canvas.requestSave()
|
||||
await sleep(200)
|
||||
|
||||
const settings = this.settings
|
||||
|
||||
const nodeData = node.getData()
|
||||
let nodeText = await getNodeText(node) || ''
|
||||
if (nodeText.length == 0) {
|
||||
this.logDebug('no node Text found')
|
||||
return
|
||||
}
|
||||
|
||||
const created = createNode(canvas, node,
|
||||
{
|
||||
text: `attempting to fetch ${nodeText}`,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
|
||||
try {
|
||||
const res = await requestUrl({
|
||||
url: nodeText,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
//"Content-Type": "text/plain",
|
||||
}
|
||||
})
|
||||
console.log('res', res.arrayBuffer)
|
||||
const regex = /\/([^/]+)$/;
|
||||
const matches = nodeText.match(regex);
|
||||
const filename = matches ? matches[1] : "";
|
||||
const buffer = Buffer.from(res.arrayBuffer);
|
||||
fs.writeFile(`${this.app.vault.adapter.basePath}/${filename}`, buffer, 'base64', (error) => {
|
||||
if (error) {
|
||||
console.error('Error saving image:', error);
|
||||
} else {
|
||||
const file = this.app.vault.getAbstractFileByPath(`${filename}`)
|
||||
const cidNode = createNode(canvas, created,
|
||||
{
|
||||
file,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
} catch (e) {
|
||||
const cideNodeError = createNode(canvas, created,
|
||||
{
|
||||
text: `error: ${e}`,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
97
src/plex/getProtein.ts
Normal file
97
src/plex/getProtein.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
import { requestUrl, Vault } from 'obsidian'
|
||||
import { CanvasNode } from 'src/utils/canvas-internal'
|
||||
import * as fs from 'fs'
|
||||
import {
|
||||
createNode,
|
||||
placeholderNoteHeight,
|
||||
assistantColor,
|
||||
getNodeText
|
||||
} from '../utils/canvas-util'
|
||||
|
||||
import { CID } from 'multiformats/cid'
|
||||
|
||||
export const getProtein = async function () {
|
||||
if (this.unloaded) return
|
||||
|
||||
this.logDebug("attempting to fetch from ipfs")
|
||||
|
||||
const canvas = this.getActiveCanvas()
|
||||
if (!canvas) {
|
||||
this.logDebug('No active canvas')
|
||||
return
|
||||
}
|
||||
const selection = canvas.selection
|
||||
if (selection?.size !== 1) return
|
||||
const values: CanvasNode[] = Array.from(selection.values())
|
||||
const node: CanvasNode = values[0]
|
||||
if (node) {
|
||||
await canvas.requestSave()
|
||||
await sleep(200)
|
||||
|
||||
const settings = this.settings
|
||||
|
||||
const nodeData = node.getData()
|
||||
let nodeText = await getNodeText(node) || ''
|
||||
if (nodeText.length == 0) {
|
||||
this.logDebug('no node Text found')
|
||||
return
|
||||
}
|
||||
|
||||
const created = createNode(canvas, node,
|
||||
{
|
||||
text: `attempting to fetch ${nodeText}`,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
|
||||
try {
|
||||
const res = await requestUrl({
|
||||
url: nodeText,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
//"Content-Type": "text/plain",
|
||||
}
|
||||
})
|
||||
console.log('res', res.arrayBuffer)
|
||||
const regex = /\/([^/]+)$/;
|
||||
const matches = nodeText.match(regex);
|
||||
const filename = matches ? matches[1] : "";
|
||||
const buffer = Buffer.from(res.arrayBuffer);
|
||||
fs.writeFile(`${this.app.vault.adapter.basePath}/${filename}`, buffer, 'base64', (error) => {
|
||||
if (error) {
|
||||
console.error('Error saving image:', error);
|
||||
} else {
|
||||
const file = this.app.vault.getAbstractFileByPath(`${filename}`)
|
||||
const cidNode = createNode(canvas, created,
|
||||
{
|
||||
file,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
} catch (e) {
|
||||
const cideNodeError = createNode(canvas, created,
|
||||
{
|
||||
text: `error: ${e}`,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
140
src/plex/runEquibind.ts
Normal file
140
src/plex/runEquibind.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import { requestUrl, Vault } from 'obsidian'
|
||||
import { CanvasNode } from 'src/utils/canvas-internal'
|
||||
import * as fs from 'fs'
|
||||
import {
|
||||
createNode,
|
||||
placeholderNoteHeight,
|
||||
assistantColor,
|
||||
getNodeText
|
||||
} from '../utils/canvas-util'
|
||||
import { exec } from 'child_process'
|
||||
import { CID } from 'multiformats/cid'
|
||||
|
||||
export const runEquibind = async function () {
|
||||
if (this.unloaded) return
|
||||
|
||||
const canvas = this.getActiveCanvas()
|
||||
if (!canvas) {
|
||||
this.logDebug('No active canvas')
|
||||
return
|
||||
}
|
||||
const selection = canvas.selection
|
||||
if (selection?.size !== 2) return
|
||||
const values: CanvasNode[] = Array.from(selection.values())
|
||||
const node: CanvasNode = values[0]
|
||||
const node2: CanvasNode = values[1]
|
||||
if (node) {
|
||||
await canvas.requestSave()
|
||||
await sleep(200)
|
||||
|
||||
const settings = this.settings
|
||||
|
||||
if (!node2.filePath && !node2.filePath) {
|
||||
this.logDebug('no files on path')
|
||||
return
|
||||
}
|
||||
let proteinPath: string | undefined;
|
||||
let moleculePath: string | undefined;
|
||||
|
||||
if (node.filePath?.endsWith('.pdb')) {
|
||||
proteinPath = node.filePath;
|
||||
} else if (node2.filePath?.endsWith('.pdb')) {
|
||||
proteinPath = node2.filePath;
|
||||
}
|
||||
|
||||
if (node.filePath?.endsWith('.sdf')) {
|
||||
moleculePath = node.filePath;
|
||||
} else if (node2.filePath?.endsWith('.sdf')) {
|
||||
moleculePath = node2.filePath;
|
||||
}
|
||||
console.log('moleculePath', moleculePath)
|
||||
console.log('proteinPath', proteinPath)
|
||||
|
||||
|
||||
const created = createNode(canvas, node,
|
||||
{
|
||||
text: `attempting equibind on ${moleculePath} and ${proteinPath}`,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
|
||||
try {
|
||||
const command = `${this.app.vault.adapter.basePath}/${this.app.vault.configDir}/plugins/obsidian-desci/src/plex/equibind.py`
|
||||
const equibind = exec(`python3 ${command} ${this.app.vault.adapter.basePath} ${proteinPath} ${moleculePath} ${this.settings.publicKey}`)
|
||||
equibind.stdout?.on('data', (data) => {
|
||||
console.log('stdout:data:', data)
|
||||
const regex = /Completed IO JSON CID: (\w+)/;
|
||||
const match = data.match(regex);
|
||||
const cid = match ? match[1] : "";
|
||||
console.log(cid); // Output: QmbijdVrr
|
||||
|
||||
const cideNodeError = createNode(canvas, created,
|
||||
{
|
||||
text: `${cid}`,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
|
||||
})
|
||||
equibind.stderr?.on('data', (data) => {
|
||||
console.log('stderr:data:', data)
|
||||
})
|
||||
equibind.on('close', (code) => {
|
||||
console.log('equibind exited with code:', code)
|
||||
})
|
||||
/*
|
||||
const res = await requestUrl({
|
||||
url: nodeText,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
//"Content-Type": "text/plain",
|
||||
}
|
||||
})
|
||||
console.log('res', res.arrayBuffer)
|
||||
|
||||
const regex = /\/([^/]+)$/;
|
||||
const matches = nodeText.match(regex);
|
||||
const filename = matches ? matches[1] : "";
|
||||
const buffer = Buffer.from(res.arrayBuffer);
|
||||
fs.writeFile(`${this.app.vault.adapter.basePath}/${filename}`, buffer, 'base64', (error) => {
|
||||
if (error) {
|
||||
console.error('Error saving image:', error);
|
||||
} else {
|
||||
const file = this.app.vault.getAbstractFileByPath(`${filename}`)
|
||||
const cidNode = createNode(canvas, created,
|
||||
{
|
||||
file,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
} catch (e) {
|
||||
const cideNodeError = createNode(canvas, created,
|
||||
{
|
||||
text: `error: ${e}`,
|
||||
size: { height: placeholderNoteHeight }
|
||||
},
|
||||
{
|
||||
color: assistantColor,
|
||||
chat_role: 'assistant'
|
||||
}
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import type ObsidianDesci from '../main'
|
||||
import { App, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
|
||||
import {ethers} from 'ethers'
|
||||
interface ChainConfig {
|
||||
name: string;
|
||||
rpcUrl: string;
|
||||
|
|
@ -9,12 +9,14 @@ interface ChainConfig {
|
|||
|
||||
export interface ObsidianDesciSettings {
|
||||
privateKey: string;
|
||||
publicKey: string;
|
||||
chain: ChainConfig;
|
||||
kuboRpc: string;
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: ObsidianDesciSettings = {
|
||||
privateKey: '',
|
||||
publicKey: '',
|
||||
chain: {
|
||||
name: 'lilypad',
|
||||
rpcUrl: 'http://testnet.lilypadnetwork.org:8545',
|
||||
|
|
@ -44,6 +46,7 @@ export class ObsidianDesciSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.privateKey)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.privateKey = value;
|
||||
this.plugin.settings.publicKey = new ethers.Wallet(value).address,
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
new Setting(containerEl)
|
||||
|
|
|
|||
|
|
@ -6,3 +6,12 @@ available in the app when your plugin is enabled.
|
|||
If your plugin does not need CSS, delete this file.
|
||||
|
||||
*/
|
||||
|
||||
div[data-path^="sdf"]{
|
||||
color: #9999996e;
|
||||
display: flex;
|
||||
}
|
||||
div[data-path*="sdf"]{
|
||||
color: #9999996e;
|
||||
display: flex;
|
||||
}
|
||||
Loading…
Reference in a new issue