Spaces:
Sleeping
Sleeping
Minor bug fixes
Browse files- app/fn.py +1 -20
- app/main.py +31 -20
- inference.py +2 -4
- requirements.txt +1 -0
- results/job_db.json +1 -15
app/fn.py
CHANGED
@@ -12,14 +12,13 @@ import tempfile
|
|
12 |
|
13 |
import pandas as pd
|
14 |
from bokeh.models import NumberFormatter, BooleanFormatter, HTMLTemplateFormatter
|
15 |
-
from bokeh.resources import INLINE
|
16 |
import gradio as gr
|
17 |
import pytz
|
18 |
import panel as pn
|
19 |
import seaborn as sns
|
20 |
from markdown import markdown
|
21 |
from rdkit import Chem, RDConfig
|
22 |
-
from rdkit.Chem import Crippen, Descriptors, rdMolDescriptors, Lipinski, rdmolops
|
23 |
import requests
|
24 |
|
25 |
from app import static
|
@@ -425,29 +424,11 @@ def create_result_table_html(summary_df, result_info, opts=(), progress=gr.Progr
|
|
425 |
image_zoom_formatter = HTMLTemplateFormatter(
|
426 |
template='<img src="data:image/svg+xml,<%= value %>" alt="Molecule" class="zoom-img">'
|
427 |
)
|
428 |
-
uniprot_id_formatter = HTMLTemplateFormatter(
|
429 |
-
template='<% if (value == value) { ' # Check if value is not NaN
|
430 |
-
'if (/^[OPQ][0-9][A-Z0-9]{3}[0-9]|[A-NR-Z][0-9]([A-Z][A-Z0-9]{2}[0-9]){1,2}$/.test(value)) '
|
431 |
-
# Check if value is a valid UniProt ID
|
432 |
-
'{ %><a href="https://www.uniprot.org/uniprotkb/<%= value %>" target="_blank"><%= value %></a><% '
|
433 |
-
# Else treat it as a sequence or other plain-text string, line-warping every 60 characters
|
434 |
-
'} else { %><div style="white-space: pre-wrap;"><%= value.match(/.{1,60}/g).join("<br>") '
|
435 |
-
'%></div><% } %><% } else { %><% } %>' # Output empty string if value is NaN
|
436 |
-
)
|
437 |
-
pubchem_id_formatter = HTMLTemplateFormatter(
|
438 |
-
template='<% if (value == value) { ' # Check if value is not NaN
|
439 |
-
'%><a href="https://pubchem.ncbi.nlm.nih.gov/#query=<%= value %>" '
|
440 |
-
'target="_blank"><%= value %></a>'
|
441 |
-
'<% } else { %><% } %>' # Output empty string if value is NaN
|
442 |
-
)
|
443 |
bool_formatters = {col: BooleanFormatter() for col in bool_cols}
|
444 |
float_formatters = {col: NumberFormatter(format='0.000') for col in html_df.select_dtypes('floating').columns}
|
445 |
other_formatters = {
|
446 |
'Compound': image_zoom_formatter,
|
447 |
# 'Scaffold': image_zoom_formatter,
|
448 |
-
# 'Target FASTA': {'type': 'textarea', 'width': 60},
|
449 |
-
'Target ID': uniprot_id_formatter,
|
450 |
-
# 'Compound ID': pubchem_id_formatter, ## TODO: add link to click for adding mol to the viewer
|
451 |
'Pose': {'type': 'molDisplayButtonFormatter'},
|
452 |
}
|
453 |
formatters = {**bool_formatters, **float_formatters, **other_formatters}
|
|
|
12 |
|
13 |
import pandas as pd
|
14 |
from bokeh.models import NumberFormatter, BooleanFormatter, HTMLTemplateFormatter
|
|
|
15 |
import gradio as gr
|
16 |
import pytz
|
17 |
import panel as pn
|
18 |
import seaborn as sns
|
19 |
from markdown import markdown
|
20 |
from rdkit import Chem, RDConfig
|
21 |
+
from rdkit.Chem import Crippen, Descriptors, rdMolDescriptors, Lipinski, rdmolops
|
22 |
import requests
|
23 |
|
24 |
from app import static
|
|
|
424 |
image_zoom_formatter = HTMLTemplateFormatter(
|
425 |
template='<img src="data:image/svg+xml,<%= value %>" alt="Molecule" class="zoom-img">'
|
426 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
427 |
bool_formatters = {col: BooleanFormatter() for col in bool_cols}
|
428 |
float_formatters = {col: NumberFormatter(format='0.000') for col in html_df.select_dtypes('floating').columns}
|
429 |
other_formatters = {
|
430 |
'Compound': image_zoom_formatter,
|
431 |
# 'Scaffold': image_zoom_formatter,
|
|
|
|
|
|
|
432 |
'Pose': {'type': 'molDisplayButtonFormatter'},
|
433 |
}
|
434 |
formatters = {**bool_formatters, **float_formatters, **other_formatters}
|
app/main.py
CHANGED
@@ -1,7 +1,6 @@
|
|
1 |
-
import io
|
2 |
-
|
3 |
import spaces
|
4 |
|
|
|
5 |
import os
|
6 |
import tempfile
|
7 |
import uuid
|
@@ -11,6 +10,7 @@ from pathlib import Path
|
|
11 |
from time import sleep, time
|
12 |
import urllib.parse
|
13 |
|
|
|
14 |
import torch
|
15 |
from email_validator import validate_email, EmailNotValidError
|
16 |
from Bio import SeqIO
|
@@ -19,15 +19,17 @@ from gradio_rangeslider import RangeSlider
|
|
19 |
from omegaconf import OmegaConf
|
20 |
import pandas as pd
|
21 |
from rdkit import Chem
|
22 |
-
from rdkit.Chem import PandasTools, Draw
|
23 |
|
24 |
from inference import (read_fragment_library, process_fragment_library, extract_pockets,
|
25 |
dock_fragments, generate_linkers, select_fragment_pairs)
|
26 |
from app import static, fn, db
|
27 |
|
28 |
|
|
|
29 |
Path(tempfile.gettempdir(), 'gradio').mkdir(exist_ok=True)
|
30 |
-
|
|
|
31 |
job_db = db.init_job_db()
|
32 |
os.chmod('./fpocket', 0o755)
|
33 |
|
@@ -82,6 +84,8 @@ It might take a few minutes up to a few hours depending on the input size and th
|
|
82 |
You may keep the page open and wait for job completion, or close the page and revisit later to look up the job status
|
83 |
using the job id. You will also receive an email notification once the job is done.
|
84 |
''',
|
|
|
|
|
85 |
}
|
86 |
if job['status'] == "COMPLETED":
|
87 |
stop = True
|
@@ -94,7 +98,9 @@ using the job id. You will also receive an email notification once the job is do
|
|
94 |
yield {
|
95 |
pred_lookup_status: msg,
|
96 |
tabs: gr.Tabs(selected='result'),
|
97 |
-
result_state: job
|
|
|
|
|
98 |
}
|
99 |
if job['status'] == "FAILED":
|
100 |
stop = True
|
@@ -118,7 +124,7 @@ using the job id. You will also receive an email notification once the job is do
|
|
118 |
yield {
|
119 |
pred_lookup_status: msg,
|
120 |
pred_lookup_btn: gr.Button(visible=stop),
|
121 |
-
pred_lookup_stop_btn: gr.Button(visible=stop),
|
122 |
}
|
123 |
sleep(5)
|
124 |
|
@@ -197,23 +203,22 @@ def dock_link(
|
|
197 |
linker_frag_dist, linker_strategy, linker_n_mols, linker_size, linker_steps,
|
198 |
job_info
|
199 |
):
|
200 |
-
update_info = {}
|
201 |
job_id = job_info['id']
|
|
|
|
|
|
|
|
|
202 |
pocket_extract_method = job_info['pocket_extraction_method']
|
203 |
pocket_path_dict = job_info['protein_pocket_files']
|
|
|
204 |
|
205 |
config = OmegaConf.load('configs/gen_fbdd_v1.yaml')
|
206 |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
207 |
print(f'Using device: {device}')
|
208 |
date_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
209 |
-
out_dir = f'
|
210 |
frag_lib['X2'] = prot
|
211 |
-
frag_lib['ID2'] = Path(prot).stem
|
212 |
-
|
213 |
-
job_db.job_update(
|
214 |
-
job_id=job_id,
|
215 |
-
update_info={'status': 'RUNNING'},
|
216 |
-
)
|
217 |
|
218 |
try:
|
219 |
docking_df = dock_fragments(
|
@@ -272,7 +277,7 @@ def dock_link(
|
|
272 |
update_info = {
|
273 |
'status': "COMPLETED",
|
274 |
'error': None,
|
275 |
-
'output_dir': out_dir,
|
276 |
'type': job_type,
|
277 |
}
|
278 |
# return {result_state: job_info | update_info, run_state: {}}
|
@@ -544,7 +549,7 @@ with gr.Blocks(theme=THEME, title='GenFBDD', css=static.CSS, delete_cache=(3600,
|
|
544 |
info="Your job ID is a UUID4 string that you receive after submitting a job on the "
|
545 |
"page or in the email notification.")
|
546 |
pred_lookup_example = gr.Button('Example', elem_classes=['example'], scale=1)
|
547 |
-
pred_lookup_btn = gr.Button(value='
|
548 |
pred_lookup_stop_btn = gr.Button(value='Stop Tracking', variant='stop', visible=False)
|
549 |
pred_lookup_status = gr.Markdown("**Job Status**", container=True)
|
550 |
|
@@ -645,7 +650,7 @@ with gr.Blocks(theme=THEME, title='GenFBDD', css=static.CSS, delete_cache=(3600,
|
|
645 |
raise ValueError(f"Unsupported method: {method}")
|
646 |
return {input_prot_file: gr.File(str(file), visible=True)}
|
647 |
except Exception as e:
|
648 |
-
|
649 |
|
650 |
prot_query_btn.click(
|
651 |
fn=pdb_query,
|
@@ -759,7 +764,7 @@ with gr.Blocks(theme=THEME, title='GenFBDD', css=static.CSS, delete_cache=(3600,
|
|
759 |
outputs=loader_html,
|
760 |
)
|
761 |
|
762 |
-
job_valid.success(
|
763 |
fn=lambda job: [job['id'], gr.Tabs(selected='job')],
|
764 |
inputs=[run_state],
|
765 |
outputs=[pred_lookup_id, tabs],
|
@@ -767,7 +772,8 @@ with gr.Blocks(theme=THEME, title='GenFBDD', css=static.CSS, delete_cache=(3600,
|
|
767 |
lambda: '<div class="loader"></ div>',
|
768 |
outputs=loader_html,
|
769 |
)
|
770 |
-
|
|
|
771 |
fn=query_job_status,
|
772 |
inputs=pred_lookup_id,
|
773 |
outputs=[pred_lookup_status, tabs, result_state, pred_lookup_btn, pred_lookup_stop_btn],
|
@@ -815,11 +821,13 @@ with gr.Blocks(theme=THEME, title='GenFBDD', css=static.CSS, delete_cache=(3600,
|
|
815 |
else:
|
816 |
raise gr.Error('Invalid result type')
|
817 |
|
|
|
818 |
draw_opts = Draw.rdMolDraw2D.MolDrawOptions()
|
819 |
draw_opts.clearBackground = False
|
820 |
draw_opts.bondLineWidth = 0.5
|
821 |
draw_opts.explicitMethyl = True
|
822 |
draw_opts.singleColourWedgeBonds = True
|
|
|
823 |
draw_opts.useCDKAtomPalette()
|
824 |
PandasTools.drawOptions = draw_opts
|
825 |
PandasTools.molSize = (90, 56)
|
@@ -918,5 +926,8 @@ with gr.Blocks(theme=THEME, title='GenFBDD', css=static.CSS, delete_cache=(3600,
|
|
918 |
demo.launch(
|
919 |
server_name='0.0.0.0',
|
920 |
max_file_size="5mb",
|
921 |
-
ssr_mode=False
|
|
|
|
|
|
|
922 |
)
|
|
|
|
|
|
|
1 |
import spaces
|
2 |
|
3 |
+
import io
|
4 |
import os
|
5 |
import tempfile
|
6 |
import uuid
|
|
|
10 |
from time import sleep, time
|
11 |
import urllib.parse
|
12 |
|
13 |
+
from dotenv import load_dotenv
|
14 |
import torch
|
15 |
from email_validator import validate_email, EmailNotValidError
|
16 |
from Bio import SeqIO
|
|
|
19 |
from omegaconf import OmegaConf
|
20 |
import pandas as pd
|
21 |
from rdkit import Chem
|
22 |
+
from rdkit.Chem import PandasTools, Draw, rdDepictor
|
23 |
|
24 |
from inference import (read_fragment_library, process_fragment_library, extract_pockets,
|
25 |
dock_fragments, generate_linkers, select_fragment_pairs)
|
26 |
from app import static, fn, db
|
27 |
|
28 |
|
29 |
+
load_dotenv()
|
30 |
Path(tempfile.gettempdir(), 'gradio').mkdir(exist_ok=True)
|
31 |
+
SERVER_DATA_DIR = os.getenv('DATA', 'results')
|
32 |
+
gr.set_static_paths(paths=["data/", SERVER_DATA_DIR, "app/"])
|
33 |
job_db = db.init_job_db()
|
34 |
os.chmod('./fpocket', 0o755)
|
35 |
|
|
|
84 |
You may keep the page open and wait for job completion, or close the page and revisit later to look up the job status
|
85 |
using the job id. You will also receive an email notification once the job is done.
|
86 |
''',
|
87 |
+
pred_lookup_btn: gr.Button(visible=False),
|
88 |
+
pred_lookup_stop_btn: gr.Button(visible=True),
|
89 |
}
|
90 |
if job['status'] == "COMPLETED":
|
91 |
stop = True
|
|
|
98 |
yield {
|
99 |
pred_lookup_status: msg,
|
100 |
tabs: gr.Tabs(selected='result'),
|
101 |
+
result_state: job,
|
102 |
+
pred_lookup_btn: gr.Button(visible=True),
|
103 |
+
pred_lookup_stop_btn: gr.Button(visible=False),
|
104 |
}
|
105 |
if job['status'] == "FAILED":
|
106 |
stop = True
|
|
|
124 |
yield {
|
125 |
pred_lookup_status: msg,
|
126 |
pred_lookup_btn: gr.Button(visible=stop),
|
127 |
+
pred_lookup_stop_btn: gr.Button(visible= not stop),
|
128 |
}
|
129 |
sleep(5)
|
130 |
|
|
|
203 |
linker_frag_dist, linker_strategy, linker_n_mols, linker_size, linker_steps,
|
204 |
job_info
|
205 |
):
|
|
|
206 |
job_id = job_info['id']
|
207 |
+
job_db.job_update(
|
208 |
+
job_id=job_id,
|
209 |
+
update_info={'status': 'RUNNING'},
|
210 |
+
)
|
211 |
pocket_extract_method = job_info['pocket_extraction_method']
|
212 |
pocket_path_dict = job_info['protein_pocket_files']
|
213 |
+
update_info = {}
|
214 |
|
215 |
config = OmegaConf.load('configs/gen_fbdd_v1.yaml')
|
216 |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
217 |
print(f'Using device: {device}')
|
218 |
date_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
|
219 |
+
out_dir = Path(SERVER_DATA_DIR, f'{date_time}_{job_id}')
|
220 |
frag_lib['X2'] = prot
|
221 |
+
frag_lib['ID2'] = str(Path(prot).stem)
|
|
|
|
|
|
|
|
|
|
|
222 |
|
223 |
try:
|
224 |
docking_df = dock_fragments(
|
|
|
277 |
update_info = {
|
278 |
'status': "COMPLETED",
|
279 |
'error': None,
|
280 |
+
'output_dir': str(out_dir),
|
281 |
'type': job_type,
|
282 |
}
|
283 |
# return {result_state: job_info | update_info, run_state: {}}
|
|
|
549 |
info="Your job ID is a UUID4 string that you receive after submitting a job on the "
|
550 |
"page or in the email notification.")
|
551 |
pred_lookup_example = gr.Button('Example', elem_classes=['example'], scale=1)
|
552 |
+
pred_lookup_btn = gr.Button(value='Query Status', variant='primary', visible=True)
|
553 |
pred_lookup_stop_btn = gr.Button(value='Stop Tracking', variant='stop', visible=False)
|
554 |
pred_lookup_status = gr.Markdown("**Job Status**", container=True)
|
555 |
|
|
|
650 |
raise ValueError(f"Unsupported method: {method}")
|
651 |
return {input_prot_file: gr.File(str(file), visible=True)}
|
652 |
except Exception as e:
|
653 |
+
gr.Warning(f"Query error: {str(e)}")
|
654 |
|
655 |
prot_query_btn.click(
|
656 |
fn=pdb_query,
|
|
|
764 |
outputs=loader_html,
|
765 |
)
|
766 |
|
767 |
+
job_valid_success = job_valid.success(
|
768 |
fn=lambda job: [job['id'], gr.Tabs(selected='job')],
|
769 |
inputs=[run_state],
|
770 |
outputs=[pred_lookup_id, tabs],
|
|
|
772 |
lambda: '<div class="loader"></ div>',
|
773 |
outputs=loader_html,
|
774 |
)
|
775 |
+
|
776 |
+
auto_job_lookup = job_valid_success.success(
|
777 |
fn=query_job_status,
|
778 |
inputs=pred_lookup_id,
|
779 |
outputs=[pred_lookup_status, tabs, result_state, pred_lookup_btn, pred_lookup_stop_btn],
|
|
|
821 |
else:
|
822 |
raise gr.Error('Invalid result type')
|
823 |
|
824 |
+
rdDepictor.SetPreferCoordGen(True)
|
825 |
draw_opts = Draw.rdMolDraw2D.MolDrawOptions()
|
826 |
draw_opts.clearBackground = False
|
827 |
draw_opts.bondLineWidth = 0.5
|
828 |
draw_opts.explicitMethyl = True
|
829 |
draw_opts.singleColourWedgeBonds = True
|
830 |
+
draw_opts.addStereoAnnotation = False
|
831 |
draw_opts.useCDKAtomPalette()
|
832 |
PandasTools.drawOptions = draw_opts
|
833 |
PandasTools.molSize = (90, 56)
|
|
|
926 |
demo.launch(
|
927 |
server_name='0.0.0.0',
|
928 |
max_file_size="5mb",
|
929 |
+
ssr_mode=False,
|
930 |
+
share=True,
|
931 |
+
share_server_address="ciddr-lab.ac.cn:7000",
|
932 |
+
share_server_protocol="https"
|
933 |
)
|
inference.py
CHANGED
@@ -443,15 +443,13 @@ def dock_fragments(
|
|
443 |
# TODO Use index instead of confidence in filename
|
444 |
if save_docking:
|
445 |
sample_df['ligand_conf_path'] = [
|
446 |
-
|
447 |
-
docking_out_dir, f"{df['name'].iloc[idx]}_{i}-confidence{confidence[i]:.2f}.sdf"
|
448 |
-
) for i in range(n_samples)
|
449 |
]
|
450 |
sample_df['ligand_mol']= [
|
451 |
create_mol_with_coords(
|
452 |
mol=RemoveAllHs(copy.deepcopy(lig)),
|
453 |
new_coords=pos,
|
454 |
-
path=sample_df['ligand_conf_path'].iloc[i] if save_docking else None
|
455 |
) for i, pos in enumerate(ligand_pos)
|
456 |
]
|
457 |
# sample_df['ligand_pos'] = list(ligand_pos)
|
|
|
443 |
# TODO Use index instead of confidence in filename
|
444 |
if save_docking:
|
445 |
sample_df['ligand_conf_path'] = [
|
446 |
+
f"{df['name'].iloc[idx]}_{i}-confidence{confidence[i]:.2f}.sdf" for i in range(n_samples)
|
|
|
|
|
447 |
]
|
448 |
sample_df['ligand_mol']= [
|
449 |
create_mol_with_coords(
|
450 |
mol=RemoveAllHs(copy.deepcopy(lig)),
|
451 |
new_coords=pos,
|
452 |
+
path=Path(docking_out_dir, sample_df['ligand_conf_path'].iloc[i]) if save_docking else None
|
453 |
) for i, pos in enumerate(ligand_pos)
|
454 |
]
|
455 |
# sample_df['ligand_pos'] = list(ligand_pos)
|
requirements.txt
CHANGED
@@ -17,6 +17,7 @@ hydra-core
|
|
17 |
pandas
|
18 |
pandarallel
|
19 |
panel
|
|
|
20 |
seaborn
|
21 |
apscheduler
|
22 |
tinydb
|
|
|
17 |
pandas
|
18 |
pandarallel
|
19 |
panel
|
20 |
+
python-dotenv
|
21 |
seaborn
|
22 |
apscheduler
|
23 |
tinydb
|
results/job_db.json
CHANGED
@@ -1,15 +1 @@
|
|
1 |
-
{
|
2 |
-
"_default": {
|
3 |
-
"1": {
|
4 |
-
"id": "80cf2658-7a1c-48d6-8372-61b978177fe6",
|
5 |
-
"type": "linking",
|
6 |
-
"status": "COMPLETED",
|
7 |
-
"output_dir": "results/2025-01-01_01-01-01_80cf2658-7a1c-48d6-8372-61b978177fe6",
|
8 |
-
"protein_structure_file": "results/2025-01-01_01-01-01_80cf2658-7a1c-48d6-8372-61b978177fe6/1xkk.pdb",
|
9 |
-
"start_time": 1735693261,
|
10 |
-
"end_time": 1735693321,
|
11 |
-
"expiry_time": 1893459721,
|
12 |
-
"ip": "1.1.1.1"
|
13 |
-
}
|
14 |
-
}
|
15 |
-
}
|
|
|
1 |
+
{"_default": {"1": {"id": "80cf2658-7a1c-48d6-8372-61b978177fe6", "type": "linking", "status": "COMPLETED", "output_dir": "results/2025-01-01_01-01-01_80cf2658-7a1c-48d6-8372-61b978177fe6", "protein_structure_file": "results/2025-01-01_01-01-01_80cf2658-7a1c-48d6-8372-61b978177fe6/1xkk.pdb", "start_time": 1735693261, "end_time": 1735693321, "expiry_time": 1893459721, "ip": "1.1.1.1"}}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|