|
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") |