gabboud commited on
Commit
e165b97
·
1 Parent(s): 19021e5

simplify status update string by integrating in generate, create stop button

Browse files
Files changed (3) hide show
  1. app.py +30 -25
  2. utils/handle_events.py +69 -68
  3. 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=2,
92
  label="Number of Designs per Batch",
93
  precision=0,
94
  minimum=1,
95
  maximum=16
96
  )
97
  num_batches= gr.Number(
98
- value=5,
99
  label="Number of Batches",
100
  precision=0,
101
  minimum=1,
102
- maximum=10
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
- run_btn = gr.Button("Run Generation", variant="primary")
 
 
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
- run_btn.click(give_run_status, inputs=[num_batches, num_designs_per_batch, config_upload, scaffold_upload], outputs=runtextbox).then(
 
 
 
 
 
 
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 gen_results: gr.update(value="Generation completed!") if gen_results is not None else gr.update(),
169
- inputs=gen_results,
170
- outputs=runtextbox
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
- def give_run_status(num_batches, num_designs_per_batch, config_upload, scaffold_upload):
104
- """
105
- 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.
106
-
107
- Parameters:
108
- ----------
109
- num_batches: gr.Number
110
- number of batches input by the user manually
111
- num_designs_per_batch: gr.Number
112
- number of designs per batch input by the user manually
113
- config_upload: gr.File
114
- uploaded config file, is None if no file is uploaded
115
- scaffold_upload: gr.File
116
- uploaded scaffold file, is None if no file is uploaded
117
-
118
- Returns:
119
- -------
120
- 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.
121
-
122
-
123
- """
124
- if config_upload is None:
125
- return gr.update(value="Please ensure you have uploaded a configuration file: .yaml or .json")
126
- elif scaffold_upload is None:
127
- 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)}")
128
- else:
129
- 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)}")
 
 
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="Generation Successful"), directory, results
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)