Upload app.py with huggingface_hub
Browse files
app.py
CHANGED
|
@@ -183,20 +183,18 @@ def fetch_pdb_structure(pdb_id: str) -> Optional[str]:
|
|
| 183 |
|
| 184 |
|
| 185 |
def create_3d_viewer(pdb_content: str, binding_site: dict = None, style: str = "cartoon") -> str:
|
| 186 |
-
"""Create 3D molecular viewer HTML with
|
| 187 |
import html
|
|
|
|
| 188 |
|
| 189 |
-
# Escape PDB content for JavaScript
|
| 190 |
-
pdb_escaped =
|
| 191 |
|
| 192 |
# Build style configuration
|
| 193 |
if style == "cartoon":
|
| 194 |
style_js = "viewer.setStyle({}, {cartoon: {color: 'spectrum'}});"
|
| 195 |
elif style == "surface":
|
| 196 |
-
style_js = ""
|
| 197 |
-
viewer.setStyle({}, {cartoon: {color: 'spectrum'}});
|
| 198 |
-
viewer.addSurface($3Dmol.SAS, {opacity: 0.7, color: 'white'});
|
| 199 |
-
"""
|
| 200 |
elif style == "stick":
|
| 201 |
style_js = "viewer.setStyle({}, {stick: {colorscheme: 'Jmol'}});"
|
| 202 |
elif style == "sphere":
|
|
@@ -207,28 +205,24 @@ def create_3d_viewer(pdb_content: str, binding_site: dict = None, style: str = "
|
|
| 207 |
# Binding site sphere
|
| 208 |
binding_site_js = ""
|
| 209 |
if binding_site:
|
| 210 |
-
binding_site_js = f""
|
| 211 |
-
viewer.addSphere({{
|
| 212 |
-
center: {{x: {binding_site['x']}, y: {binding_site['y']}, z: {binding_site['z']}}},
|
| 213 |
-
radius: 8,
|
| 214 |
-
color: 'red',
|
| 215 |
-
opacity: 0.3
|
| 216 |
-
}});
|
| 217 |
-
"""
|
| 218 |
-
|
| 219 |
-
# Generate unique ID for the viewer
|
| 220 |
-
import random
|
| 221 |
-
viewer_id = f"viewer_{random.randint(100000, 999999)}"
|
| 222 |
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
<script src="https://3dmol.org/build/3Dmol-min.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
<script>
|
| 229 |
-
(function() {{
|
| 230 |
-
var pdbData =
|
| 231 |
-
var element = document.getElementById('
|
| 232 |
var config = {{ backgroundColor: '0x1a1a2e' }};
|
| 233 |
var viewer = $3Dmol.createViewer(element, config);
|
| 234 |
viewer.addModel(pdbData, "pdb");
|
|
@@ -236,8 +230,21 @@ def create_3d_viewer(pdb_content: str, binding_site: dict = None, style: str = "
|
|
| 236 |
{binding_site_js}
|
| 237 |
viewer.zoomTo();
|
| 238 |
viewer.render();
|
| 239 |
-
}})
|
| 240 |
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
'''
|
| 242 |
|
| 243 |
return html_content
|
|
|
|
| 183 |
|
| 184 |
|
| 185 |
def create_3d_viewer(pdb_content: str, binding_site: dict = None, style: str = "cartoon") -> str:
|
| 186 |
+
"""Create 3D molecular viewer HTML using iframe with srcdoc for JS execution."""
|
| 187 |
import html
|
| 188 |
+
import base64
|
| 189 |
|
| 190 |
+
# Escape PDB content for JavaScript (double escape for iframe)
|
| 191 |
+
pdb_escaped = pdb_content.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '').replace("'", "\\'").replace('"', '\\"')
|
| 192 |
|
| 193 |
# Build style configuration
|
| 194 |
if style == "cartoon":
|
| 195 |
style_js = "viewer.setStyle({}, {cartoon: {color: 'spectrum'}});"
|
| 196 |
elif style == "surface":
|
| 197 |
+
style_js = "viewer.setStyle({}, {cartoon: {color: 'spectrum'}}); viewer.addSurface($3Dmol.SAS, {opacity: 0.7, color: 'white'});"
|
|
|
|
|
|
|
|
|
|
| 198 |
elif style == "stick":
|
| 199 |
style_js = "viewer.setStyle({}, {stick: {colorscheme: 'Jmol'}});"
|
| 200 |
elif style == "sphere":
|
|
|
|
| 205 |
# Binding site sphere
|
| 206 |
binding_site_js = ""
|
| 207 |
if binding_site:
|
| 208 |
+
binding_site_js = f"viewer.addSphere({{center: {{x: {binding_site['x']}, y: {binding_site['y']}, z: {binding_site['z']}}}, radius: 8, color: 'red', opacity: 0.3}});"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
|
| 210 |
+
# Create complete HTML document for iframe
|
| 211 |
+
iframe_html = f'''<!DOCTYPE html>
|
| 212 |
+
<html>
|
| 213 |
+
<head>
|
| 214 |
<script src="https://3dmol.org/build/3Dmol-min.js"></script>
|
| 215 |
+
<style>
|
| 216 |
+
body {{ margin: 0; padding: 0; overflow: hidden; background: #1a1a2e; }}
|
| 217 |
+
#viewer {{ width: 100%; height: 100%; }}
|
| 218 |
+
</style>
|
| 219 |
+
</head>
|
| 220 |
+
<body>
|
| 221 |
+
<div id="viewer"></div>
|
| 222 |
<script>
|
| 223 |
+
document.addEventListener('DOMContentLoaded', function() {{
|
| 224 |
+
var pdbData = "{pdb_escaped}";
|
| 225 |
+
var element = document.getElementById('viewer');
|
| 226 |
var config = {{ backgroundColor: '0x1a1a2e' }};
|
| 227 |
var viewer = $3Dmol.createViewer(element, config);
|
| 228 |
viewer.addModel(pdbData, "pdb");
|
|
|
|
| 230 |
{binding_site_js}
|
| 231 |
viewer.zoomTo();
|
| 232 |
viewer.render();
|
| 233 |
+
}});
|
| 234 |
</script>
|
| 235 |
+
</body>
|
| 236 |
+
</html>'''
|
| 237 |
+
|
| 238 |
+
# Escape for srcdoc attribute
|
| 239 |
+
iframe_srcdoc = html.escape(iframe_html)
|
| 240 |
+
|
| 241 |
+
html_content = f'''
|
| 242 |
+
<div style="width: 100%; display: flex; justify-content: center;">
|
| 243 |
+
<iframe srcdoc="{iframe_srcdoc}"
|
| 244 |
+
style="width: 700px; height: 500px; border: none; border-radius: 12px; background: #1a1a2e;"
|
| 245 |
+
sandbox="allow-scripts allow-same-origin">
|
| 246 |
+
</iframe>
|
| 247 |
+
</div>
|
| 248 |
'''
|
| 249 |
|
| 250 |
return html_content
|