Spaces:
Sleeping
Sleeping
File size: 6,233 Bytes
c98108b 9c759ad c98108b b169fb2 c98108b b169fb2 c98108b b169fb2 c98108b b169fb2 c98108b b169fb2 c98108b 9c759ad c98108b 9c759ad c98108b b169fb2 c98108b 9c759ad c98108b 6fb723e c98108b 6fb723e 9c759ad c98108b 9c759ad c98108b 9c759ad 6fb723e c98108b 6fb723e b169fb2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | import gradio as gr
import pandas as pd
import time
# --- 模拟后端功能 (来自第二个版本) ---
def smiles_to_structure(smiles):
"""Dummy function"""
time.sleep(1)
return f"Structure Generated from: {smiles}"
def fragment_molecule(smiles):
"""Dummy function"""
time.sleep(2)
return "Fragment1", "Fragment2", "1-2"
def generate_analogs(main_cls, minor_cls, number, delta_value):
"""Dummy function"""
time.sleep(3)
return [
{"SMILE": "c1cccc1", "MolWt": 100, "TPSA": 20, "SLogP": 1, "SA": 30, "QED": 0.8},
{"SMILE": "c1ccccc1", "MolWt": 105, "TPSA": 25, "SLogP": 1.2, "SA": 32, "QED": 0.9},
]
def update_output_table(data):
df = pd.DataFrame(data)
return df
# --- Gradio 界面 ---
KETCHER_HTML = r'''
<iframe id="ifKetcher" src="/ketcher/index.html" width="100%" height="600px" style="border: 1px solid #ccc;"></iframe>
<script>
console.log("[Front-end] Ketcher-Gradio integration script loaded.");
let ketcher = null;
let lastSmiles = '';
function findSmilesInput() {
const inputContainer = document.getElementById('combined_smiles_input');
if (!inputContainer) {
console.warn("[Front-end] combined_smiles_input element not found.");
return null;
}
const input = inputContainer.querySelector('input[type="text"]');
return input;
}
function updateGradioInput(smiles) {
const input = findSmilesInput();
if (input && input.value !== smiles) {
input.value = smiles;
input.dispatchEvent(new Event('input', { bubbles: true }));
console.log("[Front-end] Updated Gradio input with SMILES:", smiles);
}
}
async function handleKetcherChange() {
console.log("[Front-end] handleKetcherChange called, retrieving SMILES...");
try {
const smiles = await ketcher.getSmiles({ arom: false });
console.log("[Front-end] SMILES retrieved from Ketcher:", smiles);
if (smiles !== lastSmiles) {
lastSmiles = smiles;
updateGradioInput(smiles);
}
} catch (err) {
console.error("[Front-end] Error getting SMILES from Ketcher:", err);
}
}
function initKetcher() {
console.log("[Front-end] initKetcher started.");
const iframe = document.getElementById('ifKetcher');
if (!iframe) {
console.error("[Front-end] iframe not found.");
setTimeout(initKetcher, 500);
return;
}
const ketcherWindow = iframe.contentWindow;
if (!ketcherWindow || !ketcherWindow.ketcher) {
console.log("[Front-end] ketcher not yet available in iframe, retrying...");
setTimeout(initKetcher, 500);
return;
}
ketcher = ketcherWindow.ketcher;
console.log("[Front-end] Ketcher instance acquired:", ketcher);
ketcher.setMolecule('C').then(() => {
console.log("[Front-end] Initial molecule set to 'C'.");
});
const editor = ketcher.editor;
if (editor && typeof editor.subscribe === 'function') {
console.log("[Front-end] Using editor.subscribe('change', ...)");
editor.subscribe('change', handleKetcherChange);
} else {
console.error("[Front-end] No suitable event binding found.");
}
}
document.getElementById('ifKetcher').addEventListener('load', () => {
console.log("[Front-end] iframe loaded. Initializing Ketcher in 1s...");
setTimeout(initKetcher, 1000);
});
</script>
'''
def create_combined_interface():
with gr.Blocks() as demo:
gr.Markdown("# Fragment Optimization Tools with Ketcher")
with gr.Row():
with gr.Column(scale=2):
gr.HTML(KETCHER_HTML) # 嵌入 Ketcher,仅加载一次
with gr.Column(scale=1):
gr.Markdown("### Input SMILES (From Ketcher)")
combined_smiles_input = gr.Textbox(
label="",
value="C",
placeholder="SMILES from Ketcher will appear here",
elem_id="combined_smiles_input"
)
get_ketcher_smiles_btn = gr.Button("Get SMILES from Ketcher")
fragment_btn = gr.Button("Fragmentize Molecule")
constant_frag_input = gr.Textbox(label="Constant Fragment", placeholder="SMILES of constant fragment")
variable_frag_input = gr.Textbox(label="Variable Fragment", placeholder="SMILES of variable fragment")
attach_order_input = gr.Textbox(label="Attachment Order", placeholder="Attachment Order of SMILES")
main_cls_dropdown = gr.Dropdown(label="Main Cls", choices=["None", "Cl", "Br"])
minor_cls_dropdown = gr.Dropdown(label="Minor Cls", choices=["None", "Cl", "Br"])
number_input = gr.Number(label="Number", value=5, step=1)
delta_value_slider = gr.Slider(minimum=0, maximum=10, step=1, label="Delta Value", interactive=True)
generate_analogs_btn = gr.Button("Generate")
output_table = gr.Dataframe(headers=["SMILE", "MolWt", "TPSA", "SLogP", "SA", "QED"])
# --- 事件处理 ---
get_ketcher_smiles_btn.click(
fn=None,
inputs=None,
outputs=combined_smiles_input,
js="async () => { const iframe = document.getElementById('ifKetcher'); if(iframe && iframe.contentWindow && iframe.contentWindow.ketcher) { const smiles = await iframe.contentWindow.ketcher.getSmiles(); return smiles; } else { console.error('Ketcher not ready'); return ''; } }"
)
fragment_btn.click(fragment_molecule, inputs=combined_smiles_input, outputs=[constant_frag_input, variable_frag_input, attach_order_input])
def update_table_with_analogs(main_cls, minor_cls, number, delta_value):
analogs_data = generate_analogs(main_cls, minor_cls, number, delta_value)
return update_output_table(analogs_data)
generate_analogs_btn.click(update_table_with_analogs,
inputs=[main_cls_dropdown, minor_cls_dropdown, number_input, delta_value_slider],
outputs=output_table)
return demo
# 创建 Gradio 界面并启动
demo = create_combined_interface()
demo.launch()
|