import gradio as gr import os import subprocess from pathlib import Path import shutil import spaces # Function to check that the files are in the same directory def check_files_in_same_directory(file1, file2): if file1 is None or file2 is None: raise ValueError("Both the YAML config and target PDB/CIF files must be provided.") if Path(file1.name).parent != Path(file2.name).parent: raise ValueError("YAML config and target PDB/CIF must be in the same directory.") def move_file_to_output(file, output_dir): if file is None: return None src_path = Path(file.name) # path to the temp-uploaded file dest_path = Path(output_dir) / src_path.name dest_path.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(src_path, dest_path) # preserves metadata return dest_path def move_files_to_output(yaml_file, target_file, output_dir): yaml_path_dest = move_file_to_output(yaml_file, output_dir) target_path_dest = move_file_to_output(target_file, output_dir) check_files_in_same_directory(yaml_path_dest, target_path_dest) return yaml_path_dest, target_path_dest def download_results(results_dir, zip_name): """ Creates a ZIP of `results_dir` and returns (zip_path or None, message). """ results_dir = Path(results_dir) if not results_dir.exists() or not results_dir.is_dir(): return None, "No results available for download." # Ensure zip_name is a Path and has .zip extension zip_path = Path(zip_name) if zip_path.suffix != ".zip": zip_path = zip_path.with_suffix(".zip") # Make parent directory if needed if zip_path.parent != Path(""): zip_path.parent.mkdir(parents=True, exist_ok=True) # shutil.make_archive wants base_name without extension base_name = str(zip_path.with_suffix("")) shutil.make_archive( base_name=base_name, format="zip", root_dir=str(results_dir), ) zip_path = Path(base_name + ".zip") return str(zip_path), "Download ready!" def find_log_file(output_dir): # log files start with "boltzgen" and end with ".log" log_files = list(Path(output_dir).glob("boltzgen*.log")) if log_files: # return the most recently modified log file return max(log_files, key=lambda f: f.stat().st_mtime) return None @spaces.GPU(duration=300) def run_boltzgen(yaml_file, target_file, protocol, num_designs, budget): output_dir = "/tmp/output" os.makedirs(output_dir, exist_ok=True) # Move config and target files to the output directory yaml_path_dest, target_path_dest = move_files_to_output(yaml_file, target_file, output_dir) cmd = [ "boltzgen", "run", str(yaml_path_dest), "--output", output_dir, "--protocol", protocol, "--num_designs", str(num_designs), "--budget", str(budget), "--cache", "/tmp/cache" ] try: result = subprocess.run(cmd, capture_output=True, text=True, cwd=output_dir, timeout=300) if result.returncode == 0: final_designs_dir = Path(output_dir) / "final_ranked_designs" if final_designs_dir.exists() and final_designs_dir.is_dir(): return f"Success!\nDesigns saved to {final_designs_dir}/" else: return "No designs passed the filtering criteria." return f"Error:\n{result.stderr}" except subprocess.TimeoutExpired: return "Timeout (300s limit)" except Exception as e: return f"Failed: {str(e)}" # Interface with gr.Blocks() as demo: # Markdown with image at the beginning gr.Markdown("""