Oopstom commited on
Commit
9c9b678
·
verified ·
1 Parent(s): e0c42da

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -0
app.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from e_smiles import *
2
+ import gradio as gr
3
+ from rdkit import Chem
4
+ from rdkit.Chem import Draw
5
+ import os
6
+
7
+ def remove_atom_mapping_and_isotopes(smiles):
8
+ mol = Chem.MolFromSmiles(smiles)
9
+
10
+ if mol is None:
11
+ raise ValueError("Invalid SMILES string")
12
+
13
+ for atom in mol.GetAtoms():
14
+ atom.SetIsotope(0)
15
+ atom.SetAtomMapNum(0)
16
+
17
+ clean_smiles = Chem.MolToSmiles(Chem.RemoveHs(mol))
18
+ return clean_smiles
19
+
20
+ def get_bondtype_and_convert2string(mol, atom1_idx, atom2_idx):
21
+ atom1_idx = int(atom1_idx)
22
+ atom2_idx = int(atom2_idx)
23
+ bond = mol.GetBondBetweenAtoms(atom1_idx - 1, atom2_idx - 1)
24
+ if bond is None:
25
+ raise ValueError("Atoms are not bonded")
26
+
27
+ if bond.GetBondType() == Chem.BondType.SINGLE:
28
+ return '1.0'
29
+ elif bond.GetBondType() == Chem.BondType.DOUBLE:
30
+ return '2.0'
31
+ elif bond.GetBondType() == Chem.BondType.TRIPLE:
32
+ return '3.0'
33
+ else:
34
+ raise ValueError("Unsupported bond type")
35
+
36
+ def main_interface(smiles):
37
+ img, mapped_smiles, secondary_inputs_visible1, secondary_inputs_visible2, error = process_smiles(smiles)
38
+ return img, mapped_smiles, gr.update(visible=True), secondary_inputs_visible2, error
39
+
40
+ def process_smiles(smiles):
41
+ try:
42
+ smiles = remove_atom_mapping_and_isotopes(smiles)
43
+ mol = Chem.MolFromSmiles(smiles)
44
+ if mol:
45
+ Chem.Kekulize(mol, clearAromaticFlags=True)
46
+ for atom in mol.GetAtoms():
47
+ atom.SetAtomMapNum(atom.GetIdx() + 1)
48
+
49
+ mapped_smiles = Chem.MolToSmiles(mol, canonical=False, kekuleSmiles=True)
50
+ else:
51
+ raise ValueError("Invalid SMILES string")
52
+
53
+ mol = Chem.MolFromSmiles(mapped_smiles)
54
+ img = Draw.MolToImage(mol, size=(450, 450))
55
+ return img, mapped_smiles, gr.update(visible=True), gr.update(visible=True), gr.update(visible=False)
56
+ except Exception as e:
57
+ return None, None, gr.update(visible=False), gr.update(visible=False), gr.update(visible=True, value=str(e))
58
+
59
+ def process_bond_operation(smiles, atom1_idx, atom2_idx, operation):
60
+ try:
61
+ mol = Chem.MolFromSmiles(smiles)
62
+ if mol is None:
63
+ raise ValueError("Invalid SMILES string")
64
+
65
+ if atom1_idx > atom2_idx:
66
+ atom1_idx, atom2_idx = atom2_idx, atom1_idx
67
+
68
+ first = str(atom1_idx)
69
+ second = str(atom2_idx)
70
+ third = get_bondtype_and_convert2string(mol, atom1_idx, atom2_idx)
71
+
72
+ if operation == "break this bond":
73
+ prompt = [first + ':' + second + ':' + third + ':' + '0.0']
74
+ elif operation == "change this bond to single bond":
75
+ prompt = [first + ':' + second + ':' + third + ':' + '1.0']
76
+ elif operation == "change this bond to double bond":
77
+ prompt = [first + ':' + second + ':' + third + ':' + '2.0']
78
+ elif operation == "change this bond to triple bond":
79
+ prompt = [first + ':' + second + ':' + third + ':' + '3.0']
80
+ else:
81
+ raise ValueError("Unsupported operation")
82
+
83
+ prompt = get_b_smiles_check([smiles, prompt, [], [], [], [], []])
84
+
85
+ return prompt, gr.update(visible=False)
86
+ except Exception as e:
87
+ return None, gr.update(visible=True, value=str(e))
88
+
89
+ def retrosynthesis(reactant, prompt):
90
+ # 1. generate src file
91
+ with open('tmp_data/src.txt', 'w') as f:
92
+ f.write(" ".join(prompt))
93
+
94
+ # 2. inference
95
+ os.system('bash infer.sh')
96
+
97
+
98
+ # 3. readout reactseq
99
+ with open('./tmp_data/tgt.txt', 'r') as f:
100
+ lines = f.readlines()
101
+
102
+ reactseq_list = []
103
+ for line in lines:
104
+ line = line.replace(" ", "").rstrip("\n")
105
+ reactseq_list.append(reactant + ">>>" + line)
106
+
107
+ # 4. merge reactseq
108
+ reactant_smiles = []
109
+ for seq in reactseq_list:
110
+ reactant_smiles.append(merge_smiles_with_mapping(seq))
111
+
112
+ # 5. draw reactants
113
+ reactants = []
114
+ reactant_images = []
115
+ for smiles in reactant_smiles:
116
+ mol = Chem.MolFromSmiles(smiles)
117
+ reactants.append(smiles)
118
+ reactant_images.append(Draw.MolToImage(mol, size=(600, 600)))
119
+
120
+ return reactants, reactant_images
121
+
122
+ def secondary_interface(smiles, atom1_idx, atom2_idx, operation):
123
+ try:
124
+ prompt, error = process_bond_operation(smiles, atom1_idx, atom2_idx, operation)
125
+
126
+ if prompt:
127
+ reactant_smiles, reactant_images = retrosynthesis(smiles, prompt)
128
+ output_components = [gr.update(value=prompt, visible=True)] # prompt_output
129
+
130
+ # Add the reactant SMILES and images
131
+ for i in range(len(reactant_smiles)):
132
+ output_components.append(gr.update(value=reactant_smiles[i], visible=True))
133
+ output_components.append(gr.update(value=reactant_images[i], visible=True))
134
+
135
+ # Fill remaining hidden outputs
136
+ for j in range(len(reactant_smiles), 10):
137
+ output_components.append(gr.update(visible=False))
138
+ output_components.append(gr.update(visible=False))
139
+
140
+ output_components.append(gr.update(visible=False)) # error_output
141
+ return output_components
142
+
143
+ else:
144
+ return [gr.update(visible=False)] * 21 + [error] # Assuming 10 pairs of outputs + prompt_output + error_output
145
+
146
+ except Exception as e:
147
+ return [gr.update(visible=False)] * 21 + [gr.update(visible=True, value=str(e))]
148
+
149
+ def clear_interface():
150
+ return (
151
+ gr.update(value=None), # img_output
152
+ gr.update(value=None), # smiles_output
153
+ gr.update(visible=False), # secondary_inputs
154
+ gr.update(visible=False), # secondary_inputs
155
+ gr.update(visible=False, value=None), # error_output
156
+ gr.update(value=None, visible=False), # prompt_output
157
+ ) + ( # Reactant SMILES and Images
158
+ tuple(gr.update(value=None, visible=False) for _ in range(20))
159
+ )
160
+
161
+ # 示例数据
162
+ examples = [
163
+ ["N#CC1=CC=C(C(N2N=CN=C2)C(O)CC3=CC=C(F)C=C3)C=C1", 7, 18, "break this bond"],
164
+ ["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"],
165
+ ["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"],
166
+ ]
167
+
168
+ with gr.Blocks() as interface:
169
+ gr.Markdown("# ReactSeq")
170
+ gr.Markdown("Please input a SMILES string and two atom indices between the bond which you want to perform an operation.")
171
+ 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.")
172
+ gr.Markdown("The molecule image and SMILES with atom mapping will be displayed.")
173
+ gr.Markdown("After you input the operation, the prompt will be displayed.")
174
+ gr.Markdown("The reactants SMILES and images will be displayed after the retrosynthesis with **default** ranking.")
175
+
176
+ smiles_input = gr.Textbox(placeholder="Please input your SMILES string", label="SMILES input")
177
+ submit_smiles_button = gr.Button("Submit SMILES")
178
+
179
+ gr.Markdown("The molecule image and SMILES with atom mapping:")
180
+ img_output = gr.Image(label="Molecule image")
181
+ smiles_output = gr.Textbox(label="SMILES with atom mapping", interactive=False)
182
+
183
+ with gr.Row(visible=False) as secondary_inputs:
184
+ atom1_idx = gr.Number(label="The first atom index", minimum=1)
185
+ atom2_idx = gr.Number(label="The second atom index", minimum=2)
186
+ 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")
187
+ submit_operation_button = gr.Button("Submit Operation")
188
+
189
+ prompt_output = gr.Textbox(label="Prompt", interactive=False, visible=False)
190
+
191
+ result_row = []
192
+ for i in range(10):
193
+ result_row.append(gr.Textbox(label=f"Reactant {i+1} SMILES", interactive=False, visible=False))
194
+ result_row.append(gr.Image(label=f"Reactant {i+1} Image", visible=False))
195
+
196
+ error_output = gr.Textbox(label="Error Message", interactive=False, visible=False)
197
+
198
+ # 添加清除按钮
199
+ clear_button = gr.Button("Clear")
200
+
201
+ submit_smiles_button.click(main_interface, inputs=[smiles_input], outputs=[img_output, smiles_output, secondary_inputs, secondary_inputs, error_output])
202
+ submit_operation_button.click(
203
+ secondary_interface,
204
+ inputs=[smiles_output, atom1_idx, atom2_idx, operation],
205
+ outputs=[prompt_output] + result_row + [error_output]
206
+ )
207
+
208
+ # 清除按钮的事件处理
209
+ clear_button.click(
210
+ clear_interface,
211
+ inputs=[],
212
+ outputs=[img_output, smiles_output, secondary_inputs, secondary_inputs, error_output, prompt_output] + result_row
213
+ )
214
+
215
+ gr.Examples(examples=examples, inputs=[smiles_input, atom1_idx, atom2_idx, operation])
216
+
217
+ interface.launch()
218
+
219
+
220
+