File size: 9,132 Bytes
9c9b678 8fa7790 9c9b678 ca6c875 9c9b678 ca6c875 9c9b678 ca6c875 9c9b678 f5aaba7 9c9b678 e36a5ab 1989e40 9c9b678 f5aaba7 e36a5ab 9c9b678 e36a5ab 9c9b678 1989e40 9c9b678 f5aaba7 9c9b678 1989e40 e36a5ab 9c9b678 671cbc6 9c9b678 1989e40 9c9b678 f5aaba7 9c9b678 e36a5ab 9c9b678 081f4b5 9c9b678 4cd2990 9c9b678 f5aaba7 9c9b678 671cbc6 9c9b678 |
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 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
from e_smiles import *
import gradio as gr
from rdkit import Chem
from rdkit.Chem import Draw
import os
def remove_atom_mapping_and_isotopes(smiles):
mol = Chem.MolFromSmiles(smiles)
if mol is None:
raise ValueError("Invalid SMILES string")
for atom in mol.GetAtoms():
atom.SetIsotope(0)
atom.SetAtomMapNum(0)
clean_smiles = Chem.MolToSmiles(Chem.RemoveHs(mol))
return clean_smiles
def get_bondtype_and_convert2string(mol, atom1_idx, atom2_idx):
atom1_idx = int(atom1_idx)
atom2_idx = int(atom2_idx)
bond = mol.GetBondBetweenAtoms(atom1_idx - 1, atom2_idx - 1)
if bond is None:
raise ValueError("Atoms are not bonded")
if bond.GetBondType() == Chem.BondType.SINGLE:
return '1.0'
elif bond.GetBondType() == Chem.BondType.DOUBLE:
return '2.0'
elif bond.GetBondType() == Chem.BondType.TRIPLE:
return '3.0'
else:
raise ValueError("Unsupported bond type")
def main_interface(smiles):
img, mapped_smiles, secondary_inputs_visible1, secondary_inputs_visible2, error = process_smiles(smiles)
return img, mapped_smiles, gr.update(visible=True), secondary_inputs_visible2, error
def process_smiles(smiles):
try:
smiles = remove_atom_mapping_and_isotopes(smiles)
mol = Chem.MolFromSmiles(smiles)
if mol:
Chem.Kekulize(mol, clearAromaticFlags=True)
for atom in mol.GetAtoms():
atom.SetAtomMapNum(atom.GetIdx() + 1)
mapped_smiles = Chem.MolToSmiles(mol, canonical=False, kekuleSmiles=True)
else:
raise ValueError("Invalid SMILES string")
mol = Chem.MolFromSmiles(mapped_smiles)
img = Draw.MolToImage(mol, size=(450, 450))
return img, mapped_smiles, gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)
except Exception as e:
return None, None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=True, value=str(e))
def process_bond_operation(smiles, atom1_idx, atom2_idx, operation):
try:
mol = Chem.MolFromSmiles(smiles)
if mol is None:
raise ValueError("Invalid SMILES string")
if atom1_idx > atom2_idx:
atom1_idx, atom2_idx = atom2_idx, atom1_idx
first = str(atom1_idx)
second = str(atom2_idx)
third = get_bondtype_and_convert2string(mol, atom1_idx, atom2_idx)
if operation == "break this bond":
prompt = [first + ':' + second + ':' + third + ':' + '0.0']
elif operation == "change this bond to single bond":
prompt = [first + ':' + second + ':' + third + ':' + '1.0']
elif operation == "change this bond to double bond":
prompt = [first + ':' + second + ':' + third + ':' + '2.0']
elif operation == "change this bond to triple bond":
prompt = [first + ':' + second + ':' + third + ':' + '3.0']
else:
raise ValueError("Unsupported operation")
prompt = get_b_smiles_check([smiles, prompt, [], [], [], [], []])
return prompt, gr.update(visible=False)
except Exception as e:
return None, gr.update(visible=True, value=str(e))
def retrosynthesis(reactant, prompt):
# 1. generate src file
with open('tmp_data/src.txt', 'w') as f:
f.write(" ".join(prompt))
# 2. inference
os.system('bash infer.sh')
# 3. readout reactseq
with open('./tmp_data/tgt.txt', 'r') as f:
lines = f.readlines()
reactseq_list = []
reactant_smiles = []
for line in lines:
line = line.replace(" ", "").rstrip("\n")
reactseq_list.append(line)
rxn = reactant + ">>>" + line
# 4. merge reactseq
reactant_smiles.append(merge_smiles_with_mapping(rxn))
# 5. draw reactants
reactants = []
reactant_images = []
for smiles in reactant_smiles:
mol = Chem.MolFromSmiles(smiles)
reactants.append(smiles)
reactant_images.append(Draw.MolToImage(mol, size=(600, 600)))
return reactseq_list, reactants, reactant_images
prompt_output = gr.Textbox(label="Prompt", interactive=False, visible=True)
def secondary_interface(smiles, atom1_idx, atom2_idx, operation, progress=gr.Progress()):
try:
prompt, error = process_bond_operation(smiles, atom1_idx, atom2_idx, operation)
if prompt:
reactseq_list, reactant_smiles, reactant_images = retrosynthesis(smiles, prompt)
output_components = [gr.update(value=prompt)]
for i in range(len(reactant_smiles)):
if reactant_smiles[i] != "":
output_components.append(gr.update(value=reactseq_list[i], visible=True))
output_components.append(gr.update(value=reactant_smiles[i], visible=True))
output_components.append(gr.update(value=reactant_images[i], visible=True))
else:
output_components.append(gr.update(visible=False))
output_components.append(gr.update(visible=False))
output_components.append(gr.update(visible=False))
output_components.append(gr.update(visible=False)) # error_output
return output_components
else:
return [gr.update(visible=False)] * 31 + [error]
except Exception as e:
return [gr.update(visible=False)] * 31 + [gr.update(visible=True, value=str(e))]
def clear_interface():
return (
gr.update(value=None), # smiles_input
gr.update(value=None), # img_output
gr.update(value=None), # smiles_output
gr.update(visible=False), # secondary_inputs
gr.update(visible=False), # secondary_inputs
gr.update(visible=False, value=None), # error_output
gr.update(value=None, visible=True), # prompt_output
) + ( # Reactant SMILES and Images
tuple(gr.update(value=None, visible=False) for _ in range(30))
)
# 示例数据
examples = [
["N#CC1=CC=C(C(N2N=CN=C2)C(O)CC3=CC=C(F)C=C3)C=C1", 7, 18, "break this bond"],
["N#CC1=CC=C(C(N2N=CN=C2)C(O)CC3=CC=C(F)C=C3)C=C1", 8, 9, "change this bond to double bond"],
["N#CC1=CC=C(C(N2N=CN=C2)C(O)CC3=CC=C(F)C=C3)C=C1", 1, 2, "change this bond to single bond"],
]
with gr.Blocks() as interface:
gr.Markdown("# ReactSeq")
gr.Markdown("Please input a SMILES string and two atom indices between the bond which you want to perform an operation.")
gr.Markdown("The operation can be one of the following: break this bond, change this bond to single bond, change this bond to double bond, change this bond to triple bond.")
gr.Markdown("The molecule image and SMILES with atom mapping will be displayed.")
gr.Markdown("After you input the operation, the prompt will be displayed.")
gr.Markdown("The reactants SMILES and images will be displayed after the retrosynthesis with **default** ranking, with the invalid ones deleted.")
smiles_input = gr.Textbox(placeholder="Please input your SMILES string", label="SMILES input")
submit_smiles_button = gr.Button("Submit SMILES")
gr.Markdown("The molecule image and SMILES with atom mapping:")
img_output = gr.Image(label="Molecule image")
smiles_output = gr.Textbox(label="SMILES with atom mapping", interactive=False)
with gr.Row(visible=False) as secondary_inputs:
atom1_idx = gr.Number(label="The first atom index", minimum=1)
atom2_idx = gr.Number(label="The second atom index", minimum=1)
operation = gr.Dropdown(choices=["break this bond", "change this bond to single bond", "change this bond to double bond", "change this bond to triple bond"], label="Operation")
submit_operation_button = gr.Button("Submit Operation")
prompt_output = gr.Textbox(label="Prompt", interactive=False, visible=True)
result_row = []
for i in range(10):
result_row.append(gr.Textbox(label=f"Reactseq {i+1} ", interactive=False, visible=False))
result_row.append(gr.Textbox(label=f"Reactant {i+1} SMILES", interactive=False, visible=False))
result_row.append(gr.Image(label=f"Reactant {i+1} Image", visible=False))
error_output = gr.Textbox(label="Error Message", interactive=False, visible=False)
clear_button = gr.Button("Clear")
submit_smiles_button.click(main_interface, inputs=[smiles_input], outputs=[img_output, smiles_output, secondary_inputs, secondary_inputs, error_output])
submit_operation_button.click(
secondary_interface,
inputs=[smiles_output, atom1_idx, atom2_idx, operation],
outputs=[prompt_output] + result_row + [error_output]
)
clear_button.click(
clear_interface,
inputs=[],
outputs=[smiles_input, img_output, smiles_output, secondary_inputs, secondary_inputs, error_output, prompt_output] + result_row
)
gr.Examples(examples=examples, inputs=[smiles_input, atom1_idx, atom2_idx, operation])
interface.launch()
|