yq / app.py
ivorobyev's picture
Update app.py
b3119be verified
raw
history blame
6.75 kB
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")