Sync from GitHub (preserve manual model files)
Browse files- StreamlitApp/StreamlitApp.py +22 -45
StreamlitApp/StreamlitApp.py
CHANGED
|
@@ -5,9 +5,7 @@ import matplotlib.pyplot as plt
|
|
| 5 |
import matplotlib.patches as mpatches
|
| 6 |
import torch
|
| 7 |
import plotly.express as px
|
| 8 |
-
import json
|
| 9 |
import html as _html
|
| 10 |
-
import streamlit.components.v1 as components
|
| 11 |
from sklearn.manifold import TSNE
|
| 12 |
|
| 13 |
# modular imports
|
|
@@ -52,9 +50,9 @@ def _tooltip_label(label: str, tooltip_text: str) -> None:
|
|
| 52 |
|
| 53 |
def _try_copy_to_clipboard(text: str) -> None:
|
| 54 |
"""
|
| 55 |
-
Best-effort clipboard copy.
|
| 56 |
-
|
| 57 |
-
|
| 58 |
"""
|
| 59 |
if pyperclip is not None:
|
| 60 |
try:
|
|
@@ -62,24 +60,6 @@ def _try_copy_to_clipboard(text: str) -> None:
|
|
| 62 |
except Exception:
|
| 63 |
pass
|
| 64 |
|
| 65 |
-
safe = json.dumps(text)
|
| 66 |
-
# JS copy (browser-side). Clipboard access may be blocked by browser policies.
|
| 67 |
-
components.html(
|
| 68 |
-
f"""
|
| 69 |
-
<script>
|
| 70 |
-
(function() {{
|
| 71 |
-
try {{
|
| 72 |
-
const t = {safe};
|
| 73 |
-
if (navigator.clipboard && navigator.clipboard.writeText) {{
|
| 74 |
-
navigator.clipboard.writeText(t);
|
| 75 |
-
}}
|
| 76 |
-
}} catch (e) {{}}
|
| 77 |
-
}})();
|
| 78 |
-
</script>
|
| 79 |
-
""",
|
| 80 |
-
height=0,
|
| 81 |
-
)
|
| 82 |
-
|
| 83 |
# APP CONFIG
|
| 84 |
st.set_page_config(page_title="AMP Predictor", layout="wide")
|
| 85 |
|
|
@@ -161,7 +141,7 @@ model = load_model()
|
|
| 161 |
|
| 162 |
# PREDICT PAGE
|
| 163 |
if page == "Predict":
|
| 164 |
-
st.header("AMP
|
| 165 |
|
| 166 |
preset_cols = st.columns(2)
|
| 167 |
with preset_cols[0]:
|
|
@@ -243,9 +223,9 @@ if page == "Predict":
|
|
| 243 |
_try_copy_to_clipboard(seq)
|
| 244 |
toast_fn = getattr(st, "toast", None)
|
| 245 |
if toast_fn is not None:
|
| 246 |
-
toast_fn("Copied
|
| 247 |
else:
|
| 248 |
-
st.success("Copied
|
| 249 |
label = top_candidate.get("Prediction", "")
|
| 250 |
conf_str = format_conf_percent(top_candidate["predicted_confidence"], digits=1)
|
| 251 |
st.write(f"**{label} with {conf_str} confidence**")
|
|
@@ -259,7 +239,7 @@ if page == "Predict":
|
|
| 259 |
|
| 260 |
# ANALYZE PAGE
|
| 261 |
elif page == "Analyze":
|
| 262 |
-
st.header("
|
| 263 |
|
| 264 |
# show the last saved analyze output if user navigated back
|
| 265 |
last_seq = st.session_state.analyze_input
|
|
@@ -511,25 +491,27 @@ elif page == "Analyze":
|
|
| 511 |
|
| 512 |
# OPTIMIZE PAGE
|
| 513 |
elif page == "Optimize":
|
| 514 |
-
st.header("
|
| 515 |
|
| 516 |
-
#
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
|
|
|
|
|
|
| 521 |
|
| 522 |
-
warn_opt = sequence_length_warning(seq)
|
| 523 |
if warn_opt:
|
| 524 |
st.caption(f"Warning: {warn_opt}")
|
| 525 |
|
| 526 |
-
|
| 527 |
-
|
| 528 |
st.session_state.optimize_input = seq
|
| 529 |
progress = st.progress(0.0, text="Optimizing...")
|
| 530 |
with st.spinner("Optimizing sequence..."):
|
| 531 |
improved_seq, improved_conf, history = optimize_sequence(seq, model)
|
| 532 |
-
|
| 533 |
st.session_state.optimize_output = (seq, orig_conf, improved_seq, improved_conf, history)
|
| 534 |
progress.progress(1.0, text="Optimization complete")
|
| 535 |
st.success("Optimization finished.")
|
|
@@ -587,7 +569,7 @@ elif page == "Optimize":
|
|
| 587 |
|
| 588 |
# VISUALIZE PEPTIDE PAGE
|
| 589 |
elif page == "Visualize Peptide":
|
| 590 |
-
st.header("
|
| 591 |
# Tighter legend expanders (summary row + scrollable body)
|
| 592 |
st.markdown(
|
| 593 |
"""
|
|
@@ -605,15 +587,11 @@ elif page == "Visualize Peptide":
|
|
| 605 |
""",
|
| 606 |
unsafe_allow_html=True,
|
| 607 |
)
|
| 608 |
-
st.caption(
|
| 609 |
-
"High-impact single-sequence view. **Blue / red / green / gray** match the 3D model, helical wheel, "
|
| 610 |
-
"and functional residue map."
|
| 611 |
-
)
|
| 612 |
|
| 613 |
st.checkbox("Auto-run when sequence changes", value=False, key="viz_peptide_auto_run")
|
| 614 |
|
| 615 |
st.text_input(
|
| 616 |
-
"
|
| 617 |
key="visualize_peptide_input",
|
| 618 |
placeholder="Paste or type a one-letter amino-acid sequence",
|
| 619 |
)
|
|
@@ -622,7 +600,6 @@ elif page == "Visualize Peptide":
|
|
| 622 |
clean_viz = "".join(c for c in seq_viz.upper() if not c.isspace())
|
| 623 |
if not clean_viz:
|
| 624 |
st.session_state.viz_peptide_last_computed = ""
|
| 625 |
-
st.info("Enter a sequence above, then click **Run visualization** (or enable **Auto-run**).")
|
| 626 |
else:
|
| 627 |
run_viz = st.button("Run visualization", type="primary", key="viz_peptide_run_btn")
|
| 628 |
auto_on = bool(st.session_state.get("viz_peptide_auto_run"))
|
|
@@ -683,7 +660,7 @@ elif page == "Visualize Peptide":
|
|
| 683 |
|
| 684 |
# VISUALIZE t-SNE PAGE
|
| 685 |
elif page == "Visualize t-SNE":
|
| 686 |
-
st.header("
|
| 687 |
st.write("Upload peptide sequences (FASTA or plain list) to embed sequences and explore clusters with t-SNE.")
|
| 688 |
|
| 689 |
uploaded_file = st.file_uploader("Upload FASTA or text file", type=["txt", "fasta"])
|
|
|
|
| 5 |
import matplotlib.patches as mpatches
|
| 6 |
import torch
|
| 7 |
import plotly.express as px
|
|
|
|
| 8 |
import html as _html
|
|
|
|
| 9 |
from sklearn.manifold import TSNE
|
| 10 |
|
| 11 |
# modular imports
|
|
|
|
| 50 |
|
| 51 |
def _try_copy_to_clipboard(text: str) -> None:
|
| 52 |
"""
|
| 53 |
+
Best-effort clipboard copy (server-side only).
|
| 54 |
+
Avoids streamlit.components.html — iframe/JS can fail on Hugging Face Spaces
|
| 55 |
+
(TypeError: Failed to fetch dynamically imported module for static/js chunks).
|
| 56 |
"""
|
| 57 |
if pyperclip is not None:
|
| 58 |
try:
|
|
|
|
| 60 |
except Exception:
|
| 61 |
pass
|
| 62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
# APP CONFIG
|
| 64 |
st.set_page_config(page_title="AMP Predictor", layout="wide")
|
| 65 |
|
|
|
|
| 141 |
|
| 142 |
# PREDICT PAGE
|
| 143 |
if page == "Predict":
|
| 144 |
+
st.header("AMP Predictor")
|
| 145 |
|
| 146 |
preset_cols = st.columns(2)
|
| 147 |
with preset_cols[0]:
|
|
|
|
| 223 |
_try_copy_to_clipboard(seq)
|
| 224 |
toast_fn = getattr(st, "toast", None)
|
| 225 |
if toast_fn is not None:
|
| 226 |
+
toast_fn("Copied — or select the sequence above (Ctrl+C)")
|
| 227 |
else:
|
| 228 |
+
st.success("Copied — or select the sequence above (Ctrl+C)")
|
| 229 |
label = top_candidate.get("Prediction", "")
|
| 230 |
conf_str = format_conf_percent(top_candidate["predicted_confidence"], digits=1)
|
| 231 |
st.write(f"**{label} with {conf_str} confidence**")
|
|
|
|
| 239 |
|
| 240 |
# ANALYZE PAGE
|
| 241 |
elif page == "Analyze":
|
| 242 |
+
st.header("Peptide Analyzer")
|
| 243 |
|
| 244 |
# show the last saved analyze output if user navigated back
|
| 245 |
last_seq = st.session_state.analyze_input
|
|
|
|
| 491 |
|
| 492 |
# OPTIMIZE PAGE
|
| 493 |
elif page == "Optimize":
|
| 494 |
+
st.header("Peptide Optimizer")
|
| 495 |
|
| 496 |
+
# Form: Enter in the text field submits the form (same as clicking Run Optimization).
|
| 497 |
+
with st.form("optimize_form", clear_on_submit=False):
|
| 498 |
+
seq = st.text_input(
|
| 499 |
+
"Enter a peptide sequence to optimize:",
|
| 500 |
+
value=st.session_state.get("optimize_input", ""),
|
| 501 |
+
)
|
| 502 |
+
submitted = st.form_submit_button("Run Optimization")
|
| 503 |
|
| 504 |
+
warn_opt = sequence_length_warning(seq) if seq else None
|
| 505 |
if warn_opt:
|
| 506 |
st.caption(f"Warning: {warn_opt}")
|
| 507 |
|
| 508 |
+
if submitted and seq and str(seq).strip():
|
| 509 |
+
seq = str(seq).strip()
|
| 510 |
st.session_state.optimize_input = seq
|
| 511 |
progress = st.progress(0.0, text="Optimizing...")
|
| 512 |
with st.spinner("Optimizing sequence..."):
|
| 513 |
improved_seq, improved_conf, history = optimize_sequence(seq, model)
|
| 514 |
+
_ol, orig_conf = predict_amp(seq, model)
|
| 515 |
st.session_state.optimize_output = (seq, orig_conf, improved_seq, improved_conf, history)
|
| 516 |
progress.progress(1.0, text="Optimization complete")
|
| 517 |
st.success("Optimization finished.")
|
|
|
|
| 569 |
|
| 570 |
# VISUALIZE PEPTIDE PAGE
|
| 571 |
elif page == "Visualize Peptide":
|
| 572 |
+
st.header("Peptide Visualizer")
|
| 573 |
# Tighter legend expanders (summary row + scrollable body)
|
| 574 |
st.markdown(
|
| 575 |
"""
|
|
|
|
| 587 |
""",
|
| 588 |
unsafe_allow_html=True,
|
| 589 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 590 |
|
| 591 |
st.checkbox("Auto-run when sequence changes", value=False, key="viz_peptide_auto_run")
|
| 592 |
|
| 593 |
st.text_input(
|
| 594 |
+
"Enter a peptide sequence to visualize:",
|
| 595 |
key="visualize_peptide_input",
|
| 596 |
placeholder="Paste or type a one-letter amino-acid sequence",
|
| 597 |
)
|
|
|
|
| 600 |
clean_viz = "".join(c for c in seq_viz.upper() if not c.isspace())
|
| 601 |
if not clean_viz:
|
| 602 |
st.session_state.viz_peptide_last_computed = ""
|
|
|
|
| 603 |
else:
|
| 604 |
run_viz = st.button("Run visualization", type="primary", key="viz_peptide_run_btn")
|
| 605 |
auto_on = bool(st.session_state.get("viz_peptide_auto_run"))
|
|
|
|
| 660 |
|
| 661 |
# VISUALIZE t-SNE PAGE
|
| 662 |
elif page == "Visualize t-SNE":
|
| 663 |
+
st.header("t-SNE Visualizer")
|
| 664 |
st.write("Upload peptide sequences (FASTA or plain list) to embed sequences and explore clusters with t-SNE.")
|
| 665 |
|
| 666 |
uploaded_file = st.file_uploader("Upload FASTA or text file", type=["txt", "fasta"])
|