This commit is contained in:
Taylor Hulsmans 2023-11-11 15:57:26 -08:00
parent 2b3df8035f
commit 3c1d4fc996
9 changed files with 393 additions and 7 deletions

View file

@ -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
View file

@ -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",

View file

@ -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
View 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
View 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
View 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
View 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'
}
)
}
}
}

View file

@ -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)

View file

@ -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;
}