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