Spaces:
Runtime error
Runtime error
| {% extends "base.html" %} | |
| {% block title %}Molecule Analyzer β MoleSight AI{% endblock %} | |
| {% block content %} | |
| <div class="page-header fade-up"> | |
| <h1>Molecule <span class="accent">Analyzer</span></h1> | |
| <div class="sub">Compute physicochemical properties Β· Lipinski / Veber / Ghose rule assessment Β· 2D structure rendering</div> | |
| </div> | |
| <div class="grid-2 fade-up"> | |
| <!-- Input panel --> | |
| <div> | |
| <div class="card" style="margin-bottom:1rem"> | |
| <div class="card-title">SMILES Input</div> | |
| <form method="POST" action="{{ url_for('main.analyze') }}"> | |
| <div class="form-group"> | |
| <label class="form-label" for="smiles-input">SMILES String</label> | |
| <input id="smiles-input" name="smiles" class="form-input" | |
| placeholder="e.g. CC(=O)Oc1ccccc1C(=O)O" | |
| value="{{ smiles_input }}" autocomplete="off"/> | |
| </div> | |
| <div style="margin-bottom:1rem"> | |
| <div class="form-label">Quick Examples</div> | |
| <div class="example-pills"> | |
| {% for name, smi in examples %} | |
| <span class="pill" data-smiles="{{ smi }}">{{ name }}</span> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| <button type="submit" class="btn btn-primary">⬑ Analyze Molecule</button> | |
| </form> | |
| </div> | |
| {% if error %} | |
| <div class="alert alert-error fade-up">β {{ error }}</div> | |
| {% endif %} | |
| {% if result %} | |
| <!-- Property table --> | |
| <div class="card fade-up" style="margin-bottom:1rem"> | |
| <div class="card-title">Physicochemical Properties</div> | |
| <table class="prop-table"> | |
| <thead> | |
| <tr><th>Property</th><th>Value</th><th>Threshold</th></tr> | |
| </thead> | |
| <tbody> | |
| {% set p = result.props %} | |
| <tr><td>Formula</td><td class="val">{{ p.formula }}</td><td>β</td></tr> | |
| <tr><td>Mol. Weight (Da)</td><td class="val">{{ p.mw }}</td><td>≤500 (Ro5)</td></tr> | |
| <tr><td>LogP</td><td class="val">{{ p.logp }}</td><td>≤5 (Ro5)</td></tr> | |
| <tr><td>H-Bond Donors</td><td class="val">{{ p.hbd }}</td><td>≤5 (Ro5)</td></tr> | |
| <tr><td>H-Bond Acceptors</td><td class="val">{{ p.hba }}</td><td>≤10 (Ro5)</td></tr> | |
| <tr><td>TPSA (Γ Β²)</td><td class="val">{{ p.tpsa }}</td><td>≤140 (Veber)</td></tr> | |
| <tr><td>Rotatable Bonds</td><td class="val">{{ p.rotbonds }}</td><td>≤10 (Veber)</td></tr> | |
| <tr><td>Heavy Atoms</td><td class="val">{{ p.heavy_atoms }}</td><td>20β70 (Ghose)</td></tr> | |
| <tr><td>Aromatic Rings</td><td class="val">{{ p.aromatic_rings }}</td><td>β</td></tr> | |
| <tr><td>FspΒ³</td><td class="val">{{ p.fsp3 }}</td><td>>0.25 preferred</td></tr> | |
| <tr><td>QED Score</td><td class="val" style="color:var(--amber)">{{ p.qed }}</td><td>0β1 (higher=better)</td></tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <!-- Rule assessments --> | |
| <div class="card fade-up"> | |
| <div class="card-title">Rule Assessments</div> | |
| <div style="margin-bottom:.75rem"> | |
| <div style="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem"> | |
| <span style="font-size:.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:.08em">Lipinski Ro5</span> | |
| {% if result.lipinski.passed %} | |
| <span class="tag tag-green">β PASS</span> | |
| {% else %} | |
| <span class="tag tag-red">{{ result.lipinski.violations }} violation{{ 's' if result.lipinski.violations != 1 }}</span> | |
| {% endif %} | |
| </div> | |
| <div class="rule-grid"> | |
| {% for rule, passed in result.lipinski.rules.items() %} | |
| <div class="rule-item {{ 'rule-pass' if passed else 'rule-fail' }}"> | |
| <span class="rule-check">{{ 'β' if passed else 'β' }}</span> | |
| <span style="font-size:.7rem;color:{{ 'var(--g1)' if passed else 'var(--red)' }}">{{ rule }}</span> | |
| </div> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| <div style="margin-bottom:.75rem"> | |
| <div style="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem"> | |
| <span style="font-size:.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:.08em">Veber Rules</span> | |
| {% if result.veber.passed %} | |
| <span class="tag tag-green">β PASS</span> | |
| {% else %} | |
| <span class="tag tag-amber">{{ result.veber.violations }} violation{{ 's' if result.veber.violations != 1 }}</span> | |
| {% endif %} | |
| </div> | |
| <div class="rule-grid"> | |
| {% for rule, passed in result.veber.rules.items() %} | |
| <div class="rule-item {{ 'rule-pass' if passed else 'rule-fail' }}"> | |
| <span class="rule-check">{{ 'β' if passed else 'β' }}</span> | |
| <span style="font-size:.7rem;color:{{ 'var(--g1)' if passed else 'var(--red)' }}">{{ rule }}</span> | |
| </div> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| <div> | |
| <div style="display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem"> | |
| <span style="font-size:.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:.08em">Ghose Filter</span> | |
| {% if result.ghose.passed %} | |
| <span class="tag tag-green">β PASS</span> | |
| {% else %} | |
| <span class="tag tag-amber">{{ result.ghose.violations }} violation{{ 's' if result.ghose.violations != 1 }}</span> | |
| {% endif %} | |
| </div> | |
| <div class="rule-grid"> | |
| {% for rule, passed in result.ghose.rules.items() %} | |
| <div class="rule-item {{ 'rule-pass' if passed else 'rule-fail' }}"> | |
| <span class="rule-check">{{ 'β' if passed else 'β' }}</span> | |
| <span style="font-size:.7rem;color:{{ 'var(--g1)' if passed else 'var(--red)' }}">{{ rule }}</span> | |
| </div> | |
| {% endfor %} | |
| </div> | |
| </div> | |
| </div> | |
| {% endif %} | |
| </div> | |
| <!-- Right panel: structure + radar --> | |
| <div> | |
| {% if result %} | |
| <!-- 2D Structure --> | |
| <div class="card fade-up" style="margin-bottom:1rem"> | |
| <div class="card-title">2D Structure Rendering</div> | |
| {% if result.svg_img %} | |
| <div class="mol-svg"> | |
| {{ result.svg_img | safe }} | |
| </div> | |
| {% else %} | |
| <div class="mol-placeholder"> | |
| <span>π¬ RDKit not available β structure not rendered</span> | |
| </div> | |
| {% endif %} | |
| </div> | |
| <!-- Radar --> | |
| <div class="card fade-up"> | |
| <div class="card-title">Drug-Likeness Profile (Radar)</div> | |
| <div id="chart-radar" class="plotly-wrap" style="min-height:320px"></div> | |
| </div> | |
| {% else %} | |
| <!-- Placeholder info --> | |
| <div class="card fade-up" style="border-style:dashed;margin-bottom:1rem"> | |
| <div style="text-align:center;padding:2rem;color:var(--muted)"> | |
| <div style="font-size:3rem;margin-bottom:.75rem">⬑</div> | |
| <div style="font-size:.85rem">Enter a SMILES string and click <strong style="color:var(--g1)">Analyze Molecule</strong> to compute properties.</div> | |
| </div> | |
| </div> | |
| <div class="card fade-up"> | |
| <div class="card-title">About the Rules</div> | |
| <div style="font-size:.78rem;color:var(--text);line-height:1.7"> | |
| <p style="margin-bottom:.6rem"><strong style="color:var(--g1)">Lipinski's Rule of Five</strong> β MW ≤500, LogP ≤5, HBD ≤5, HBA ≤10. Predicts oral bioavailability.</p> | |
| <p style="margin-bottom:.6rem"><strong style="color:var(--g2)">Veber Rules</strong> β TPSA ≤140 Γ Β² and RotBonds ≤10. Predicts good oral absorption in rats.</p> | |
| <p><strong style="color:var(--amber)">Ghose Filter</strong> β Tighter constraints on MW, LogP, and heavy atom count for lead-like molecules.</p> | |
| </div> | |
| </div> | |
| {% endif %} | |
| </div> | |
| </div> | |
| {% endblock %} | |
| {% block scripts %} | |
| <script> | |
| </script> | |
| {% endblock %} | |