Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -186,9 +186,44 @@ def load_html_file(filename):
|
|
| 186 |
encoded_content = urllib.parse.quote(content, safe='')
|
| 187 |
return f'<iframe src="data:text/html;charset=utf-8,{encoded_content}" width="100%" height="800px" style="border: none; border-radius: 10px;"></iframe>'
|
| 188 |
except FileNotFoundError:
|
| 189 |
-
return f'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
except Exception as e:
|
| 191 |
-
return f'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
|
| 193 |
# HTML for 3D Viewer
|
| 194 |
HTML_3D_VIEWER = """
|
|
@@ -200,9 +235,9 @@ HTML_3D_VIEWER = """
|
|
| 200 |
body {
|
| 201 |
margin: 0;
|
| 202 |
padding: 0;
|
| 203 |
-
background: #
|
| 204 |
font-family: Arial, sans-serif;
|
| 205 |
-
color: #
|
| 206 |
height: 100vh;
|
| 207 |
overflow: hidden;
|
| 208 |
}
|
|
@@ -219,43 +254,57 @@ HTML_3D_VIEWER = """
|
|
| 219 |
position: absolute;
|
| 220 |
top: 20px;
|
| 221 |
right: 20px;
|
| 222 |
-
background: rgba(
|
|
|
|
| 223 |
padding: 20px;
|
| 224 |
-
border-radius:
|
| 225 |
-
|
| 226 |
max-width: 300px;
|
| 227 |
}
|
| 228 |
.controls-panel h3 {
|
| 229 |
-
color: #
|
| 230 |
margin-top: 0;
|
|
|
|
| 231 |
}
|
| 232 |
.control-btn {
|
| 233 |
-
background: #
|
| 234 |
-
color: #
|
| 235 |
border: none;
|
| 236 |
-
padding:
|
| 237 |
margin: 5px;
|
| 238 |
-
border-radius:
|
| 239 |
cursor: pointer;
|
| 240 |
-
font-weight:
|
|
|
|
|
|
|
| 241 |
}
|
| 242 |
.control-btn:hover {
|
| 243 |
-
|
|
|
|
| 244 |
}
|
| 245 |
.info-display {
|
| 246 |
position: absolute;
|
| 247 |
bottom: 20px;
|
| 248 |
left: 20px;
|
| 249 |
-
background: rgba(
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
border:
|
|
|
|
| 253 |
}
|
| 254 |
#sequence-display {
|
| 255 |
font-family: monospace;
|
| 256 |
-
color: #
|
| 257 |
word-break: break-all;
|
| 258 |
margin-top: 10px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
}
|
| 260 |
</style>
|
| 261 |
</head>
|
|
@@ -264,7 +313,7 @@ HTML_3D_VIEWER = """
|
|
| 264 |
<canvas id="canvas3d"></canvas>
|
| 265 |
|
| 266 |
<div class="controls-panel">
|
| 267 |
-
<h3
|
| 268 |
<button class="control-btn" onclick="setViewMode('cartoon')">Cartoon</button>
|
| 269 |
<button class="control-btn" onclick="setViewMode('stick')">Stick</button>
|
| 270 |
<button class="control-btn" onclick="setViewMode('sphere')">Sphere</button>
|
|
@@ -288,21 +337,29 @@ HTML_3D_VIEWER = """
|
|
| 288 |
|
| 289 |
function init() {
|
| 290 |
scene = new THREE.Scene();
|
| 291 |
-
|
|
|
|
|
|
|
| 292 |
|
| 293 |
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
| 294 |
camera.position.z = 50;
|
| 295 |
|
| 296 |
-
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('canvas3d'), antialias: true });
|
| 297 |
renderer.setSize(window.innerWidth, window.innerHeight);
|
|
|
|
| 298 |
|
| 299 |
-
const ambientLight = new THREE.AmbientLight(
|
| 300 |
scene.add(ambientLight);
|
| 301 |
|
| 302 |
-
const directionalLight = new THREE.DirectionalLight(0xffffff,
|
| 303 |
directionalLight.position.set(50, 50, 50);
|
|
|
|
| 304 |
scene.add(directionalLight);
|
| 305 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 306 |
moleculeGroup = new THREE.Group();
|
| 307 |
scene.add(moleculeGroup);
|
| 308 |
|
|
@@ -358,8 +415,16 @@ HTML_3D_VIEWER = """
|
|
| 358 |
const tubeGeometry1 = new THREE.TubeGeometry(curve1, 100, 0.5, 8, false);
|
| 359 |
const tubeGeometry2 = new THREE.TubeGeometry(curve2, 100, 0.5, 8, false);
|
| 360 |
|
| 361 |
-
const material1 = new THREE.MeshPhongMaterial({
|
| 362 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 363 |
|
| 364 |
moleculeGroup.add(new THREE.Mesh(tubeGeometry1, material1));
|
| 365 |
moleculeGroup.add(new THREE.Mesh(tubeGeometry2, material2));
|
|
@@ -375,7 +440,9 @@ HTML_3D_VIEWER = """
|
|
| 375 |
|
| 376 |
const geometry = new THREE.CylinderGeometry(0.3, 0.3, distance, 8);
|
| 377 |
const material = new THREE.MeshPhongMaterial({
|
| 378 |
-
color: getBaseColor(sequence[i])
|
|
|
|
|
|
|
| 379 |
});
|
| 380 |
|
| 381 |
const cylinder = new THREE.Mesh(geometry, material);
|
|
@@ -393,12 +460,12 @@ HTML_3D_VIEWER = """
|
|
| 393 |
|
| 394 |
function getBaseColor(base) {
|
| 395 |
const colors = {
|
| 396 |
-
'A':
|
| 397 |
-
'T':
|
| 398 |
-
'G':
|
| 399 |
-
'C':
|
| 400 |
};
|
| 401 |
-
return colors[base] ||
|
| 402 |
}
|
| 403 |
|
| 404 |
function setViewMode(mode) {
|
|
@@ -480,51 +547,151 @@ def create_demo():
|
|
| 480 |
css = """
|
| 481 |
.gradio-container {
|
| 482 |
font-family: 'Arial', sans-serif;
|
| 483 |
-
background: linear-gradient(135deg, #
|
|
|
|
| 484 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 485 |
.sequence-box {
|
| 486 |
font-family: 'Courier New', monospace;
|
| 487 |
-
background-color:
|
| 488 |
-
color: #
|
| 489 |
padding: 15px;
|
| 490 |
border-radius: 8px;
|
| 491 |
-
border:
|
|
|
|
|
|
|
| 492 |
}
|
| 493 |
iframe {
|
| 494 |
border: none;
|
| 495 |
border-radius: 10px;
|
| 496 |
-
box-shadow: 0
|
|
|
|
| 497 |
}
|
| 498 |
.gr-button-primary {
|
| 499 |
-
background: linear-gradient(135deg, #
|
| 500 |
border: none !important;
|
| 501 |
-
color: #
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 502 |
}
|
| 503 |
.gr-button-secondary {
|
| 504 |
-
background: linear-gradient(135deg, #
|
| 505 |
border: none !important;
|
| 506 |
color: #fff !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 507 |
}
|
| 508 |
"""
|
| 509 |
|
| 510 |
with gr.Blocks(css=css, title="DNA-Diffusion Suite", theme=gr.themes.Soft()) as demo:
|
| 511 |
gr.Markdown(
|
| 512 |
"""
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 518 |
"""
|
| 519 |
)
|
| 520 |
|
| 521 |
gpu_status = gr.Markdown(
|
| 522 |
-
f
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 523 |
)
|
| 524 |
|
| 525 |
with gr.Tabs():
|
| 526 |
# Tab 1: Sequence Generation
|
| 527 |
-
with gr.TabItem("
|
| 528 |
with gr.Row():
|
| 529 |
with gr.Column(scale=1):
|
| 530 |
cell_type = gr.Dropdown(
|
|
@@ -550,7 +717,7 @@ def create_demo():
|
|
| 550 |
)
|
| 551 |
|
| 552 |
generate_btn = gr.Button(
|
| 553 |
-
"
|
| 554 |
variant="primary",
|
| 555 |
size="lg"
|
| 556 |
)
|
|
@@ -568,10 +735,10 @@ def create_demo():
|
|
| 568 |
)
|
| 569 |
|
| 570 |
# Tab 2: 3D Visualization
|
| 571 |
-
with gr.TabItem("
|
| 572 |
with gr.Row():
|
| 573 |
with gr.Column():
|
| 574 |
-
gr.Markdown("### 3D DNA Structure Visualization")
|
| 575 |
gr.Markdown("The 3D viewer shows the double helix structure of your generated DNA sequence.")
|
| 576 |
|
| 577 |
# HTML component for 3D viewer
|
|
@@ -589,8 +756,8 @@ def create_demo():
|
|
| 589 |
|
| 590 |
# Tab 3: DNA Casino (if external HTML exists)
|
| 591 |
with gr.TabItem("🎰 DNA Casino"):
|
| 592 |
-
gr.Markdown("### DNA Slot Machine Game")
|
| 593 |
-
gr.Markdown("Experience DNA generation as a casino game!")
|
| 594 |
|
| 595 |
# Load external HTML file using helper function
|
| 596 |
casino_html = gr.HTML(
|
|
@@ -626,7 +793,7 @@ def create_demo():
|
|
| 626 |
)
|
| 627 |
|
| 628 |
batch_generate_btn = gr.Button(
|
| 629 |
-
"
|
| 630 |
variant="primary"
|
| 631 |
)
|
| 632 |
|
|
@@ -638,7 +805,7 @@ def create_demo():
|
|
| 638 |
|
| 639 |
status_text = gr.Textbox(
|
| 640 |
label="Status",
|
| 641 |
-
value="Ready to generate sequences...",
|
| 642 |
interactive=False
|
| 643 |
)
|
| 644 |
|
|
@@ -650,11 +817,11 @@ def create_demo():
|
|
| 650 |
sequence = app.generate_with_gpu(cell_type, guidance_scale, enhanced)
|
| 651 |
analysis = app.analyze_sequence(sequence)
|
| 652 |
|
| 653 |
-
status_text.value = f"
|
| 654 |
return sequence, analysis, status_text.value
|
| 655 |
|
| 656 |
except Exception as e:
|
| 657 |
-
error_msg = f"
|
| 658 |
logger.error(error_msg)
|
| 659 |
return "", {}, error_msg
|
| 660 |
|
|
@@ -674,7 +841,7 @@ def create_demo():
|
|
| 674 |
|
| 675 |
def generate_batch(cell_types, count):
|
| 676 |
if not cell_types:
|
| 677 |
-
return None, "
|
| 678 |
|
| 679 |
try:
|
| 680 |
status_text.value = "🔄 Generating batch on GPU..."
|
|
@@ -693,11 +860,11 @@ def create_demo():
|
|
| 693 |
analysis['melting_temp']
|
| 694 |
])
|
| 695 |
|
| 696 |
-
status_text.value = f"
|
| 697 |
return results, status_text.value
|
| 698 |
|
| 699 |
except Exception as e:
|
| 700 |
-
error_msg = f"
|
| 701 |
logger.error(error_msg)
|
| 702 |
return None, error_msg
|
| 703 |
|
|
@@ -730,10 +897,10 @@ def create_demo():
|
|
| 730 |
# Casino sequence analysis
|
| 731 |
def analyze_casino_sequence(seq):
|
| 732 |
if not seq:
|
| 733 |
-
return {}, "
|
| 734 |
|
| 735 |
analysis = app.analyze_sequence(seq)
|
| 736 |
-
return analysis, "
|
| 737 |
|
| 738 |
try:
|
| 739 |
analyze_casino_btn.click(
|
|
|
|
| 186 |
encoded_content = urllib.parse.quote(content, safe='')
|
| 187 |
return f'<iframe src="data:text/html;charset=utf-8,{encoded_content}" width="100%" height="800px" style="border: none; border-radius: 10px;"></iframe>'
|
| 188 |
except FileNotFoundError:
|
| 189 |
+
return f'''
|
| 190 |
+
<div style="
|
| 191 |
+
padding: 60px 40px;
|
| 192 |
+
text-align: center;
|
| 193 |
+
background: linear-gradient(135deg, rgba(253, 121, 168, 0.1), rgba(162, 155, 254, 0.1));
|
| 194 |
+
border: 2px dashed #a29bfe;
|
| 195 |
+
border-radius: 20px;
|
| 196 |
+
margin: 20px;
|
| 197 |
+
">
|
| 198 |
+
<h3 style="color: #5f3dc4; font-size: 1.5em; margin-bottom: 10px;">
|
| 199 |
+
📁 File Not Found
|
| 200 |
+
</h3>
|
| 201 |
+
<p style="color: #6c5ce7; font-size: 1.1em;">
|
| 202 |
+
{filename} not found in the current directory.
|
| 203 |
+
</p>
|
| 204 |
+
<p style="color: #74b9ff; margin-top: 20px;">
|
| 205 |
+
Please place the file in the same directory as app.py
|
| 206 |
+
</p>
|
| 207 |
+
</div>
|
| 208 |
+
'''
|
| 209 |
except Exception as e:
|
| 210 |
+
return f'''
|
| 211 |
+
<div style="
|
| 212 |
+
padding: 60px 40px;
|
| 213 |
+
text-align: center;
|
| 214 |
+
background: linear-gradient(135deg, rgba(253, 121, 168, 0.1), rgba(253, 203, 110, 0.1));
|
| 215 |
+
border: 2px dashed #fd79a8;
|
| 216 |
+
border-radius: 20px;
|
| 217 |
+
margin: 20px;
|
| 218 |
+
">
|
| 219 |
+
<h3 style="color: #e17055; font-size: 1.5em; margin-bottom: 10px;">
|
| 220 |
+
❌ Error Loading File
|
| 221 |
+
</h3>
|
| 222 |
+
<p style="color: #d63031; font-size: 1.1em;">
|
| 223 |
+
{str(e)}
|
| 224 |
+
</p>
|
| 225 |
+
</div>
|
| 226 |
+
'''
|
| 227 |
|
| 228 |
# HTML for 3D Viewer
|
| 229 |
HTML_3D_VIEWER = """
|
|
|
|
| 235 |
body {
|
| 236 |
margin: 0;
|
| 237 |
padding: 0;
|
| 238 |
+
background: linear-gradient(135deg, #ffeaa7 0%, #fab1a0 25%, #a29bfe 50%, #74b9ff 75%, #81ecec 100%);
|
| 239 |
font-family: Arial, sans-serif;
|
| 240 |
+
color: #2d3436;
|
| 241 |
height: 100vh;
|
| 242 |
overflow: hidden;
|
| 243 |
}
|
|
|
|
| 254 |
position: absolute;
|
| 255 |
top: 20px;
|
| 256 |
right: 20px;
|
| 257 |
+
background: rgba(255, 255, 255, 0.9);
|
| 258 |
+
backdrop-filter: blur(10px);
|
| 259 |
padding: 20px;
|
| 260 |
+
border-radius: 15px;
|
| 261 |
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
| 262 |
max-width: 300px;
|
| 263 |
}
|
| 264 |
.controls-panel h3 {
|
| 265 |
+
color: #5f3dc4;
|
| 266 |
margin-top: 0;
|
| 267 |
+
font-weight: 600;
|
| 268 |
}
|
| 269 |
.control-btn {
|
| 270 |
+
background: linear-gradient(135deg, #74b9ff, #a29bfe);
|
| 271 |
+
color: #fff;
|
| 272 |
border: none;
|
| 273 |
+
padding: 10px 18px;
|
| 274 |
margin: 5px;
|
| 275 |
+
border-radius: 8px;
|
| 276 |
cursor: pointer;
|
| 277 |
+
font-weight: 600;
|
| 278 |
+
box-shadow: 0 4px 6px rgba(162, 155, 254, 0.3);
|
| 279 |
+
transition: all 0.3s ease;
|
| 280 |
}
|
| 281 |
.control-btn:hover {
|
| 282 |
+
transform: translateY(-2px);
|
| 283 |
+
box-shadow: 0 6px 12px rgba(162, 155, 254, 0.4);
|
| 284 |
}
|
| 285 |
.info-display {
|
| 286 |
position: absolute;
|
| 287 |
bottom: 20px;
|
| 288 |
left: 20px;
|
| 289 |
+
background: rgba(255, 255, 255, 0.9);
|
| 290 |
+
backdrop-filter: blur(10px);
|
| 291 |
+
padding: 15px 20px;
|
| 292 |
+
border-radius: 12px;
|
| 293 |
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
| 294 |
}
|
| 295 |
#sequence-display {
|
| 296 |
font-family: monospace;
|
| 297 |
+
color: #5f3dc4;
|
| 298 |
word-break: break-all;
|
| 299 |
margin-top: 10px;
|
| 300 |
+
background: rgba(162, 155, 254, 0.1);
|
| 301 |
+
padding: 10px;
|
| 302 |
+
border-radius: 8px;
|
| 303 |
+
border: 1px solid rgba(162, 155, 254, 0.3);
|
| 304 |
+
}
|
| 305 |
+
strong {
|
| 306 |
+
color: #2d3436;
|
| 307 |
+
font-weight: 600;
|
| 308 |
}
|
| 309 |
</style>
|
| 310 |
</head>
|
|
|
|
| 313 |
<canvas id="canvas3d"></canvas>
|
| 314 |
|
| 315 |
<div class="controls-panel">
|
| 316 |
+
<h3>🎨 3D View Controls</h3>
|
| 317 |
<button class="control-btn" onclick="setViewMode('cartoon')">Cartoon</button>
|
| 318 |
<button class="control-btn" onclick="setViewMode('stick')">Stick</button>
|
| 319 |
<button class="control-btn" onclick="setViewMode('sphere')">Sphere</button>
|
|
|
|
| 337 |
|
| 338 |
function init() {
|
| 339 |
scene = new THREE.Scene();
|
| 340 |
+
// Soft white background with subtle gradient
|
| 341 |
+
scene.background = new THREE.Color(0xffffff);
|
| 342 |
+
scene.fog = new THREE.Fog(0xffffff, 50, 200);
|
| 343 |
|
| 344 |
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
| 345 |
camera.position.z = 50;
|
| 346 |
|
| 347 |
+
renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('canvas3d'), antialias: true, alpha: true });
|
| 348 |
renderer.setSize(window.innerWidth, window.innerHeight);
|
| 349 |
+
renderer.setClearColor(0xffffff, 0.5);
|
| 350 |
|
| 351 |
+
const ambientLight = new THREE.AmbientLight(0xffffff, 0.8);
|
| 352 |
scene.add(ambientLight);
|
| 353 |
|
| 354 |
+
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6);
|
| 355 |
directionalLight.position.set(50, 50, 50);
|
| 356 |
+
directionalLight.castShadow = true;
|
| 357 |
scene.add(directionalLight);
|
| 358 |
|
| 359 |
+
const directionalLight2 = new THREE.DirectionalLight(0xa29bfe, 0.3);
|
| 360 |
+
directionalLight2.position.set(-50, 50, -50);
|
| 361 |
+
scene.add(directionalLight2);
|
| 362 |
+
|
| 363 |
moleculeGroup = new THREE.Group();
|
| 364 |
scene.add(moleculeGroup);
|
| 365 |
|
|
|
|
| 415 |
const tubeGeometry1 = new THREE.TubeGeometry(curve1, 100, 0.5, 8, false);
|
| 416 |
const tubeGeometry2 = new THREE.TubeGeometry(curve2, 100, 0.5, 8, false);
|
| 417 |
|
| 418 |
+
const material1 = new THREE.MeshPhongMaterial({
|
| 419 |
+
color: 0x74b9ff,
|
| 420 |
+
shininess: 100,
|
| 421 |
+
specular: 0xffffff
|
| 422 |
+
});
|
| 423 |
+
const material2 = new THREE.MeshPhongMaterial({
|
| 424 |
+
color: 0xa29bfe,
|
| 425 |
+
shininess: 100,
|
| 426 |
+
specular: 0xffffff
|
| 427 |
+
});
|
| 428 |
|
| 429 |
moleculeGroup.add(new THREE.Mesh(tubeGeometry1, material1));
|
| 430 |
moleculeGroup.add(new THREE.Mesh(tubeGeometry2, material2));
|
|
|
|
| 440 |
|
| 441 |
const geometry = new THREE.CylinderGeometry(0.3, 0.3, distance, 8);
|
| 442 |
const material = new THREE.MeshPhongMaterial({
|
| 443 |
+
color: getBaseColor(sequence[i]),
|
| 444 |
+
shininess: 100,
|
| 445 |
+
specular: 0xffffff
|
| 446 |
});
|
| 447 |
|
| 448 |
const cylinder = new THREE.Mesh(geometry, material);
|
|
|
|
| 460 |
|
| 461 |
function getBaseColor(base) {
|
| 462 |
const colors = {
|
| 463 |
+
'A': 0xfd79a8, // Soft pink
|
| 464 |
+
'T': 0x81ecec, // Soft turquoise
|
| 465 |
+
'G': 0xfdcb6e, // Soft yellow
|
| 466 |
+
'C': 0xa29bfe // Soft purple
|
| 467 |
};
|
| 468 |
+
return colors[base] || 0x74b9ff;
|
| 469 |
}
|
| 470 |
|
| 471 |
function setViewMode(mode) {
|
|
|
|
| 547 |
css = """
|
| 548 |
.gradio-container {
|
| 549 |
font-family: 'Arial', sans-serif;
|
| 550 |
+
background: linear-gradient(135deg, #ffeaa7 0%, #fab1a0 25%, #a29bfe 50%, #74b9ff 75%, #81ecec 100%);
|
| 551 |
+
min-height: 100vh;
|
| 552 |
}
|
| 553 |
+
/* Alternative pastel gradients - uncomment to use */
|
| 554 |
+
/* Soft pink to purple: background: linear-gradient(135deg, #ffeef8 0%, #f8e1ff 25%, #e1e8ff 50%, #d4f1ff 75%, #c8f7f7 100%); */
|
| 555 |
+
/* Peach to lavender: background: linear-gradient(135deg, #fff5e6 0%, #ffe6f2 25%, #f0e6ff 50%, #e6f0ff 75%, #e6fff9 100%); */
|
| 556 |
+
/* Warm sunset: background: linear-gradient(135deg, #fff9e6 0%, #ffede6 25%, #ffe6ee 50%, #f2e6ff 75%, #e6f3ff 100%); */
|
| 557 |
+
|
| 558 |
.sequence-box {
|
| 559 |
font-family: 'Courier New', monospace;
|
| 560 |
+
background-color: rgba(255, 255, 255, 0.8);
|
| 561 |
+
color: #2d3436;
|
| 562 |
padding: 15px;
|
| 563 |
border-radius: 8px;
|
| 564 |
+
border: 2px solid #74b9ff;
|
| 565 |
+
backdrop-filter: blur(10px);
|
| 566 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
| 567 |
}
|
| 568 |
iframe {
|
| 569 |
border: none;
|
| 570 |
border-radius: 10px;
|
| 571 |
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
| 572 |
+
background: rgba(255, 255, 255, 0.9);
|
| 573 |
}
|
| 574 |
.gr-button-primary {
|
| 575 |
+
background: linear-gradient(135deg, #74b9ff, #a29bfe) !important;
|
| 576 |
border: none !important;
|
| 577 |
+
color: #fff !important;
|
| 578 |
+
font-weight: 600 !important;
|
| 579 |
+
box-shadow: 0 4px 6px rgba(162, 155, 254, 0.3) !important;
|
| 580 |
+
transition: all 0.3s ease !important;
|
| 581 |
+
}
|
| 582 |
+
.gr-button-primary:hover {
|
| 583 |
+
transform: translateY(-2px) !important;
|
| 584 |
+
box-shadow: 0 6px 12px rgba(162, 155, 254, 0.4) !important;
|
| 585 |
}
|
| 586 |
.gr-button-secondary {
|
| 587 |
+
background: linear-gradient(135deg, #fd79a8, #fdcb6e) !important;
|
| 588 |
border: none !important;
|
| 589 |
color: #fff !important;
|
| 590 |
+
font-weight: 600 !important;
|
| 591 |
+
box-shadow: 0 4px 6px rgba(253, 121, 168, 0.3) !important;
|
| 592 |
+
transition: all 0.3s ease !important;
|
| 593 |
+
}
|
| 594 |
+
.gr-button-secondary:hover {
|
| 595 |
+
transform: translateY(-2px) !important;
|
| 596 |
+
box-shadow: 0 6px 12px rgba(253, 121, 168, 0.4) !important;
|
| 597 |
+
}
|
| 598 |
+
/* Card styling */
|
| 599 |
+
.gr-box {
|
| 600 |
+
background: rgba(255, 255, 255, 0.7) !important;
|
| 601 |
+
backdrop-filter: blur(10px) !important;
|
| 602 |
+
border: 1px solid rgba(255, 255, 255, 0.8) !important;
|
| 603 |
+
}
|
| 604 |
+
/* Tab styling */
|
| 605 |
+
.gr-button.gr-button-sm {
|
| 606 |
+
background: rgba(255, 255, 255, 0.6) !important;
|
| 607 |
+
color: #2d3436 !important;
|
| 608 |
+
border: 1px solid rgba(255, 255, 255, 0.8) !important;
|
| 609 |
+
}
|
| 610 |
+
.gr-button.gr-button-sm.selected {
|
| 611 |
+
background: linear-gradient(135deg, #74b9ff, #a29bfe) !important;
|
| 612 |
+
color: #fff !important;
|
| 613 |
+
border: none !important;
|
| 614 |
+
}
|
| 615 |
+
/* Input fields */
|
| 616 |
+
.gr-input, .gr-dropdown {
|
| 617 |
+
background: rgba(255, 255, 255, 0.8) !important;
|
| 618 |
+
border: 2px solid #dfe6e9 !important;
|
| 619 |
+
color: #2d3436 !important;
|
| 620 |
+
}
|
| 621 |
+
.gr-input:focus, .gr-dropdown:focus {
|
| 622 |
+
border-color: #74b9ff !important;
|
| 623 |
+
box-shadow: 0 0 0 3px rgba(116, 185, 255, 0.2) !important;
|
| 624 |
+
}
|
| 625 |
+
/* Labels and text */
|
| 626 |
+
label, .gr-label {
|
| 627 |
+
color: #2d3436 !important;
|
| 628 |
+
font-weight: 600 !important;
|
| 629 |
+
}
|
| 630 |
+
/* Status text */
|
| 631 |
+
#status {
|
| 632 |
+
background: rgba(255, 255, 255, 0.8) !important;
|
| 633 |
+
color: #2d3436 !important;
|
| 634 |
}
|
| 635 |
"""
|
| 636 |
|
| 637 |
with gr.Blocks(css=css, title="DNA-Diffusion Suite", theme=gr.themes.Soft()) as demo:
|
| 638 |
gr.Markdown(
|
| 639 |
"""
|
| 640 |
+
<div style="text-align: center; padding: 20px;">
|
| 641 |
+
<h1 style="
|
| 642 |
+
font-size: 3em;
|
| 643 |
+
background: linear-gradient(135deg, #5f3dc4, #74b9ff, #fd79a8);
|
| 644 |
+
-webkit-background-clip: text;
|
| 645 |
+
-webkit-text-fill-color: transparent;
|
| 646 |
+
background-clip: text;
|
| 647 |
+
margin-bottom: 10px;
|
| 648 |
+
">
|
| 649 |
+
🧬 DNA-Diffusion Suite
|
| 650 |
+
</h1>
|
| 651 |
+
<p style="
|
| 652 |
+
font-size: 1.2em;
|
| 653 |
+
color: #5f3dc4;
|
| 654 |
+
font-weight: 500;
|
| 655 |
+
">
|
| 656 |
+
AI-Powered Molecular Engineering with Beautiful Visualizations
|
| 657 |
+
</p>
|
| 658 |
+
<div style="margin-top: 15px;">
|
| 659 |
+
<span style="
|
| 660 |
+
background: linear-gradient(135deg, #74b9ff, #a29bfe);
|
| 661 |
+
color: white;
|
| 662 |
+
padding: 6px 16px;
|
| 663 |
+
border-radius: 20px;
|
| 664 |
+
font-size: 0.9em;
|
| 665 |
+
font-weight: 600;
|
| 666 |
+
display: inline-block;
|
| 667 |
+
box-shadow: 0 4px 6px rgba(162, 155, 254, 0.3);
|
| 668 |
+
">
|
| 669 |
+
✨ GPU Accelerated
|
| 670 |
+
</span>
|
| 671 |
+
</div>
|
| 672 |
+
</div>
|
| 673 |
"""
|
| 674 |
)
|
| 675 |
|
| 676 |
gpu_status = gr.Markdown(
|
| 677 |
+
f'''
|
| 678 |
+
<div style="
|
| 679 |
+
text-align: center;
|
| 680 |
+
padding: 10px;
|
| 681 |
+
background: {'linear-gradient(135deg, rgba(129, 236, 236, 0.2), rgba(116, 185, 255, 0.2))' if SPACES_AVAILABLE else 'linear-gradient(135deg, rgba(253, 121, 168, 0.2), rgba(253, 203, 110, 0.2))'};
|
| 682 |
+
border-radius: 10px;
|
| 683 |
+
margin: 10px 0;
|
| 684 |
+
">
|
| 685 |
+
<span style="font-size: 1.1em; color: {'#00b894' if SPACES_AVAILABLE else '#e17055'};">
|
| 686 |
+
{'🎯 GPU Accelerated' if SPACES_AVAILABLE else '💻 CPU Mode'}
|
| 687 |
+
</span>
|
| 688 |
+
</div>
|
| 689 |
+
'''
|
| 690 |
)
|
| 691 |
|
| 692 |
with gr.Tabs():
|
| 693 |
# Tab 1: Sequence Generation
|
| 694 |
+
with gr.TabItem("🌸 Generate Sequence"):
|
| 695 |
with gr.Row():
|
| 696 |
with gr.Column(scale=1):
|
| 697 |
cell_type = gr.Dropdown(
|
|
|
|
| 717 |
)
|
| 718 |
|
| 719 |
generate_btn = gr.Button(
|
| 720 |
+
"✨ Generate Sequence",
|
| 721 |
variant="primary",
|
| 722 |
size="lg"
|
| 723 |
)
|
|
|
|
| 735 |
)
|
| 736 |
|
| 737 |
# Tab 2: 3D Visualization
|
| 738 |
+
with gr.TabItem("🔮 3D Structure"):
|
| 739 |
with gr.Row():
|
| 740 |
with gr.Column():
|
| 741 |
+
gr.Markdown("### 🧬 3D DNA Structure Visualization")
|
| 742 |
gr.Markdown("The 3D viewer shows the double helix structure of your generated DNA sequence.")
|
| 743 |
|
| 744 |
# HTML component for 3D viewer
|
|
|
|
| 756 |
|
| 757 |
# Tab 3: DNA Casino (if external HTML exists)
|
| 758 |
with gr.TabItem("🎰 DNA Casino"):
|
| 759 |
+
gr.Markdown("### 🎲 DNA Slot Machine Game")
|
| 760 |
+
gr.Markdown("Experience DNA generation as a fun casino game!")
|
| 761 |
|
| 762 |
# Load external HTML file using helper function
|
| 763 |
casino_html = gr.HTML(
|
|
|
|
| 793 |
)
|
| 794 |
|
| 795 |
batch_generate_btn = gr.Button(
|
| 796 |
+
"✨ Generate Batch",
|
| 797 |
variant="primary"
|
| 798 |
)
|
| 799 |
|
|
|
|
| 805 |
|
| 806 |
status_text = gr.Textbox(
|
| 807 |
label="Status",
|
| 808 |
+
value="🌸 Ready to generate sequences...",
|
| 809 |
interactive=False
|
| 810 |
)
|
| 811 |
|
|
|
|
| 817 |
sequence = app.generate_with_gpu(cell_type, guidance_scale, enhanced)
|
| 818 |
analysis = app.analyze_sequence(sequence)
|
| 819 |
|
| 820 |
+
status_text.value = f"✨ Successfully generated sequence for {cell_type}"
|
| 821 |
return sequence, analysis, status_text.value
|
| 822 |
|
| 823 |
except Exception as e:
|
| 824 |
+
error_msg = f"⚠️ Error: {str(e)}"
|
| 825 |
logger.error(error_msg)
|
| 826 |
return "", {}, error_msg
|
| 827 |
|
|
|
|
| 841 |
|
| 842 |
def generate_batch(cell_types, count):
|
| 843 |
if not cell_types:
|
| 844 |
+
return None, "⚠️ Please select at least one cell type"
|
| 845 |
|
| 846 |
try:
|
| 847 |
status_text.value = "🔄 Generating batch on GPU..."
|
|
|
|
| 860 |
analysis['melting_temp']
|
| 861 |
])
|
| 862 |
|
| 863 |
+
status_text.value = f"✨ Generated {len(results)} sequences"
|
| 864 |
return results, status_text.value
|
| 865 |
|
| 866 |
except Exception as e:
|
| 867 |
+
error_msg = f"⚠️ Error: {str(e)}"
|
| 868 |
logger.error(error_msg)
|
| 869 |
return None, error_msg
|
| 870 |
|
|
|
|
| 897 |
# Casino sequence analysis
|
| 898 |
def analyze_casino_sequence(seq):
|
| 899 |
if not seq:
|
| 900 |
+
return {}, "⚠️ No sequence to analyze"
|
| 901 |
|
| 902 |
analysis = app.analyze_sequence(seq)
|
| 903 |
+
return analysis, "✨ Casino sequence analyzed"
|
| 904 |
|
| 905 |
try:
|
| 906 |
analyze_casino_btn.click(
|