Spaces:
Running on Zero
Running on Zero
simplify status update string by integrating in generate, create stop button
Browse files- app.py +30 -25
- utils/handle_events.py +69 -68
- utils/pipelines.py +11 -1
app.py
CHANGED
|
@@ -64,42 +64,31 @@ with gr.Blocks(title="RFD3 Test") as demo:
|
|
| 64 |
|
| 65 |
""")
|
| 66 |
|
| 67 |
-
#config_ready = gr.State(None) # whether the config is ready for running generation, takes values None, "manual", or "upload"
|
| 68 |
-
#scaffold_ready = gr.State(None) # whether the scaffold is ready for running generation, takes values None, "upload", or "no_input"
|
| 69 |
gen_directory = gr.State(None) # the directory where generation results are saved, used to trigger the download of results as zip file
|
| 70 |
gen_results = gr.State(None) # the results of the generation, which is a list of dicts where each dict contains batch number "batch", design number "design", path to cif file "cif_path", and path to pdb file "pdb_path".
|
| 71 |
|
| 72 |
# inputs from user
|
| 73 |
with gr.Row():
|
| 74 |
with gr.Column(scale=1): # Left half
|
| 75 |
-
#gr.Markdown("Set up the configuration for your run through a valid yaml file. Choose the number of batches and designs per batch for your run.")
|
| 76 |
config_upload = gr.File(label="Config file: .yaml or .json", file_types=[".pdb", ".yaml", ".json"])
|
| 77 |
-
#config_validation_btn = gr.Button("Validate Config")
|
| 78 |
-
#config_textbox = gr.Textbox(label="Configuration status", value ="Waiting for config validation...")
|
| 79 |
-
|
| 80 |
|
| 81 |
with gr.Column(scale=1): # Right half
|
| 82 |
-
#gr.Markdown("Upload your target/scaffold structure as a PDB file to condition the generation. Press 'No Scaffold/Target' if you want to run an unconditional generation.")
|
| 83 |
scaffold_upload = gr.File(label="Target/Scaffold PDB", file_types=[".pdb"])
|
| 84 |
-
#with gr.Row():
|
| 85 |
-
# scaffold_validation_btn = gr.Button("Validate Scaffold")
|
| 86 |
-
# no_input_btn = gr.Button("No Scaffold/Target")
|
| 87 |
-
#scaffold_textbox = gr.Textbox(label="Scaffold/Target status", value ="Waiting for scaffold validation...")
|
| 88 |
|
| 89 |
with gr.Row():
|
| 90 |
num_designs_per_batch = gr.Number(
|
| 91 |
-
value=
|
| 92 |
label="Number of Designs per Batch",
|
| 93 |
precision=0,
|
| 94 |
minimum=1,
|
| 95 |
maximum=16
|
| 96 |
)
|
| 97 |
num_batches= gr.Number(
|
| 98 |
-
value=
|
| 99 |
label="Number of Batches",
|
| 100 |
precision=0,
|
| 101 |
minimum=1,
|
| 102 |
-
maximum=
|
| 103 |
)
|
| 104 |
max_duration = gr.Number(
|
| 105 |
value=3600,
|
|
@@ -117,15 +106,12 @@ with gr.Blocks(title="RFD3 Test") as demo:
|
|
| 117 |
info="Add extra RFD3 CLI arguments here (optional)"
|
| 118 |
)
|
| 119 |
|
| 120 |
-
|
|
|
|
|
|
|
| 121 |
runtextbox = gr.Textbox(label="Run status", value="Waiting for generation run...")
|
| 122 |
|
| 123 |
|
| 124 |
-
# validate the configuration
|
| 125 |
-
#config_validation_btn.click(validate_config_ready, inputs=config_upload, outputs=[config_textbox, config_ready])
|
| 126 |
-
#scaffold_validation_btn.click(validate_scaffold_ready_with_file, inputs=scaffold_upload, outputs=[scaffold_textbox, scaffold_ready])
|
| 127 |
-
#no_input_btn.click(lambda: ("No scaffold/target will be used. Ready for unconditional generation!", "no_input"), outputs=[scaffold_textbox, scaffold_ready])
|
| 128 |
-
|
| 129 |
output_file = gr.File(label="Download RFD3 results as zip", visible=True)
|
| 130 |
|
| 131 |
# Section to inspect PDB of generated structures
|
|
@@ -149,12 +135,17 @@ with gr.Blocks(title="RFD3 Test") as demo:
|
|
| 149 |
if config_upload is None:
|
| 150 |
return gr.update(), None, None
|
| 151 |
else:
|
| 152 |
-
#generate_with_correct_time_limit = generation_with_input_config_factory(max_duration)
|
| 153 |
textbox_update, gen_directory, gen_results = generation_with_input_config(config_upload, scaffold_upload, num_batches, num_designs_per_batch, extra_args, max_duration)
|
| 154 |
print(textbox_update)
|
| 155 |
return textbox_update, gen_directory, gen_results
|
| 156 |
|
| 157 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
generate, inputs=[config_upload, scaffold_upload, num_batches, num_designs_per_batch, extra_args, max_duration], outputs=[runtextbox, gen_directory, gen_results]
|
| 159 |
).then(
|
| 160 |
update_batch_choices,
|
|
@@ -165,9 +156,23 @@ with gr.Blocks(title="RFD3 Test") as demo:
|
|
| 165 |
inputs=gen_directory,
|
| 166 |
outputs=output_file
|
| 167 |
).then(
|
| 168 |
-
lambda
|
| 169 |
-
|
| 170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
)
|
| 172 |
|
| 173 |
|
|
|
|
| 64 |
|
| 65 |
""")
|
| 66 |
|
|
|
|
|
|
|
| 67 |
gen_directory = gr.State(None) # the directory where generation results are saved, used to trigger the download of results as zip file
|
| 68 |
gen_results = gr.State(None) # the results of the generation, which is a list of dicts where each dict contains batch number "batch", design number "design", path to cif file "cif_path", and path to pdb file "pdb_path".
|
| 69 |
|
| 70 |
# inputs from user
|
| 71 |
with gr.Row():
|
| 72 |
with gr.Column(scale=1): # Left half
|
|
|
|
| 73 |
config_upload = gr.File(label="Config file: .yaml or .json", file_types=[".pdb", ".yaml", ".json"])
|
|
|
|
|
|
|
|
|
|
| 74 |
|
| 75 |
with gr.Column(scale=1): # Right half
|
|
|
|
| 76 |
scaffold_upload = gr.File(label="Target/Scaffold PDB", file_types=[".pdb"])
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
|
| 78 |
with gr.Row():
|
| 79 |
num_designs_per_batch = gr.Number(
|
| 80 |
+
value=8,
|
| 81 |
label="Number of Designs per Batch",
|
| 82 |
precision=0,
|
| 83 |
minimum=1,
|
| 84 |
maximum=16
|
| 85 |
)
|
| 86 |
num_batches= gr.Number(
|
| 87 |
+
value=2,
|
| 88 |
label="Number of Batches",
|
| 89 |
precision=0,
|
| 90 |
minimum=1,
|
| 91 |
+
maximum=50
|
| 92 |
)
|
| 93 |
max_duration = gr.Number(
|
| 94 |
value=3600,
|
|
|
|
| 106 |
info="Add extra RFD3 CLI arguments here (optional)"
|
| 107 |
)
|
| 108 |
|
| 109 |
+
with gr.Row():
|
| 110 |
+
run_btn = gr.Button("Run Generation", variant="primary")
|
| 111 |
+
stop_btn = gr.Button("Stop Generation", variant="stop", visible=False)
|
| 112 |
runtextbox = gr.Textbox(label="Run status", value="Waiting for generation run...")
|
| 113 |
|
| 114 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
output_file = gr.File(label="Download RFD3 results as zip", visible=True)
|
| 116 |
|
| 117 |
# Section to inspect PDB of generated structures
|
|
|
|
| 135 |
if config_upload is None:
|
| 136 |
return gr.update(), None, None
|
| 137 |
else:
|
|
|
|
| 138 |
textbox_update, gen_directory, gen_results = generation_with_input_config(config_upload, scaffold_upload, num_batches, num_designs_per_batch, extra_args, max_duration)
|
| 139 |
print(textbox_update)
|
| 140 |
return textbox_update, gen_directory, gen_results
|
| 141 |
|
| 142 |
+
generation_event = run_btn.click(
|
| 143 |
+
lambda: gr.update(visible=False),
|
| 144 |
+
outputs=run_btn
|
| 145 |
+
).then(
|
| 146 |
+
lambda: gr.update(visible=True),
|
| 147 |
+
outputs=stop_btn
|
| 148 |
+
).then(
|
| 149 |
generate, inputs=[config_upload, scaffold_upload, num_batches, num_designs_per_batch, extra_args, max_duration], outputs=[runtextbox, gen_directory, gen_results]
|
| 150 |
).then(
|
| 151 |
update_batch_choices,
|
|
|
|
| 156 |
inputs=gen_directory,
|
| 157 |
outputs=output_file
|
| 158 |
).then(
|
| 159 |
+
lambda: gr.update(visible=True),
|
| 160 |
+
outputs=run_btn
|
| 161 |
+
).then(
|
| 162 |
+
lambda: gr.update(visible=False),
|
| 163 |
+
outputs=stop_btn
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
stop_btn.click(
|
| 167 |
+
lambda: gr.update(value="Generation cancelled by user."),
|
| 168 |
+
outputs=runtextbox,
|
| 169 |
+
cancels=[generation_event]
|
| 170 |
+
).then(
|
| 171 |
+
lambda: gr.update(visible=True),
|
| 172 |
+
outputs=run_btn
|
| 173 |
+
).then(
|
| 174 |
+
lambda: gr.update(visible=False),
|
| 175 |
+
outputs=stop_btn
|
| 176 |
)
|
| 177 |
|
| 178 |
|
utils/handle_events.py
CHANGED
|
@@ -59,71 +59,72 @@ def show_pdb(batch, design, result):
|
|
| 59 |
print(pdb_str)
|
| 60 |
return gr.update(value=f"Selected Batch: {batch}, Design: {design}, saved at {pdb_path}:\n {pdb_str}", visible=True)
|
| 61 |
|
| 62 |
-
def validate_config_ready(config_upload):
|
| 63 |
-
"""
|
| 64 |
-
Once the user presses on the Validate Config button, this function checks whether the config is really ready to go.
|
| 65 |
-
It is ready if the config file is uploaded.
|
| 66 |
-
|
| 67 |
-
Parameters:
|
| 68 |
-
----------
|
| 69 |
-
|
| 70 |
-
config_upload: gr.File
|
| 71 |
-
uploaded config file, is None if no file is uploaded
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
Returns:
|
| 75 |
-
-------
|
| 76 |
-
str: message to the user about the status of the config validation
|
| 77 |
-
str: "upload" if upload, and None if config is not ready for generation.
|
| 78 |
-
"""
|
| 79 |
-
if config_upload is None:
|
| 80 |
-
return "Please upload a config file for the generation to be ready.", None
|
| 81 |
-
return "Config file uploaded!", "upload"
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
def validate_scaffold_ready_with_file(scaffold_upload):
|
| 85 |
-
"""
|
| 86 |
-
Once the user presses on the Validate Scaffold button, this function checks whether a file was indeed uploaded. If not, it prompts the user to upload a file or select no scaffold/target for unconditioned generation.
|
| 87 |
-
|
| 88 |
-
Parameters:
|
| 89 |
-
----------
|
| 90 |
-
scaffold_upload: gr.File
|
| 91 |
-
uploaded scaffold file, is None if no file is uploaded
|
| 92 |
-
|
| 93 |
-
Returns:
|
| 94 |
-
-------
|
| 95 |
-
str: message to the user about the status of the scaffold validation
|
| 96 |
-
str: status string. "upload" if scaffold file is uploaded and valid, None if not.
|
| 97 |
-
"""
|
| 98 |
-
if scaffold_upload is not None:
|
| 99 |
-
return "Scaffold file uploaded and valid!", "upload"
|
| 100 |
-
else:
|
| 101 |
-
return "Please upload a scaffold file or press 'No Scaffold/Target' for unconditional generation.", None
|
| 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 |
-
|
|
|
|
|
|
| 59 |
print(pdb_str)
|
| 60 |
return gr.update(value=f"Selected Batch: {batch}, Design: {design}, saved at {pdb_path}:\n {pdb_str}", visible=True)
|
| 61 |
|
| 62 |
+
#def validate_config_ready(config_upload):
|
| 63 |
+
# """
|
| 64 |
+
# Once the user presses on the Validate Config button, this function checks whether the config is really ready to go.
|
| 65 |
+
# It is ready if the config file is uploaded.
|
| 66 |
+
#
|
| 67 |
+
# Parameters:
|
| 68 |
+
# ----------
|
| 69 |
+
#
|
| 70 |
+
# config_upload: gr.File
|
| 71 |
+
# uploaded config file, is None if no file is uploaded
|
| 72 |
+
#
|
| 73 |
+
#
|
| 74 |
+
# Returns:
|
| 75 |
+
# -------
|
| 76 |
+
# str: message to the user about the status of the config validation
|
| 77 |
+
# str: "upload" if upload, and None if config is not ready for generation.
|
| 78 |
+
# """
|
| 79 |
+
# if config_upload is None:
|
| 80 |
+
# return "Please upload a config file for the generation to be ready.", None
|
| 81 |
+
# return "Config file uploaded!", "upload"
|
| 82 |
+
#
|
| 83 |
+
#
|
| 84 |
+
#def validate_scaffold_ready_with_file(scaffold_upload):
|
| 85 |
+
# """
|
| 86 |
+
# Once the user presses on the Validate Scaffold button, this function checks whether a file was indeed uploaded. If not, it prompts the user to upload a file or select no scaffold/target for unconditioned generation.
|
| 87 |
+
#
|
| 88 |
+
# Parameters:
|
| 89 |
+
# ----------
|
| 90 |
+
# scaffold_upload: gr.File
|
| 91 |
+
# uploaded scaffold file, is None if no file is uploaded
|
| 92 |
+
#
|
| 93 |
+
# Returns:
|
| 94 |
+
# -------
|
| 95 |
+
# str: message to the user about the status of the scaffold validation
|
| 96 |
+
# str: status string. "upload" if scaffold file is uploaded and valid, None if not.
|
| 97 |
+
# """
|
| 98 |
+
# if scaffold_upload is not None:
|
| 99 |
+
# return "Scaffold file uploaded and valid!", "upload"
|
| 100 |
+
# else:
|
| 101 |
+
# return "Please upload a scaffold file or press 'No Scaffold/Target' for unconditional generation.", None
|
| 102 |
+
#
|
| 103 |
+
#
|
| 104 |
+
#def give_run_status(num_batches, num_designs_per_batch, config_upload, scaffold_upload):
|
| 105 |
+
# """
|
| 106 |
+
# Once the user presses on the Run Generation button, this function checks whether both config and scaffold are ready, and gives a status message about the generation run that is about to happen. If both config and scaffold are not ready, it prompts the user to ensure they are both validated before running the generation.
|
| 107 |
+
#
|
| 108 |
+
# Parameters:
|
| 109 |
+
# ----------
|
| 110 |
+
# num_batches: gr.Number
|
| 111 |
+
# number of batches input by the user manually
|
| 112 |
+
# num_designs_per_batch: gr.Number
|
| 113 |
+
# number of designs per batch input by the user manually
|
| 114 |
+
# config_upload: gr.File
|
| 115 |
+
# uploaded config file, is None if no file is uploaded
|
| 116 |
+
# scaffold_upload: gr.File
|
| 117 |
+
# uploaded scaffold file, is None if no file is uploaded
|
| 118 |
+
#
|
| 119 |
+
# Returns:
|
| 120 |
+
# -------
|
| 121 |
+
# gr.update: Gradio update object to update the generation status message in the UI about to be run. If both config and scaffold are not ready, returns an update with a message prompting the user to ensure they are both validated before running the generation.
|
| 122 |
+
#
|
| 123 |
+
#
|
| 124 |
+
# """
|
| 125 |
+
# if config_upload is None:
|
| 126 |
+
# return gr.update(value="Please ensure you have uploaded a configuration file: .yaml or .json")
|
| 127 |
+
# elif scaffold_upload is None:
|
| 128 |
+
# return gr.update(value=f"Running unconditional generation for {num_batches} batches of {num_designs_per_batch}, config uploaded from file {os.path.basename(config_upload)}")
|
| 129 |
+
# else:
|
| 130 |
+
# return gr.update(value=f"Running conditional generation for {num_batches} batches of {num_designs_per_batch}, config uploaded from file {os.path.basename(config_upload)}, scaffold uploaded as {os.path.basename(scaffold_upload)}")
|
utils/pipelines.py
CHANGED
|
@@ -40,6 +40,14 @@ def generation_with_input_config(input_file, pdb_file, num_batches, num_designs_
|
|
| 40 |
|
| 41 |
"""
|
| 42 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
session_hash = random.getrandbits(128)
|
| 44 |
time_stamp = time.strftime("%Y-%m-%d-%H-%M-%S")
|
| 45 |
directory = f"./outputs/generation_with_input_config/session_{session_hash}_{time_stamp}"
|
|
@@ -60,9 +68,11 @@ def generation_with_input_config(input_file, pdb_file, num_batches, num_designs_
|
|
| 60 |
if extra_args:
|
| 61 |
command += f" {extra_args}"
|
| 62 |
print(f"Running command: {command}")
|
|
|
|
| 63 |
start = perf_counter()
|
| 64 |
res = subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
|
| 65 |
print("Command took", perf_counter() - start, "seconds to run.")
|
|
|
|
| 66 |
|
| 67 |
|
| 68 |
results = []
|
|
@@ -78,7 +88,7 @@ def generation_with_input_config(input_file, pdb_file, num_batches, num_designs_
|
|
| 78 |
results.append({"batch": batch, "design": design, "cif_path": cif_path, "pdb_path": pdb_path})
|
| 79 |
|
| 80 |
print(results)
|
| 81 |
-
return gr.update(value=
|
| 82 |
|
| 83 |
except subprocess.CalledProcessError as e:
|
| 84 |
print("subprocess threw an error", e.stderr)
|
|
|
|
| 40 |
|
| 41 |
"""
|
| 42 |
|
| 43 |
+
|
| 44 |
+
if input_file is None:
|
| 45 |
+
return gr.update(value="Please ensure you have uploaded a configuration file: .yaml or .json"), gr.update(), gr.update()
|
| 46 |
+
elif pdb_file is None:
|
| 47 |
+
status_update = f"Running generation for {num_batches} batches of {num_designs_per_batch}\n job configuration uploaded from file {os.path.basename(input_file)}\n no scaffold/target provided"
|
| 48 |
+
else:
|
| 49 |
+
status_update = f"Running generation for {num_batches} batches of {num_designs_per_batch}\n job configuration uploaded from file {os.path.basename(input_file)}\n scaffold/target provided from file {os.path.basename(pdb_file)}"
|
| 50 |
+
|
| 51 |
session_hash = random.getrandbits(128)
|
| 52 |
time_stamp = time.strftime("%Y-%m-%d-%H-%M-%S")
|
| 53 |
directory = f"./outputs/generation_with_input_config/session_{session_hash}_{time_stamp}"
|
|
|
|
| 68 |
if extra_args:
|
| 69 |
command += f" {extra_args}"
|
| 70 |
print(f"Running command: {command}")
|
| 71 |
+
status_update += f"\nRunning command: {command}."
|
| 72 |
start = perf_counter()
|
| 73 |
res = subprocess.run(command, shell=True, check=True, text=True, capture_output=True)
|
| 74 |
print("Command took", perf_counter() - start, "seconds to run.")
|
| 75 |
+
status_update += f"\nGeneration successful! Command took {perf_counter() - start:.2f} seconds to run."
|
| 76 |
|
| 77 |
|
| 78 |
results = []
|
|
|
|
| 88 |
results.append({"batch": batch, "design": design, "cif_path": cif_path, "pdb_path": pdb_path})
|
| 89 |
|
| 90 |
print(results)
|
| 91 |
+
return gr.update(value=status_update), directory, results
|
| 92 |
|
| 93 |
except subprocess.CalledProcessError as e:
|
| 94 |
print("subprocess threw an error", e.stderr)
|