annabossler commited on
Commit
2f6c8f7
·
verified ·
1 Parent(s): 16c8c8f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +61 -64
app.py CHANGED
@@ -5,14 +5,12 @@ import numpy as np
5
  import gradio as gr
6
  from ase.io import read
7
  from ase.io.trajectory import Trajectory
8
-
9
- # ----- Kill-switch para desactivar el visor si molesta (export VIS_DISABLED=1) -----
10
- VIS_DISABLED = os.environ.get("VIS_DISABLED", "0") == "1"
11
 
12
  # ==== Intentar visor nativo como en UMA (opcional) ====
13
  try:
14
  from gradio_molecule3d import Molecule3D
15
- HAVE_MOL3D = True and not VIS_DISABLED
16
  except Exception:
17
  HAVE_MOL3D = False
18
 
@@ -21,6 +19,9 @@ def traj_to_html(traj_path, width=520, height=520, interval_ms=200):
21
  """
22
  Render de una trayectoria ASE (.traj) con 3Dmol.js (sin depender de Jupyter).
23
  """
 
 
 
24
  try:
25
  traj = Trajectory(traj_path)
26
  except Exception as e:
@@ -38,40 +39,56 @@ def traj_to_html(traj_path, width=520, height=520, interval_ms=200):
38
  if not xyz_frames:
39
  return "<div style='color:#555'>Empty trajectory</div>"
40
 
 
 
41
  html = f"""
42
- <div id="viewer_md" style="width:{width}px; height:{height}px; position:relative;"></div>
43
- <script src="https://3dmol.org/build/3Dmol-min.js"></script>
 
 
44
  <script>
45
- (function() {{
46
- function ready(fn) {{
47
- if (document.readyState !== 'loading') fn();
48
- else document.addEventListener('DOMContentLoaded', fn);
49
- }}
50
- ready(function() {{
51
- var el = document.getElementById("viewer_md");
52
- if (!el || typeof $3Dmol === "undefined") {{
53
- el.innerHTML = '<div style="padding:8px;color:#b00">3Dmol.js no cargó. Reintenta o habilita CORS.</div>';
54
- return;
 
 
 
 
 
 
 
 
 
55
  }}
 
56
  var viewer = $3Dmol.createViewer(el, {{backgroundColor: 'white'}});
57
- var frames = {xyz_frames!r};
58
- var i = 0;
59
- function show(k) {{
60
- viewer.clear();
61
- viewer.addModel(frames[k], "xyz");
62
- viewer.setStyle({{}}, {{stick: {{}}}});
63
- viewer.zoomTo();
64
- viewer.render();
 
65
  }}
66
- show(0);
 
 
67
  if (frames.length > 1) {{
68
- setInterval(function() {{
69
- i = (i + 1) % frames.length;
70
- show(i);
71
- }}, {int(interval_ms)});
72
  }}
73
- }});
74
- }})();
75
  </script>
76
  """
77
  return html
@@ -167,7 +184,8 @@ def md_wrapper(xyz_content, charge, spin, steps, tempK, timestep_fs, ensemble):
167
  )
168
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
169
 
170
- html_value = traj_to_html(traj_path) if not HAVE_MOL3D else ""
 
171
  return (status, traj_path, log_text, script_text, explanation, html_value)
172
 
173
  except Exception as e:
@@ -193,7 +211,8 @@ def relax_wrapper(xyz_content, steps, fmax, charge, spin, relax_cell):
193
  )
194
  status = f"Relaxation finished (≤ {int(steps)} steps, fmax={float(fmax)} eV/Å)"
195
 
196
- html_value = "" if (VIS_DISABLED or HAVE_MOL3D) else traj_to_html(traj_path)
 
197
  return (status, traj_path, log_text, script_text, explanation, html_value)
198
 
199
  except Exception as e:
@@ -262,28 +281,15 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
262
 
263
  with gr.Column(variant="panel", min_width=520):
264
  md_status = gr.Textbox(label="MD Status", interactive=False)
265
-
266
- # Archivo de trayectoria SIEMPRE (Molecule3D lo consume)
267
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
268
-
269
- # Visor nativo si está disponible
270
- if HAVE_MOL3D:
271
- md_viewer = Molecule3D(
272
- label="Trajectory Viewer",
273
- inputs=[md_traj],
274
- value=lambda x: x,
275
- interactive=False,
276
- )
277
- md_html = gr.HTML(visible=False)
278
- else:
279
- md_html = gr.HTML(label="Trajectory Viewer")
280
- md_viewer = gr.Textbox(visible=False)
281
-
282
  md_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
283
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
284
  md_explain = gr.Markdown()
285
 
286
- # NOTA: el visor Molecule3D se refresca cuando cambia md_traj (no hay que conectarlo)
287
  run_md_btn.click(
288
  md_wrapper,
289
  inputs=[xyz_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
@@ -305,20 +311,11 @@ with gr.Blocks(theme=gr.themes.Ocean(), title="OrbMol Demo") as demo:
305
 
306
  with gr.Column(variant="panel", min_width=520):
307
  rlx_status = gr.Textbox(label="Status", interactive=False)
308
-
309
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
310
- if HAVE_MOL3D:
311
- rlx_viewer = Molecule3D(
312
- label="Final Structure",
313
- inputs=[rlx_traj],
314
- value=lambda x: x,
315
- interactive=False,
316
- )
317
- rlx_html = gr.HTML(visible=False)
318
- else:
319
- rlx_html = gr.HTML(label="Final Structure")
320
- rlx_viewer = gr.Textbox(visible=False)
321
-
322
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
323
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
324
  rlx_explain = gr.Markdown()
@@ -333,4 +330,4 @@ print("Starting OrbMol model loading…")
333
  _ = _load_orbmol_calc()
334
 
335
  if __name__ == "__main__":
336
- demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)
 
5
  import gradio as gr
6
  from ase.io import read
7
  from ase.io.trajectory import Trajectory
8
+ import hashlib
 
 
9
 
10
  # ==== Intentar visor nativo como en UMA (opcional) ====
11
  try:
12
  from gradio_molecule3d import Molecule3D
13
+ HAVE_MOL3D = False # Forzar HTML siempre
14
  except Exception:
15
  HAVE_MOL3D = False
16
 
 
19
  """
20
  Render de una trayectoria ASE (.traj) con 3Dmol.js (sin depender de Jupyter).
21
  """
22
+ # ID único basado en el path
23
+ viewer_id = f"viewer_{abs(hash(traj_path))}"
24
+
25
  try:
26
  traj = Trajectory(traj_path)
27
  except Exception as e:
 
39
  if not xyz_frames:
40
  return "<div style='color:#555'>Empty trajectory</div>"
41
 
42
+ frames_json = str(xyz_frames).replace("'", '"')
43
+
44
  html = f"""
45
+ <div style="margin-bottom:10px;">
46
+ <strong>3D Molecular Viewer</strong> - {len(xyz_frames)} frames
47
+ </div>
48
+ <div id="{viewer_id}" style="width:{width}px; height:{height}px; position:relative; border:1px solid #ccc; background:white;"></div>
49
  <script>
50
+ // Load 3Dmol if not already loaded
51
+ if (typeof window.$3Dmol === 'undefined') {{
52
+ var script = document.createElement('script');
53
+ script.src = 'https://3dmol.org/build/3Dmol-min.js';
54
+ script.onload = function() {{
55
+ setTimeout(function() {{ initViewer_{abs(hash(traj_path))}(); }}, 100);
56
+ }};
57
+ document.head.appendChild(script);
58
+ }} else {{
59
+ initViewer_{abs(hash(traj_path))}();
60
+ }}
61
+
62
+ function initViewer_{abs(hash(traj_path))}() {{
63
+ var el = document.getElementById("{viewer_id}");
64
+ if (!el) return;
65
+
66
+ if (typeof $3Dmol === "undefined") {{
67
+ el.innerHTML = '<div style="padding:20px;text-align:center;color:#666;">3Dmol.js no disponible</div>';
68
+ return;
69
  }}
70
+
71
  var viewer = $3Dmol.createViewer(el, {{backgroundColor: 'white'}});
72
+ var frames = {frames_json};
73
+ var currentFrame = 0;
74
+
75
+ function showFrame(frameIndex) {{
76
+ viewer.clear();
77
+ viewer.addModel(frames[frameIndex], "xyz");
78
+ viewer.setStyle({{}}, {{stick: {{radius: 0.1}}, sphere: {{radius: 0.3}}}});
79
+ viewer.zoomTo();
80
+ viewer.render();
81
  }}
82
+
83
+ showFrame(0);
84
+
85
  if (frames.length > 1) {{
86
+ setInterval(function() {{
87
+ currentFrame = (currentFrame + 1) % frames.length;
88
+ showFrame(currentFrame);
89
+ }}, {interval_ms});
90
  }}
91
+ }}
 
92
  </script>
93
  """
94
  return html
 
184
  )
185
  status = f"MD completed: {int(steps)} steps at {int(tempK)} K ({ensemble})"
186
 
187
+ # SIEMPRE generar HTML ya que HAVE_MOL3D = False
188
+ html_value = traj_to_html(traj_path)
189
  return (status, traj_path, log_text, script_text, explanation, html_value)
190
 
191
  except Exception as e:
 
211
  )
212
  status = f"Relaxation finished (≤ {int(steps)} steps, fmax={float(fmax)} eV/Å)"
213
 
214
+ # SIEMPRE generar HTML ya que HAVE_MOL3D = False
215
+ html_value = traj_to_html(traj_path)
216
  return (status, traj_path, log_text, script_text, explanation, html_value)
217
 
218
  except Exception as e:
 
281
 
282
  with gr.Column(variant="panel", min_width=520):
283
  md_status = gr.Textbox(label="MD Status", interactive=False)
 
 
284
  md_traj = gr.File(label="Trajectory (.traj)", interactive=False)
285
+
286
+ # Siempre usar HTML ya que HAVE_MOL3D = False
287
+ md_html = gr.HTML(label="Trajectory Viewer")
288
+
 
 
 
 
 
 
 
 
 
 
289
  md_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
290
  md_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
291
  md_explain = gr.Markdown()
292
 
 
293
  run_md_btn.click(
294
  md_wrapper,
295
  inputs=[xyz_md, charge_md, spin_md, steps_md, temp_md, timestep_md, ensemble_md],
 
311
 
312
  with gr.Column(variant="panel", min_width=520):
313
  rlx_status = gr.Textbox(label="Status", interactive=False)
 
314
  rlx_traj = gr.File(label="Trajectory (.traj)", interactive=False)
315
+
316
+ # Siempre usar HTML ya que HAVE_MOL3D = False
317
+ rlx_html = gr.HTML(label="Final Structure")
318
+
 
 
 
 
 
 
 
 
319
  rlx_log = gr.Textbox(label="Log", interactive=False, lines=15, max_lines=25)
320
  rlx_script = gr.Code(label="Reproduction Script", language="python", interactive=False, lines=20, max_lines=30)
321
  rlx_explain = gr.Markdown()
 
330
  _ = _load_orbmol_calc()
331
 
332
  if __name__ == "__main__":
333
+ demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True)