File size: 6,751 Bytes
50bf798
 
 
580db5b
b0cb70d
9f2073b
289b045
0014c63
977b489
2550c12
50bf798
b0cb70d
9f2073b
50bf798
 
 
 
 
 
9f2073b
26ee080
50bf798
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ea99d62
50bf798
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
580db5b
9f2073b
 
50bf798
9f2073b
2550c12
 
 
c9bfe79
50bf798
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
977b489
2550c12
50bf798
 
 
 
2550c12
9f2073b
41bea22
dbcc60e
2550c12
50bf798
 
2550c12
50bf798
 
b3119be
 
 
 
 
 
 
 
 
 
 
2550c12
b3119be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2550c12
41bea22
50bf798
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
import csv
csv.field_size_limit(131072 * 10)

import gradio as gr
from igfold import IgFoldRunner
import os
import random
import base64
import socket
import re
from pathlib import Path

def read_mol(molpath):
    try:
        with open(molpath, "r") as fp:
            return fp.read()
    except Exception as e:
        print(f"Error reading PDB file: {e}")
        return ""

def molecule(input_pdb, h_seq, l_seq):
    try:
        mol = read_mol(input_pdb)
        if not mol:
            return "<p>Error: Failed to read PDB file</p>"

        byte_content = mol.encode('utf-8')
        base64_content = base64.b64encode(byte_content).decode('utf-8')

        x = f"""<!DOCTYPE html><html><head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <style>body{{font-family:sans-serif}}
        .mol-container {{width: 100%; height: 600px; position: relative;}}
        .mol-container select{{background-image:None;}}</style>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
        <script src="https://3Dmol.csb.pitt.edu/build/3Dmol-min.js"></script>
        </head><body><div id="container" class="mol-container"></div>
        <script>
        $(document).ready(function () {{
            let element = $("#container");
            let config = {{ backgroundColor: "white" }};
            let viewer = $3Dmol.createViewer(element, config);
            viewer.addModel(`{mol}`, "pdb");
            viewer.getModel(0).setStyle({{chain: "H"}}, {{cartoon:{{color:"red"}}}});
            viewer.getModel(0).setStyle({{chain: "L"}}, {{cartoon:{{color:"blue"}}}});
            viewer.addSurface($3Dmol.SurfaceType.VDW, {{opacity: 0.4, color: "lightblue"}});
            viewer.zoomTo();
            viewer.render();
            viewer.zoom(0.8, 2000);
        }})
        </script></body></html>"""

        return f"""<iframe style="width: 100%; height: 600px" srcdoc='{x}'></iframe>
        <div style="position: absolute; top: 10px; right: 10px; background-color: white; padding: 10px; border: 1px solid black;">
            <div style="width: 20px; height: 20px; background-color: red; display: inline-block;"></div>
            <span>Heavy chain</span><br>
            <div style="width: 20px; height: 20px; background-color: blue; display: inline-block;"></div>
            <span>Light chain</span>
            <div style="margin-top: 5px;">
            <a href="data:application/octet-stream;base64,{base64_content}" download="structure.pdb">Download PDB</a>
            </div>
        </div>"""
    except Exception as e:
        print(f"Error in molecule visualization: {e}")
        return f"<p>Error generating visualization: {str(e)}</p>"

def validate(seq):
    alphabet = set('ACDEFGHIKLMNPQRSTVWY')
    return not (set(seq.upper()) - alphabet)

def clean_sequence(seq):
    return re.sub(r'\s+', '', seq)

def pred_seq(h_seq, l_seq):
    try:
        h_seq = clean_sequence(h_seq).upper()
        l_seq = clean_sequence(l_seq).upper()

        if not (validate(h_seq) and validate(l_seq)):
            return "<p>Error: Invalid amino acid characters detected</p>"

        sequences = {"H": h_seq, "L": l_seq}
        f_name = f"temp_{random.randint(0, 100000)}.pdb"
        
        try:
            igfold = IgFoldRunner(num_models=1)
            igfold.fold(f_name, sequences=sequences, do_refine=False, do_renum=False)
            
            if not os.path.exists(f_name):
                return "<p>Error: Failed to generate PDB file</p>"
                
            html = molecule(f_name, h_seq, l_seq)
        finally:
            if os.path.exists(f_name):
                os.remove(f_name)
        
        return html
    except Exception as e:
        print(f"Error in prediction: {e}")
        return f"<p>Error: {str(e)}</p>"

examples = [
    ["QVQLKESGPGLVAPSQSLSITCTVSGFSLSSYGVSWVRQPPGKGLEWLGVIWGDGSTNYHPNLMSRLSISKDISKSQVLFKLNSLQTDDTATYYCVTLDYWGQGTSVTVSS",
     "DVVMTQTPLSLPVSLGDQASISCRSSQSLVHRNGNTYLHWYLQKPGQSPKLLIYKVSNRFSGVPDRFSGSGSGTDFTLKISRVEAEDLGLYFCFQTTYVPNTFGGGTKLEIK"],
    ["EVQLLESGGGLVQPGGSLRLSCAASGFTFSLYWMGWVRQAPGKGLEWVSSISSSGGVTPYADSVKGRFTISRDNSKNTLYLQMNSLRAEDTAVYYCAKLGELGWFDPWGQGTLVTVSS",
     "DIQMTQSPSSLSASVGDRVTITCRASQGISSYLNWYQQKPGKAPKLLIYYASNLQNGVPSRFSGSGSGTDFTLTISSLQPEDFATYYCQQSYSTPLTFGGGTKVEIK"]
]

with gr.Blocks() as demo:
    gr.Markdown('# Antibody Structure Prediction')
    with gr.Row():
        h_text = gr.Textbox(lines=5, label="Heavy chain", placeholder="Enter heavy chain sequence...")
        l_text = gr.Textbox(lines=5, label="Light chain", placeholder="Enter light chain sequence...")
    
    gr.Examples(examples=examples, inputs=[h_text, l_text], label="Example sequences")
    btn = gr.Button("Predict Structure")
    
    progress_bar = gr.HTML("""
    <div id="progress" style="display: none; margin: 20px 0;">
        <div style="width: 100%; background: #f0f0f0; border-radius: 5px;">
            <div id="progress-bar" style="height: 20px; width: 0%; background: linear-gradient(90deg, #4CAF50 0%, #8BC34A 100%); border-radius: 5px; transition: width 0.5s;">
                <div style="text-align: center; color: white; line-height: 20px;">Processing...</div>
            </div>
        </div>
    </div>
    """)
    
    output_html = gr.HTML()
    
    js_animation = """
    <script>
    function startProgress() {
        const progress = document.getElementById("progress");
        const progressBar = document.getElementById("progress-bar");
        progress.style.display = "block";
        
        let width = 0;
        const interval = setInterval(() => {
            if (width >= 90) {
                clearInterval(interval);
                return;
            }
            width += 5;
            progressBar.style.width = width + "%";
        }, 500);
        
        return interval;
    }
    </script>
    """
    
    gr.HTML(js_animation)
    
    def wrapper_pred_seq(h_seq, l_seq):
        import time
        progress_js = """
        <script>
            const interval = startProgress();
        </script>
        """
        
        result = pred_seq(h_seq, l_seq)
        
        complete_js = """
        <script>
            if (typeof interval !== 'undefined') clearInterval(interval);
            document.getElementById("progress-bar").style.width = "100%";
            setTimeout(() => {
                document.getElementById("progress").style.display = "none";
            }, 1000);
        </script>
        """
        
        return progress_js + result + complete_js
    
    btn.click(wrapper_pred_seq, inputs=[h_text, l_text], outputs=output_html)

if __name__ == "__main__":
    demo.launch(show_error=True, server_name="0.0.0.0")