File size: 7,958 Bytes
965f144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
{% 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>&le;500 (Ro5)</td></tr>
          <tr><td>LogP</td><td class="val">{{ p.logp }}</td><td>&le;5 (Ro5)</td></tr>
          <tr><td>H-Bond Donors</td><td class="val">{{ p.hbd }}</td><td>&le;5 (Ro5)</td></tr>
          <tr><td>H-Bond Acceptors</td><td class="val">{{ p.hba }}</td><td>&le;10 (Ro5)</td></tr>
          <tr><td>TPSA (Γ…Β²)</td><td class="val">{{ p.tpsa }}</td><td>&le;140 (Veber)</td></tr>
          <tr><td>Rotatable Bonds</td><td class="val">{{ p.rotbonds }}</td><td>&le;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>&gt;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 &le;500, LogP &le;5, HBD &le;5, HBA &le;10. Predicts oral bioavailability.</p>
        <p style="margin-bottom:.6rem"><strong style="color:var(--g2)">Veber Rules</strong> β€” TPSA &le;140 Γ…Β² and RotBonds &le;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>
  {% if result %}
  renderPlotly('chart-radar', {{ result.chart_radar | safe }});
  {% endif %}
</script>
{% endblock %}