import os
# Environment preamble before any heavy import: these gate AtomWorks/numba/biotite startup and
# keep the ZeroGPU parent process free of CUDA initialization.
os.environ.setdefault("NUMBA_DISABLE_CUDA", "1")
os.environ.setdefault("ALLOW_BIOTITE_CCD", "true")
os.environ.setdefault("DISABLE_CUEQUIVARIANCE", "true")
os.environ.setdefault("WANDB_MODE", "disabled")
os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "false")
os.environ.setdefault("CLUSTER", "local")
os.environ.setdefault("OMP_NUM_THREADS", "1")
os.environ.setdefault("OPENBLAS_NUM_THREADS", "1")
import spaces # noqa: E402 # MUST precede torch / diffusers / atomworks
import time
from pathlib import Path
import gradio as gr
import torch
MODEL_ID = "nvidia/RFD4-Proteina-Diffusers"
EXAMPLES_DIR = Path(__file__).parent / "examples"
from diffusers import RFD4ProteinaPipeline # noqa: E402
from rfd4_proteina_prep import prepare_cif, write_cif # noqa: E402
# The feature tensors the pipeline consumes as direct keyword arguments; everything else the
# preprocessor emits rides inside `conditioning_features`.
REQUIRED_KEYS = (
"padding_mask",
"is_in_context_conditioning",
"supports_local_latent",
"token_type",
"atom37_mask",
)
MODES = (
"Full design",
"Inverse folding",
"Partial diffusion",
)
MODE_INFO = {
"Full design": (
"Design every free token in the input: sequence and structure are generated from noise, "
"conditioned on whatever the annotated CIF holds fixed."
),
"Inverse folding": (
"The backbone of every free token is held fixed; RFD4 predicts only the sequence. Use it on "
"a structure whose fold you want to keep."
),
"Partial diffusion": (
"Start from the input structure at a partly-noised state: the beginning of the trajectory "
"is skipped, so designs stay close to the input fold."
),
}
# The released recipe fixes the number of diffusion steps (len(config.recycle_depths) = 60).
N_STEPS = 60
CSS = """
#col-container { max-width: 1100px; margin: 0 auto; }
.dark .gradio-container { color: var(--body-text-color); }
"""
_PLACEHOLDER_HTML = (
'
Press “Design” to see the generated structure here
'
)
# The pipeline is loaded once at module scope, eagerly on the GPU: no offloading, no device_map.
pipe = RFD4ProteinaPipeline.from_pretrained(MODEL_ID, dtype=torch.bfloat16).to("cuda")
def _describe(mode: str) -> str:
"""One-line explanation of a design mode, shown under the dropdown."""
return MODE_INFO.get(mode, "")
def _viewer_for(cif_path: str | Path, height: int = 520) -> str:
"""Render a designed CIF as an interactive 3Dmol.js cartoon view."""
import py3Dmol
with open(cif_path) as handle:
data = handle.read()
view = py3Dmol.view(width="100%", height=height)
view.addModel(data, "cif")
view.setStyle({"cartoon": {"colorscheme": "chain"}})
view.zoomTo()
return view._make_html()
@spaces.GPU(duration=120)
def design_protein(
cif_file,
mode="Full design",
seed=42,
num_designs=1,
remaining_fraction=0.4,
progress=gr.Progress(track_tqdm=True),
):
"""Run RFD4-Proteina on an annotated CIF and return the designed structure(s).
Args:
cif_file: Path to the uploaded annotated CIF (AtomWorks Studio format).
mode: "Full design", "Inverse folding" or "Partial diffusion".
seed: Random seed; the same input and seed reproduce the same design.
num_designs: How many independent designs to draw in one call (1-8).
remaining_fraction: "Partial diffusion" only — the fraction of the trajectory left to
run. The released example uses 0.4.
progress: Gradio progress bar.
Returns:
The design CIF path (or list of paths), an interactive 3D view of the first design, and a
short text summary.
"""
started = time.perf_counter()
if cif_file is None:
raise gr.Error("Upload an annotated CIF first, or pick one of the examples below.")
num_designs = int(num_designs)
if not 1 <= num_designs <= 8:
raise gr.Error("Number of designs must be between 1 and 8.")
# Feature preparation is CPU-side AtomWorks parsing; the pipeline moves every tensor to its
# execution device itself, so CPU tensors are fine here.
features, atoms = prepare_cif(str(cif_file), seed=int(seed), device="cpu")
tokens = int(features["padding_mask"].shape[1])
required = {name: features[name] for name in REQUIRED_KEYS}
conditioning = {name: value for name, value in features.items() if name not in REQUIRED_KEYS}
if mode == "Inverse folding":
kwargs = {
"inverse_folding": True,
"partial_t_bb_ca": 0.0,
"partial_t_local_latents": 0.0,
}
required["coords_nm"] = features["coords_nm"]
elif mode == "Partial diffusion":
# Reproduce the released partial-diffusion entry point: start each modality at the time
# its schedule reaches after skipping (1 - remaining_fraction) of the trajectory.
fraction = float(min(max(remaining_fraction, 0.05), 1.0))
index = round((1 - fraction) * N_STEPS)
pipe.bb_ca_scheduler.set_timesteps(N_STEPS)
pipe.local_latents_scheduler.set_timesteps(N_STEPS)
kwargs = {
"partial_t_bb_ca": float(pipe.bb_ca_scheduler.timesteps[index]),
"partial_t_local_latents": float(pipe.local_latents_scheduler.timesteps[index]),
}
required["coords_nm"] = features["coords_nm"]
else:
kwargs = {}
conditioning["coords_nm"] = features["coords_nm"]
if num_designs == 1:
generator = torch.Generator("cuda").manual_seed(int(seed))
else:
generator = [
torch.Generator("cuda").manual_seed(int(seed) + offset)
for offset in range(num_designs)
]
with torch.no_grad():
output = pipe(
padding_mask=required["padding_mask"],
is_in_context_conditioning=required["is_in_context_conditioning"],
supports_local_latent=required["supports_local_latent"],
token_type=required["token_type"],
atom37_mask=required["atom37_mask"],
coords_nm=required.get("coords_nm"),
conditioning_features=conditioning,
num_designs_per_prompt=num_designs,
generator=generator,
**kwargs,
)
# `write_cif` reads one feature row per output row: repeat the input features per design.
if num_designs > 1:
features = {
name: value.repeat_interleave(num_designs, dim=0) for name, value in features.items()
}
out_paths = []
for row in range(num_designs):
out_paths.append(write_cif(output, features, atoms, _unique_path(row, seed), row=row))
elapsed = time.perf_counter() - started
summary = (
f"**{num_designs}** design{'s' if num_designs > 1 else ''} · **{tokens}** tokens · "
f"**{mode.lower()}** · seed **{int(seed)}** · **{elapsed:.1f} s** on this GPU"
)
viewer_html = _viewer_for(out_paths[0])
if num_designs == 1:
return out_paths[0], viewer_html, summary
return out_paths, viewer_html, summary
def _unique_path(row: int, seed) -> Path:
"""A fresh, non-existent output path in this worker's temp directory."""
base = Path(os.environ.get("GRADIO_TEMP_DIR") or "/tmp/gradio") / f"rfd4_design_{int(seed)}_{row}.cif"
base.parent.mkdir(parents=True, exist_ok=True)
candidate = base
suffix = 0
while candidate.exists():
suffix += 1
candidate = base.with_name(f"{base.stem}_{suffix}{base.suffix}")
return candidate
with gr.Blocks(title="RFD4-Proteina · Diffusers") as demo:
gr.HTML(
"""
RFD4-Proteina · Diffusers
Joint sequence–structure generation for biomolecular design, conditioned on an
annotated CIF that says what to hold fixed and what to design. This Space runs
RFD4ProteinaPipeline from 🤗 Diffusers on ZeroGPU.
"""
)
with gr.Column(elem_id="col-container"):
with gr.Row():
with gr.Column(scale=1):
cif_input = gr.File(
label="Annotated CIF (input)",
file_types=[".cif"],
type="filepath",
file_count="single",
)
mode = gr.Dropdown(
choices=list(MODES),
value="Full design",
label="Design mode",
info="What RFD4 generates versus keeps from the input.",
)
mode_info = gr.Markdown(_describe("Full design"))
with gr.Accordion("Advanced options", open=False):
seed = gr.Slider(0, 2**31 - 1, value=42, step=1, label="Seed")
num_designs = gr.Slider(1, 8, value=1, step=1, label="Number of designs")
remaining_fraction = gr.Slider(
0.05,
1.0,
value=0.4,
step=0.05,
label="Remaining schedule (partial diffusion only)",
info="The released partial-diffusion example uses 0.4.",
)
go = gr.Button("Design", variant="primary")
with gr.Column(scale=2):
viewer = gr.HTML(value=_PLACEHOLDER_HTML, show_label=False)
out_files = gr.File(
label="Designed structure(s) · annotated CIF",
file_count="single",
interactive=False,
)
summary = gr.Markdown()
mode.change(_describe, inputs=mode, outputs=mode_info)
go.click(
design_protein,
inputs=[cif_input, mode, seed, num_designs, remaining_fraction],
outputs=[out_files, viewer, summary],
api_name="design",
)
gr.Examples(
examples=[
[str(EXAMPLES_DIR / "motif_scaffolding.cif"), "Full design"],
[str(EXAMPLES_DIR / "inverse_folding.cif"), "Inverse folding"],
[str(EXAMPLES_DIR / "inverse_folding.cif"), "Partial diffusion"],
[str(EXAMPLES_DIR / "protein_binder.cif"), "Full design"],
[str(EXAMPLES_DIR / "enzyme_design.cif"), "Full design"],
[str(EXAMPLES_DIR / "small_molecule_binder.cif"), "Full design"],
[str(EXAMPLES_DIR / "unconditional.cif"), "Full design"],
],
inputs=[cif_input, mode],
outputs=[out_files, viewer, summary],
fn=design_protein,
cache_examples=True,
cache_mode="lazy",
example_labels=[
"Motif scaffolding (1QJG)",
"Inverse folding (2KL8)",
"Partial diffusion (2KL8)",
"Protein binder (PD-L1)",
"Enzyme (catalytic motif)",
"Small-molecule binder (SAM)",
"Unconditional protein",
],
label="Author examples (from the model card, BSD-3-Clause)",
)
demo.launch(theme=gr.themes.Citrus(), css=CSS, mcp_server=True)