Update app.py
Browse files
app.py
CHANGED
|
@@ -11,7 +11,7 @@ from datetime import datetime
|
|
| 11 |
from pathlib import Path
|
| 12 |
import plotly.graph_objects as go
|
| 13 |
import plotly.express as px
|
| 14 |
-
import tabulate
|
| 15 |
|
| 16 |
# ========== Діагностичний друк ==========
|
| 17 |
print("Gradio version:", gr.__version__)
|
|
@@ -43,22 +43,27 @@ def log_entry(tab, inputs, result, note=""):
|
|
| 43 |
except Exception as e:
|
| 44 |
print(f"Log error: {e}")
|
| 45 |
|
| 46 |
-
def load_journal():
|
|
|
|
| 47 |
try:
|
| 48 |
if not LOG_PATH.exists() or LOG_PATH.stat().st_size == 0:
|
| 49 |
return "No entries yet."
|
| 50 |
df = pd.read_csv(LOG_PATH)
|
| 51 |
if df.empty:
|
| 52 |
return "No entries yet."
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
except Exception as e:
|
| 55 |
print(f"Journal load error: {e}")
|
| 56 |
return "Error loading journal."
|
| 57 |
|
| 58 |
-
def save_note(note,
|
| 59 |
if note.strip():
|
| 60 |
-
log_entry(
|
| 61 |
-
return
|
| 62 |
|
| 63 |
def clear_journal():
|
| 64 |
try:
|
|
@@ -169,6 +174,17 @@ PROTEINS = ["albumin","apolipoprotein","fibrinogen","vitronectin",
|
|
| 169 |
"clusterin","igm","iga","igg","complement","transferrin",
|
| 170 |
"alpha-2-macroglobulin"]
|
| 171 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 172 |
# ---------- S1-F RARE ----------
|
| 173 |
DIPG_VARIANTS = [
|
| 174 |
{"Variant":"H3K27M (H3F3A)","Freq_pct":78,"Pathway":"PRC2 inhibition → global H3K27me3 loss","Drug_status":"ONC201 (clinical)","Circadian_gene":"BMAL1 suppressed"},
|
|
@@ -229,20 +245,20 @@ def safe_img_from_fig(fig):
|
|
| 229 |
|
| 230 |
def predict_mirna(gene):
|
| 231 |
df = pd.DataFrame(MIRNA_DB.get(gene, []))
|
| 232 |
-
log_entry("S1-B
|
| 233 |
return df
|
| 234 |
|
| 235 |
def predict_sirna(cancer):
|
| 236 |
df = pd.DataFrame(SIRNA_DB.get(cancer, []))
|
| 237 |
-
log_entry("S1-B
|
| 238 |
return df
|
| 239 |
|
| 240 |
def get_lncrna():
|
| 241 |
-
log_entry("S1-B
|
| 242 |
return pd.DataFrame(CERNA)
|
| 243 |
|
| 244 |
def get_aso():
|
| 245 |
-
log_entry("S1-B
|
| 246 |
return pd.DataFrame(ASO)
|
| 247 |
|
| 248 |
def predict_drug(pocket):
|
|
@@ -259,10 +275,10 @@ def predict_drug(pocket):
|
|
| 259 |
ax.set_title(f"Top compounds — {pocket}", color=TXT, fontsize=10)
|
| 260 |
plt.tight_layout()
|
| 261 |
img = safe_img_from_fig(fig)
|
| 262 |
-
log_entry("S1-C
|
| 263 |
return df, img
|
| 264 |
except Exception as e:
|
| 265 |
-
log_entry("S1-C
|
| 266 |
return pd.DataFrame(), None
|
| 267 |
|
| 268 |
def predict_variant(hgvs, sift, polyphen, gnomad):
|
|
@@ -279,10 +295,10 @@ def predict_variant(hgvs, sift, polyphen, gnomad):
|
|
| 279 |
conf = "High" if (sift < 0.01 or sift > 0.9) else "Moderate"
|
| 280 |
colour = RED if "Pathogenic" in cls else GRN
|
| 281 |
icon = "⚠️ WARNING" if "Pathogenic" in cls else "✅ OK"
|
| 282 |
-
log_entry("S1-A
|
| 283 |
return (
|
| 284 |
f"<div style=\'background:{CARD};padding:16px;border-radius:8px;font-family:sans-serif;color:{TXT}\'>"
|
| 285 |
-
f"<p style=\'font-size:11px;color:{DIM};margin:0 0 8px\'>S1-A
|
| 286 |
f"<h3 style=\'color:{colour};margin:0 0 8px\'>{icon} {cls}</h3>"
|
| 287 |
f"<p>Score: <b>{score:.3f}</b> | Confidence: <b>{conf}</b></p>"
|
| 288 |
f"<div style=\'background:{BORDER};border-radius:4px;height:14px\'>"
|
|
@@ -301,7 +317,7 @@ def predict_corona(size, zeta, peg, lipid):
|
|
| 301 |
if size < 100: score += 1
|
| 302 |
dominant = ["ApoE","Albumin","Fibrinogen","Vitronectin","ApoA-I"][min(score, 4)]
|
| 303 |
efficacy = "High" if score >= 4 else "Medium" if score >= 2 else "Low"
|
| 304 |
-
log_entry("S1-D
|
| 305 |
return f"**Dominant corona protein:** {dominant}\n\n**Predicted efficacy:** {efficacy}\n\n**Score:** {score}/6"
|
| 306 |
except Exception as e:
|
| 307 |
return f"Error: {str(e)}"
|
|
@@ -325,10 +341,10 @@ def predict_cancer(c1,c2,c3,c4,c5,c6,c7,c8,c9,c10):
|
|
| 325 |
ax.set_title("Protein contributions", color=TXT, fontsize=10)
|
| 326 |
plt.tight_layout()
|
| 327 |
img = safe_img_from_fig(fig)
|
| 328 |
-
log_entry("S1-E
|
| 329 |
html_out = (
|
| 330 |
f"<div style=\'background:{CARD};padding:14px;border-radius:8px;font-family:sans-serif;\'>"
|
| 331 |
-
f"<p style=\'font-size:11px;color:{DIM};margin:0 0 6px\'>S1-E
|
| 332 |
f"<span style=\'color:{colour};font-size:24px;font-weight:bold\'>{label}</span><br>"
|
| 333 |
f"<span style=\'color:{TXT};font-size:14px\'>Probability: {prob:.2f}</span></div>"
|
| 334 |
)
|
|
@@ -354,7 +370,7 @@ def predict_flow(size, zeta, peg, charge, flow_rate):
|
|
| 354 |
ax.set_title("Vroman Effect — flow vs static", color=TXT, fontsize=9)
|
| 355 |
plt.tight_layout()
|
| 356 |
img = safe_img_from_fig(fig)
|
| 357 |
-
log_entry("S1-D
|
| 358 |
return f"**Corona Shift Index: {csi}** — {stability}", img
|
| 359 |
except Exception as e:
|
| 360 |
return f"Error: {str(e)}", None
|
|
@@ -376,7 +392,7 @@ def predict_bbb(smiles, pka, zeta):
|
|
| 376 |
ax.tick_params(colors=TXT)
|
| 377 |
plt.tight_layout()
|
| 378 |
img = safe_img_from_fig(fig)
|
| 379 |
-
log_entry("S1-D
|
| 380 |
return f"**Predicted ApoE:** {apoe_pct:.1f}% — {tier}\n\n**BBB Probability:** {bbb_prob:.2f}", img
|
| 381 |
except Exception as e:
|
| 382 |
return f"Error: {str(e)}", None
|
|
@@ -402,7 +418,7 @@ def extract_corona(text):
|
|
| 402 |
if not out["zeta_mv"]: flags.append("zeta_mv not found")
|
| 403 |
if not out["corona_proteins"]: flags.append("no proteins detected")
|
| 404 |
summary = "All key fields extracted" if not flags else " | ".join(flags)
|
| 405 |
-
log_entry("S1-D
|
| 406 |
return json.dumps(out, indent=2), summary
|
| 407 |
except Exception as e:
|
| 408 |
return json.dumps({"error": str(e)}), "Extraction error"
|
|
@@ -410,7 +426,7 @@ def extract_corona(text):
|
|
| 410 |
def dipg_variants(sort_by):
|
| 411 |
df = pd.DataFrame(DIPG_VARIANTS).sort_values(
|
| 412 |
"Freq_pct" if sort_by == "Frequency" else "Drug_status", ascending=False)
|
| 413 |
-
log_entry("S1-F
|
| 414 |
return df
|
| 415 |
|
| 416 |
def dipg_csf(peg, size):
|
|
@@ -428,14 +444,14 @@ def dipg_csf(peg, size):
|
|
| 428 |
ax.set_title("DIPG — CSF LNP formulations (ApoE%)", color=TXT, fontsize=9)
|
| 429 |
plt.tight_layout()
|
| 430 |
img = safe_img_from_fig(fig)
|
| 431 |
-
log_entry("S1-F
|
| 432 |
return df[["Formulation","Size_nm","Zeta_mV","ApoE_pct","BBB_est","Priority"]], img
|
| 433 |
except Exception as e:
|
| 434 |
return pd.DataFrame(), None
|
| 435 |
|
| 436 |
def uvm_variants():
|
| 437 |
df = pd.DataFrame(UVM_VARIANTS)
|
| 438 |
-
log_entry("S1-F
|
| 439 |
return df
|
| 440 |
|
| 441 |
def uvm_vitreous():
|
|
@@ -451,7 +467,7 @@ def uvm_vitreous():
|
|
| 451 |
ax.set_title("UVM — LNP retention in vitreous humor", color=TXT, fontsize=9)
|
| 452 |
plt.tight_layout()
|
| 453 |
img = safe_img_from_fig(fig)
|
| 454 |
-
log_entry("S1-F
|
| 455 |
return df, img
|
| 456 |
except Exception as e:
|
| 457 |
return pd.DataFrame(), None
|
|
@@ -475,7 +491,7 @@ def paml_ferroptosis(variant):
|
|
| 475 |
ax.set_title(f"pAML · {row['Variant'][:20]}", color=TXT, fontsize=9)
|
| 476 |
plt.tight_layout()
|
| 477 |
img = safe_img_from_fig(fig)
|
| 478 |
-
log_entry("S1-F
|
| 479 |
_v = row["Variant"]
|
| 480 |
_p = row["Pathway"]
|
| 481 |
_d = row["Drug_status"]
|
|
@@ -483,7 +499,7 @@ def paml_ferroptosis(variant):
|
|
| 483 |
_fs = f"{ferr_score:.2f}"
|
| 484 |
summary = (
|
| 485 |
f"<div style='background:{CARD};padding:14px;border-radius:8px;font-family:sans-serif;'>"
|
| 486 |
-
f"<p style='color:{DIM};font-size:11px;margin:0 0 6px'>S1-F
|
| 487 |
f"<b style='color:{ACC2};font-size:15px'>{_v}</b><br>"
|
| 488 |
f"<p style='color:{TXT};margin:6px 0'><b>Pathway:</b> {_p}</p>"
|
| 489 |
f"<p style='color:{TXT};margin:0'><b>Drug:</b> {_d}</p>"
|
|
@@ -597,7 +613,12 @@ def plot_corona():
|
|
| 597 |
css = f"""
|
| 598 |
body, .gradio-container {{ background: {BG} !important; color: {TXT} !important; }}
|
| 599 |
|
| 600 |
-
/* Вкладки верхнього рівня (категорії) */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 601 |
.tabs-outer .tab-nav button {{
|
| 602 |
color: {TXT} !important;
|
| 603 |
background: {CARD} !important;
|
|
@@ -605,6 +626,11 @@ body, .gradio-container {{ background: {BG} !important; color: {TXT} !important;
|
|
| 605 |
font-weight: 600 !important;
|
| 606 |
padding: 8px 16px !important;
|
| 607 |
border-radius: 6px 6px 0 0 !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 608 |
}}
|
| 609 |
.tabs-outer .tab-nav button.selected {{
|
| 610 |
border-bottom: 3px solid {ACC} !important;
|
|
@@ -676,14 +702,14 @@ body, .gradio-container {{ background: {BG} !important; color: {TXT} !important;
|
|
| 676 |
margin-left: 6px;
|
| 677 |
}}
|
| 678 |
|
| 679 |
-
/*
|
| 680 |
-
.journal {{
|
| 681 |
background: {CARD};
|
| 682 |
border: 1px solid {BORDER};
|
| 683 |
border-radius: 8px;
|
| 684 |
padding: 14px;
|
| 685 |
}}
|
| 686 |
-
.journal h3 {{
|
| 687 |
color: {ACC};
|
| 688 |
margin-top: 0;
|
| 689 |
}}
|
|
@@ -701,30 +727,30 @@ MAP_HTML = f"""
|
|
| 701 |
<span style="color:{DIM};font-size:11px;margin-left:12px">Science Sphere — sub-direction 1</span>
|
| 702 |
<br><br>
|
| 703 |
<span style="color:{ACC2};font-weight:600">S1-A · PHYLO-GENOMICS</span> — What breaks in DNA<br>
|
| 704 |
-
├─ <b>S1-A
|
| 705 |
-
└─ <b>S1-A
|
| 706 |
<span style="color:{ACC2};font-weight:600">S1-B · PHYLO-RNA</span> — How to silence it via RNA<br>
|
| 707 |
-
├─ <b>S1-B
|
| 708 |
-
├─ <b>S1-B
|
| 709 |
-
├─ <b>S1-B
|
| 710 |
-
└─ <b>S1-B
|
| 711 |
<span style="color:{ACC2};font-weight:600">S1-C · PHYLO-DRUG</span> — Which molecule treats it<br>
|
| 712 |
-
├─ <b>S1-C
|
| 713 |
-
├─ <b>S1-C
|
| 714 |
-
└─ <b>S1-C
|
| 715 |
<span style="color:{ACC2};font-weight:600">S1-D · PHYLO-LNP</span> — How to deliver the drug<br>
|
| 716 |
-
├─ <b>S1-D
|
| 717 |
-
├─ <b>S1-D
|
| 718 |
-
├─ <b>S1-D
|
| 719 |
-
├─ <b>S1-D
|
| 720 |
-
└─ <b>S1-D
|
| 721 |
<span style="color:{ACC2};font-weight:600">S1-E · PHYLO-BIOMARKERS</span> — Detect without biopsy<br>
|
| 722 |
-
├─ <b>S1-E
|
| 723 |
-
└─ <b>S1-E
|
| 724 |
<span style="color:{ACC2};font-weight:600">S1-F · PHYLO-RARE</span> — Where almost nobody has looked yet<br>
|
| 725 |
-
├─ <b>S1-F
|
| 726 |
-
├─ <b>S1-F
|
| 727 |
-
└─ <b>S1-F
|
| 728 |
<span style="color:{ACC2};font-weight:600">S1-G · PHYLO-SIM</span> — 3D Models & Simulations<br>
|
| 729 |
├─ <b>Nanoparticle</b> Interactive 3D model <span style="color:{GRN}"> ✅</span><br>
|
| 730 |
├─ <b>DNA Helix</b> Double helix visualization <span style="color:{GRN}"> ✅</span><br>
|
|
@@ -750,7 +776,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 750 |
gr.HTML(MAP_HTML)
|
| 751 |
|
| 752 |
# === S1-A · PHYLO-GENOMICS ===
|
| 753 |
-
with gr.TabItem("🧬 S1-A
|
| 754 |
gr.HTML(section_header(
|
| 755 |
"S1-A", "PHYLO-GENOMICS", "— What breaks in DNA",
|
| 756 |
"R1a OpenVariant ✅ · R1b Somatic classifier 🔶"
|
|
@@ -761,7 +787,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 761 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 762 |
# R1a · OpenVariant
|
| 763 |
with gr.TabItem("R1a · OpenVariant"):
|
| 764 |
-
gr.HTML(proj_badge("S1-A
|
| 765 |
hgvs = gr.Textbox(label="HGVS notation", placeholder="BRCA1:p.R1699Q")
|
| 766 |
gr.Markdown("**Or enter functional scores manually:**")
|
| 767 |
with gr.Row():
|
|
@@ -776,11 +802,11 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 776 |
b_v.click(predict_variant, [hgvs,sift,pp,gn], o_v)
|
| 777 |
# R1b · Somatic Classifier (в розробці)
|
| 778 |
with gr.TabItem("R1b · Somatic Classifier 🔶"):
|
| 779 |
-
gr.HTML(proj_badge("S1-A
|
| 780 |
gr.Markdown("> This module is in active development. Coming in the next release.")
|
| 781 |
|
| 782 |
# === S1-B · PHYLO-RNA ===
|
| 783 |
-
with gr.TabItem("🔬 S1-B
|
| 784 |
gr.HTML(section_header(
|
| 785 |
"S1-B", "PHYLO-RNA", "— How to silence it via RNA",
|
| 786 |
"R1a miRNA ✅ · R2a siRNA ✅ · R3a lncRNA ✅ · R3b ASO ✅"
|
|
@@ -790,7 +816,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 790 |
with gr.TabItem("R1 · miRNA silencing"):
|
| 791 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 792 |
with gr.TabItem("R1a · BRCA2 miRNA"):
|
| 793 |
-
gr.HTML(proj_badge("S1-B
|
| 794 |
g1 = gr.Dropdown(["BRCA2","BRCA1","TP53"], value="BRCA2", label="Gene")
|
| 795 |
b1 = gr.Button("Find miRNAs", variant="primary")
|
| 796 |
o1 = gr.Dataframe(label="Top 5 downregulated miRNAs")
|
|
@@ -800,7 +826,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 800 |
with gr.TabItem("R2 · siRNA SL"):
|
| 801 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 802 |
with gr.TabItem("R2a · TP53 siRNA"):
|
| 803 |
-
gr.HTML(proj_badge("S1-B
|
| 804 |
g2 = gr.Dropdown(["LUAD","BRCA","COAD"], value="LUAD", label="Cancer type")
|
| 805 |
b2 = gr.Button("Find Targets", variant="primary")
|
| 806 |
o2 = gr.Dataframe(label="Top 5 synthetic lethal targets")
|
|
@@ -810,18 +836,18 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 810 |
with gr.TabItem("R3 · lncRNA + ASO"):
|
| 811 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 812 |
with gr.TabItem("R3a · lncRNA-TREM2"):
|
| 813 |
-
gr.HTML(proj_badge("S1-B
|
| 814 |
b3a = gr.Button("Load ceRNA", variant="primary")
|
| 815 |
o3a = gr.Dataframe(label="ceRNA Network (R3a)")
|
| 816 |
b3a.click(lambda: pd.DataFrame(CERNA), [], o3a)
|
| 817 |
with gr.TabItem("R3b · ASO Designer"):
|
| 818 |
-
gr.HTML(proj_badge("S1-B
|
| 819 |
b3b = gr.Button("Load ASO Candidates", variant="primary")
|
| 820 |
o3b = gr.Dataframe(label="ASO Candidates (R3b)")
|
| 821 |
b3b.click(lambda: pd.DataFrame(ASO), [], o3b)
|
| 822 |
|
| 823 |
# === S1-C · PHYLO-DRUG ===
|
| 824 |
-
with gr.TabItem("💊 S1-C
|
| 825 |
gr.HTML(section_header(
|
| 826 |
"S1-C", "PHYLO-DRUG", "— Which molecule treats it",
|
| 827 |
"R1a FGFR3 ✅ · R1b SL drug mapping 🔶 · R2a Frontier 🔴⭐"
|
|
@@ -831,7 +857,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 831 |
with gr.TabItem("R1 · RNA-directed drug"):
|
| 832 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 833 |
with gr.TabItem("R1a · FGFR3 RNA Drug"):
|
| 834 |
-
gr.HTML(proj_badge("S1-C
|
| 835 |
g4 = gr.Radio(["P1 (hairpin loop)","P10 (G-quadruplex)"],
|
| 836 |
value="P1 (hairpin loop)", label="Target pocket")
|
| 837 |
b4_drug = gr.Button("Screen Compounds", variant="primary")
|
|
@@ -840,13 +866,13 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 840 |
gr.Examples([["P1 (hairpin loop)"],["P10 (G-quadruplex)"]], inputs=[g4])
|
| 841 |
b4_drug.click(predict_drug, [g4], [o4t, o4p])
|
| 842 |
with gr.TabItem("R1b · SL Drug Mapping 🔶"):
|
| 843 |
-
gr.HTML(proj_badge("S1-C
|
| 844 |
gr.Markdown("> In development. Coming soon.")
|
| 845 |
# R2 · Frontier
|
| 846 |
with gr.TabItem("R2 · Frontier"):
|
| 847 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 848 |
with gr.TabItem("R2a · m6A×Ferroptosis×Circadian 🔴⭐"):
|
| 849 |
-
gr.HTML(proj_badge("S1-C
|
| 850 |
gr.Markdown(
|
| 851 |
"> **Research gap:** This triple intersection has never been studied as an integrated system.\n\n"
|
| 852 |
"> **Planned datasets:** TCGA-PAAD · GEO m6A atlases · Circadian gene panels\n\n"
|
|
@@ -854,7 +880,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 854 |
)
|
| 855 |
|
| 856 |
# === S1-D · PHYLO-LNP ===
|
| 857 |
-
with gr.TabItem("🧪 S1-D
|
| 858 |
gr.HTML(section_header(
|
| 859 |
"S1-D", "PHYLO-LNP", "— How to deliver the drug",
|
| 860 |
"R1a Corona ✅ · R2a Flow ✅ · R3a Brain ✅ · R4a NLP ✅ · R5a CSF/BM 🔴⭐"
|
|
@@ -864,7 +890,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 864 |
with gr.TabItem("R1 · Serum corona"):
|
| 865 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 866 |
with gr.TabItem("R1a · LNP Corona ML"):
|
| 867 |
-
gr.HTML(proj_badge("S1-D
|
| 868 |
with gr.Row():
|
| 869 |
sz = gr.Slider(50,300,value=100,step=1,label="Size (nm)")
|
| 870 |
zt = gr.Slider(-40,10,value=-5,step=1,label="Zeta (mV)")
|
|
@@ -879,7 +905,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 879 |
with gr.TabItem("R2 · Flow corona"):
|
| 880 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 881 |
with gr.TabItem("R2a · Flow Corona"):
|
| 882 |
-
gr.HTML(proj_badge("S1-D
|
| 883 |
with gr.Row():
|
| 884 |
s8 = gr.Slider(50,300,value=100,step=1,label="Size (nm)")
|
| 885 |
z8 = gr.Slider(-40,10,value=-5,step=1,label="Zeta (mV)")
|
|
@@ -896,7 +922,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 896 |
with gr.TabItem("R3 · Brain BBB"):
|
| 897 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 898 |
with gr.TabItem("R3a · LNP Brain"):
|
| 899 |
-
gr.HTML(proj_badge("S1-D
|
| 900 |
smi = gr.Textbox(label="Ionizable lipid SMILES",
|
| 901 |
value="CC(C)CC(=O)OCC(COC(=O)CC(C)C)OC(=O)CC(C)C")
|
| 902 |
with gr.Row():
|
|
@@ -911,7 +937,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 911 |
with gr.TabItem("R4 · NLP"):
|
| 912 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 913 |
with gr.TabItem("R4a · AutoCorona NLP"):
|
| 914 |
-
gr.HTML(proj_badge("S1-D
|
| 915 |
txt = gr.Textbox(lines=5,label="Paper abstract",placeholder="Paste abstract here...")
|
| 916 |
b10 = gr.Button("Extract Data", variant="primary")
|
| 917 |
o10j = gr.Code(label="Extracted JSON", language="json")
|
|
@@ -926,7 +952,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 926 |
with gr.TabItem("R5 · Exotic fluids 🔴⭐"):
|
| 927 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 928 |
with gr.TabItem("R5a · CSF/Vitreous/BM"):
|
| 929 |
-
gr.HTML(proj_badge("S1-D
|
| 930 |
gr.Markdown(
|
| 931 |
"> **Research gap:** Protein corona has only been characterized in serum/plasma. "
|
| 932 |
"CSF, vitreous humor, and bone marrow interstitial fluid remain completely unstudied.\n\n"
|
|
@@ -935,7 +961,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 935 |
)
|
| 936 |
|
| 937 |
# === S1-E · PHYLO-BIOMARKERS ===
|
| 938 |
-
with gr.TabItem("🩸 S1-E
|
| 939 |
gr.HTML(section_header(
|
| 940 |
"S1-E", "PHYLO-BIOMARKERS", "— Detect without biopsy",
|
| 941 |
"R1a Liquid Biopsy ✅ · R1b Protein validator 🔶"
|
|
@@ -944,7 +970,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 944 |
with gr.TabItem("R1 · Liquid biopsy"):
|
| 945 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 946 |
with gr.TabItem("R1a · Liquid Biopsy"):
|
| 947 |
-
gr.HTML(proj_badge("S1-E
|
| 948 |
with gr.Row():
|
| 949 |
p1=gr.Slider(-3,3,value=0,step=0.1,label="CTHRC1")
|
| 950 |
p2=gr.Slider(-3,3,value=0,step=0.1,label="FHL2")
|
|
@@ -964,11 +990,11 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 964 |
inputs=[p1,p2,p3,p4,p5,p6,p7,p8,p9,p10])
|
| 965 |
b7.click(predict_cancer, [p1,p2,p3,p4,p5,p6,p7,p8,p9,p10], [o7t,o7p])
|
| 966 |
with gr.TabItem("R1b · Protein Validator 🔶"):
|
| 967 |
-
gr.HTML(proj_badge("S1-E
|
| 968 |
gr.Markdown("> Coming next — validates R1a results against GEO plasma proteomics datasets.")
|
| 969 |
|
| 970 |
# === S1-F · PHYLO-RARE ===
|
| 971 |
-
with gr.TabItem("🧠 S1-F
|
| 972 |
gr.HTML(section_header(
|
| 973 |
"S1-F", "PHYLO-RARE", "— Where almost nobody has looked yet",
|
| 974 |
"<b style='color:#ef4444'>⚠️ <300 cases/yr · <5% survival · 0–1 prior studies per gap</b><br>"
|
|
@@ -979,7 +1005,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 979 |
with gr.TabItem("R1 · DIPG"):
|
| 980 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 981 |
with gr.TabItem("R1a · DIPG Toolkit"):
|
| 982 |
-
gr.HTML(proj_badge("S1-F
|
| 983 |
gr.Markdown(
|
| 984 |
"> **Why DIPG?** Diffuse Intrinsic Pontine Glioma — median survival 9–11 months. "
|
| 985 |
"H3K27M oncohistone in **78%** cases. "
|
|
@@ -1013,7 +1039,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 1013 |
with gr.TabItem("R2 · UVM"):
|
| 1014 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 1015 |
with gr.TabItem("R2a · UVM Toolkit"):
|
| 1016 |
-
gr.HTML(proj_badge("S1-F
|
| 1017 |
gr.Markdown(
|
| 1018 |
"> **Why UVM?** Uveal Melanoma — metastatic 5-yr survival **15%**. "
|
| 1019 |
"GNAQ/GNA11 mutations in 78% cases. "
|
|
@@ -1043,7 +1069,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 1043 |
with gr.TabItem("R3 · pAML"):
|
| 1044 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 1045 |
with gr.TabItem("R3a · pAML Toolkit"):
|
| 1046 |
-
gr.HTML(proj_badge("S1-F
|
| 1047 |
gr.Markdown(
|
| 1048 |
"> **Why pAML?** Pediatric AML — relapse OS **<30%**. "
|
| 1049 |
"FLT3-ITD in 25% cases. "
|
|
@@ -1077,7 +1103,7 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 1077 |
)
|
| 1078 |
|
| 1079 |
# === S1-G · 3D Lab ===
|
| 1080 |
-
with gr.TabItem("🧊 S1-G
|
| 1081 |
gr.HTML(section_header(
|
| 1082 |
"S1-G", "PHYLO-SIM", "— 3D Models & Simulations",
|
| 1083 |
"Interactive visualizations for learning"
|
|
@@ -1110,29 +1136,53 @@ with gr.Blocks(css=css, title="K R&D Lab · S1 Biomedical") as demo:
|
|
| 1110 |
## 🧪 Guided Investigations
|
| 1111 |
> 🟢 Beginner → 🟡 Intermediate → 🔴 Advanced
|
| 1112 |
|
| 1113 |
-
**S1-A
|
| 1114 |
-
**S1-D
|
| 1115 |
-
**S1-D
|
| 1116 |
-
**S1-B
|
| 1117 |
-
**S1-E
|
| 1118 |
-
**S1-G
|
| 1119 |
""")
|
| 1120 |
|
| 1121 |
-
|
| 1122 |
-
|
| 1123 |
-
|
| 1124 |
-
|
| 1125 |
-
|
| 1126 |
-
|
| 1127 |
-
|
| 1128 |
-
|
| 1129 |
-
|
| 1130 |
-
|
| 1131 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1132 |
|
| 1133 |
-
save_btn.click(
|
| 1134 |
-
refresh_btn.click(load_journal, [], journal_display)
|
| 1135 |
-
clear_btn.click(clear_journal, [], journal_display)
|
| 1136 |
|
| 1137 |
gr.Markdown(
|
| 1138 |
"---\n**K R&D Lab** · MIT License · "
|
|
|
|
| 11 |
from pathlib import Path
|
| 12 |
import plotly.graph_objects as go
|
| 13 |
import plotly.express as px
|
| 14 |
+
import tabulate
|
| 15 |
|
| 16 |
# ========== Діагностичний друк ==========
|
| 17 |
print("Gradio version:", gr.__version__)
|
|
|
|
| 43 |
except Exception as e:
|
| 44 |
print(f"Log error: {e}")
|
| 45 |
|
| 46 |
+
def load_journal(category=None):
|
| 47 |
+
"""Load journal entries, optionally filtered by category. Returns markdown string."""
|
| 48 |
try:
|
| 49 |
if not LOG_PATH.exists() or LOG_PATH.stat().st_size == 0:
|
| 50 |
return "No entries yet."
|
| 51 |
df = pd.read_csv(LOG_PATH)
|
| 52 |
if df.empty:
|
| 53 |
return "No entries yet."
|
| 54 |
+
if category and category != "All":
|
| 55 |
+
df = df[df["tab"] == category]
|
| 56 |
+
if df.empty:
|
| 57 |
+
return "No entries for this category."
|
| 58 |
+
return df.tail(50).to_markdown(index=False)
|
| 59 |
except Exception as e:
|
| 60 |
print(f"Journal load error: {e}")
|
| 61 |
return "Error loading journal."
|
| 62 |
|
| 63 |
+
def save_note(note, category):
|
| 64 |
if note.strip():
|
| 65 |
+
log_entry(category, "manual note", note, note)
|
| 66 |
+
return "Note saved."
|
| 67 |
|
| 68 |
def clear_journal():
|
| 69 |
try:
|
|
|
|
| 174 |
"clusterin","igm","iga","igg","complement","transferrin",
|
| 175 |
"alpha-2-macroglobulin"]
|
| 176 |
|
| 177 |
+
# ========== Список кодів проєктів для випадаючих списків ==========
|
| 178 |
+
PROJECT_CODES = [
|
| 179 |
+
"S1-A·R1a", "S1-A·R1b",
|
| 180 |
+
"S1-B·R1a", "S1-B·R2a", "S1-B·R3a", "S1-B·R3b",
|
| 181 |
+
"S1-C·R1a", "S1-C·R1b", "S1-C·R2a",
|
| 182 |
+
"S1-D·R1a", "S1-D·R2a", "S1-D·R3a", "S1-D·R4a", "S1-D·R5a",
|
| 183 |
+
"S1-E·R1a", "S1-E·R1b",
|
| 184 |
+
"S1-F·R1a", "S1-F·R2a", "S1-F·R3a",
|
| 185 |
+
"S1-G·General"
|
| 186 |
+
]
|
| 187 |
+
|
| 188 |
# ---------- S1-F RARE ----------
|
| 189 |
DIPG_VARIANTS = [
|
| 190 |
{"Variant":"H3K27M (H3F3A)","Freq_pct":78,"Pathway":"PRC2 inhibition → global H3K27me3 loss","Drug_status":"ONC201 (clinical)","Circadian_gene":"BMAL1 suppressed"},
|
|
|
|
| 245 |
|
| 246 |
def predict_mirna(gene):
|
| 247 |
df = pd.DataFrame(MIRNA_DB.get(gene, []))
|
| 248 |
+
log_entry("S1-B·R1a", gene, f"{len(df)} miRNAs")
|
| 249 |
return df
|
| 250 |
|
| 251 |
def predict_sirna(cancer):
|
| 252 |
df = pd.DataFrame(SIRNA_DB.get(cancer, []))
|
| 253 |
+
log_entry("S1-B·R2a", cancer, f"{len(df)} targets")
|
| 254 |
return df
|
| 255 |
|
| 256 |
def get_lncrna():
|
| 257 |
+
log_entry("S1-B·R3a", "load", "ceRNA")
|
| 258 |
return pd.DataFrame(CERNA)
|
| 259 |
|
| 260 |
def get_aso():
|
| 261 |
+
log_entry("S1-B·R3b", "load", "ASO")
|
| 262 |
return pd.DataFrame(ASO)
|
| 263 |
|
| 264 |
def predict_drug(pocket):
|
|
|
|
| 275 |
ax.set_title(f"Top compounds — {pocket}", color=TXT, fontsize=10)
|
| 276 |
plt.tight_layout()
|
| 277 |
img = safe_img_from_fig(fig)
|
| 278 |
+
log_entry("S1-C·R1a", pocket, f"Top: {df.iloc[0]['Compound'] if len(df) else 'none'}")
|
| 279 |
return df, img
|
| 280 |
except Exception as e:
|
| 281 |
+
log_entry("S1-C·R1a", pocket, f"Error: {str(e)}")
|
| 282 |
return pd.DataFrame(), None
|
| 283 |
|
| 284 |
def predict_variant(hgvs, sift, polyphen, gnomad):
|
|
|
|
| 295 |
conf = "High" if (sift < 0.01 or sift > 0.9) else "Moderate"
|
| 296 |
colour = RED if "Pathogenic" in cls else GRN
|
| 297 |
icon = "⚠️ WARNING" if "Pathogenic" in cls else "✅ OK"
|
| 298 |
+
log_entry("S1-A·R1a", hgvs or f"SIFT={sift}", f"{cls} score={score}")
|
| 299 |
return (
|
| 300 |
f"<div style=\'background:{CARD};padding:16px;border-radius:8px;font-family:sans-serif;color:{TXT}\'>"
|
| 301 |
+
f"<p style=\'font-size:11px;color:{DIM};margin:0 0 8px\'>S1-A·R1a · OpenVariant</p>"
|
| 302 |
f"<h3 style=\'color:{colour};margin:0 0 8px\'>{icon} {cls}</h3>"
|
| 303 |
f"<p>Score: <b>{score:.3f}</b> | Confidence: <b>{conf}</b></p>"
|
| 304 |
f"<div style=\'background:{BORDER};border-radius:4px;height:14px\'>"
|
|
|
|
| 317 |
if size < 100: score += 1
|
| 318 |
dominant = ["ApoE","Albumin","Fibrinogen","Vitronectin","ApoA-I"][min(score, 4)]
|
| 319 |
efficacy = "High" if score >= 4 else "Medium" if score >= 2 else "Low"
|
| 320 |
+
log_entry("S1-D·R1a", f"size={size},peg={peg}", f"dominant={dominant}")
|
| 321 |
return f"**Dominant corona protein:** {dominant}\n\n**Predicted efficacy:** {efficacy}\n\n**Score:** {score}/6"
|
| 322 |
except Exception as e:
|
| 323 |
return f"Error: {str(e)}"
|
|
|
|
| 341 |
ax.set_title("Protein contributions", color=TXT, fontsize=10)
|
| 342 |
plt.tight_layout()
|
| 343 |
img = safe_img_from_fig(fig)
|
| 344 |
+
log_entry("S1-E·R1a", f"CTHRC1={c1},FHL2={c2}", f"{label} {prob:.2f}")
|
| 345 |
html_out = (
|
| 346 |
f"<div style=\'background:{CARD};padding:14px;border-radius:8px;font-family:sans-serif;\'>"
|
| 347 |
+
f"<p style=\'font-size:11px;color:{DIM};margin:0 0 6px\'>S1-E·R1a · Liquid Biopsy</p>"
|
| 348 |
f"<span style=\'color:{colour};font-size:24px;font-weight:bold\'>{label}</span><br>"
|
| 349 |
f"<span style=\'color:{TXT};font-size:14px\'>Probability: {prob:.2f}</span></div>"
|
| 350 |
)
|
|
|
|
| 370 |
ax.set_title("Vroman Effect — flow vs static", color=TXT, fontsize=9)
|
| 371 |
plt.tight_layout()
|
| 372 |
img = safe_img_from_fig(fig)
|
| 373 |
+
log_entry("S1-D·R2a", f"flow={flow_rate}", f"CSI={csi}")
|
| 374 |
return f"**Corona Shift Index: {csi}** — {stability}", img
|
| 375 |
except Exception as e:
|
| 376 |
return f"Error: {str(e)}", None
|
|
|
|
| 392 |
ax.tick_params(colors=TXT)
|
| 393 |
plt.tight_layout()
|
| 394 |
img = safe_img_from_fig(fig)
|
| 395 |
+
log_entry("S1-D·R3a", f"pka={pka},zeta={zeta}", f"ApoE={apoe_pct:.1f}%")
|
| 396 |
return f"**Predicted ApoE:** {apoe_pct:.1f}% — {tier}\n\n**BBB Probability:** {bbb_prob:.2f}", img
|
| 397 |
except Exception as e:
|
| 398 |
return f"Error: {str(e)}", None
|
|
|
|
| 418 |
if not out["zeta_mv"]: flags.append("zeta_mv not found")
|
| 419 |
if not out["corona_proteins"]: flags.append("no proteins detected")
|
| 420 |
summary = "All key fields extracted" if not flags else " | ".join(flags)
|
| 421 |
+
log_entry("S1-D·R4a", text[:80], f"proteins={len(out['corona_proteins'])}")
|
| 422 |
return json.dumps(out, indent=2), summary
|
| 423 |
except Exception as e:
|
| 424 |
return json.dumps({"error": str(e)}), "Extraction error"
|
|
|
|
| 426 |
def dipg_variants(sort_by):
|
| 427 |
df = pd.DataFrame(DIPG_VARIANTS).sort_values(
|
| 428 |
"Freq_pct" if sort_by == "Frequency" else "Drug_status", ascending=False)
|
| 429 |
+
log_entry("S1-F·R1a", sort_by, f"{len(df)} variants")
|
| 430 |
return df
|
| 431 |
|
| 432 |
def dipg_csf(peg, size):
|
|
|
|
| 444 |
ax.set_title("DIPG — CSF LNP formulations (ApoE%)", color=TXT, fontsize=9)
|
| 445 |
plt.tight_layout()
|
| 446 |
img = safe_img_from_fig(fig)
|
| 447 |
+
log_entry("S1-F·R1a", f"peg={peg},size={size}", "formulation ranking")
|
| 448 |
return df[["Formulation","Size_nm","Zeta_mV","ApoE_pct","BBB_est","Priority"]], img
|
| 449 |
except Exception as e:
|
| 450 |
return pd.DataFrame(), None
|
| 451 |
|
| 452 |
def uvm_variants():
|
| 453 |
df = pd.DataFrame(UVM_VARIANTS)
|
| 454 |
+
log_entry("S1-F·R2a", "load", f"{len(df)} variants")
|
| 455 |
return df
|
| 456 |
|
| 457 |
def uvm_vitreous():
|
|
|
|
| 467 |
ax.set_title("UVM — LNP retention in vitreous humor", color=TXT, fontsize=9)
|
| 468 |
plt.tight_layout()
|
| 469 |
img = safe_img_from_fig(fig)
|
| 470 |
+
log_entry("S1-F·R2a", "load", "vitreous LNP ranking")
|
| 471 |
return df, img
|
| 472 |
except Exception as e:
|
| 473 |
return pd.DataFrame(), None
|
|
|
|
| 491 |
ax.set_title(f"pAML · {row['Variant'][:20]}", color=TXT, fontsize=9)
|
| 492 |
plt.tight_layout()
|
| 493 |
img = safe_img_from_fig(fig)
|
| 494 |
+
log_entry("S1-F·R3a", variant, f"ferr={ferr_score:.2f}")
|
| 495 |
_v = row["Variant"]
|
| 496 |
_p = row["Pathway"]
|
| 497 |
_d = row["Drug_status"]
|
|
|
|
| 499 |
_fs = f"{ferr_score:.2f}"
|
| 500 |
summary = (
|
| 501 |
f"<div style='background:{CARD};padding:14px;border-radius:8px;font-family:sans-serif;'>"
|
| 502 |
+
f"<p style='color:{DIM};font-size:11px;margin:0 0 6px'>S1-F·R3a · pAML</p>"
|
| 503 |
f"<b style='color:{ACC2};font-size:15px'>{_v}</b><br>"
|
| 504 |
f"<p style='color:{TXT};margin:6px 0'><b>Pathway:</b> {_p}</p>"
|
| 505 |
f"<p style='color:{TXT};margin:0'><b>Drug:</b> {_d}</p>"
|
|
|
|
| 613 |
css = f"""
|
| 614 |
body, .gradio-container {{ background: {BG} !important; color: {TXT} !important; }}
|
| 615 |
|
| 616 |
+
/* Вкладки верхнього рівня (категорії) з переносом на новий ряд */
|
| 617 |
+
.tabs-outer .tab-nav {{
|
| 618 |
+
display: flex;
|
| 619 |
+
flex-wrap: wrap;
|
| 620 |
+
gap: 2px;
|
| 621 |
+
}}
|
| 622 |
.tabs-outer .tab-nav button {{
|
| 623 |
color: {TXT} !important;
|
| 624 |
background: {CARD} !important;
|
|
|
|
| 626 |
font-weight: 600 !important;
|
| 627 |
padding: 8px 16px !important;
|
| 628 |
border-radius: 6px 6px 0 0 !important;
|
| 629 |
+
border: 1px solid {BORDER};
|
| 630 |
+
border-bottom: none;
|
| 631 |
+
margin-right: 2px;
|
| 632 |
+
margin-bottom: 2px;
|
| 633 |
+
white-space: nowrap;
|
| 634 |
}}
|
| 635 |
.tabs-outer .tab-nav button.selected {{
|
| 636 |
border-bottom: 3px solid {ACC} !important;
|
|
|
|
| 702 |
margin-left: 6px;
|
| 703 |
}}
|
| 704 |
|
| 705 |
+
/* Бічна панель з журналом (тільки введення) */
|
| 706 |
+
.sidebar-journal {{
|
| 707 |
background: {CARD};
|
| 708 |
border: 1px solid {BORDER};
|
| 709 |
border-radius: 8px;
|
| 710 |
padding: 14px;
|
| 711 |
}}
|
| 712 |
+
.sidebar-journal h3 {{
|
| 713 |
color: {ACC};
|
| 714 |
margin-top: 0;
|
| 715 |
}}
|
|
|
|
| 727 |
<span style="color:{DIM};font-size:11px;margin-left:12px">Science Sphere — sub-direction 1</span>
|
| 728 |
<br><br>
|
| 729 |
<span style="color:{ACC2};font-weight:600">S1-A · PHYLO-GENOMICS</span> — What breaks in DNA<br>
|
| 730 |
+
├─ <b>S1-A·R1a</b> OpenVariant <span style="color:{GRN}"> AUC=0.939 ✅</span><br>
|
| 731 |
+
└─ <b>S1-A·R1b</b> Somatic classifier <span style="color:#f59e0b"> 🔶 In progress</span><br><br>
|
| 732 |
<span style="color:{ACC2};font-weight:600">S1-B · PHYLO-RNA</span> — How to silence it via RNA<br>
|
| 733 |
+
├─ <b>S1-B·R1a</b> miRNA silencing <span style="color:{GRN}"> ✅</span><br>
|
| 734 |
+
├─ <b>S1-B·R2a</b> siRNA synthetic lethal <span style="color:{GRN}"> ✅</span><br>
|
| 735 |
+
├─ <b>S1-B·R3a</b> lncRNA-TREM2 ceRNA <span style="color:{GRN}"> ✅</span><br>
|
| 736 |
+
└─ <b>S1-B·R3b</b> ASO designer <span style="color:{GRN}"> ✅</span><br><br>
|
| 737 |
<span style="color:{ACC2};font-weight:600">S1-C · PHYLO-DRUG</span> — Which molecule treats it<br>
|
| 738 |
+
├─ <b>S1-C·R1a</b> FGFR3 RNA-directed compounds <span style="color:{GRN}"> ✅</span><br>
|
| 739 |
+
├─ <b>S1-C·R1b</b> Synthetic lethal drug mapping <span style="color:#f59e0b"> 🔶</span><br>
|
| 740 |
+
└─ <b>S1-C·R2a</b> m6A × Ferroptosis × Circadian <span style="color:{DIM}"> 🔴 Frontier</span><br><br>
|
| 741 |
<span style="color:{ACC2};font-weight:600">S1-D · PHYLO-LNP</span> — How to deliver the drug<br>
|
| 742 |
+
├─ <b>S1-D·R1a</b> LNP corona (serum) <span style="color:{GRN}"> AUC=0.791 ✅</span><br>
|
| 743 |
+
├─ <b>S1-D·R2a</b> Flow corona — Vroman effect <span style="color:{GRN}"> ✅</span><br>
|
| 744 |
+
├─ <b>S1-D·R3a</b> LNP brain / BBB / ApoE <span style="color:{GRN}"> ✅</span><br>
|
| 745 |
+
├─ <b>S1-D·R4a</b> AutoCorona NLP <span style="color:{GRN}"> F1=0.71 ✅</span><br>
|
| 746 |
+
└─ <b>S1-D·R5a</b> CSF · Vitreous · Bone Marrow <span style="color:{DIM}"> 🔴 0 prior studies</span><br><br>
|
| 747 |
<span style="color:{ACC2};font-weight:600">S1-E · PHYLO-BIOMARKERS</span> — Detect without biopsy<br>
|
| 748 |
+
├─ <b>S1-E·R1a</b> Liquid Biopsy classifier <span style="color:{GRN}"> AUC=0.992* ✅</span><br>
|
| 749 |
+
└─ <b>S1-E·R1b</b> Protein panel validator <span style="color:#f59e0b"> 🔶</span><br><br>
|
| 750 |
<span style="color:{ACC2};font-weight:600">S1-F · PHYLO-RARE</span> — Where almost nobody has looked yet<br>
|
| 751 |
+
├─ <b>S1-F·R1a</b> DIPG toolkit (H3K27M + CSF LNP + Circadian) <span style="color:#f59e0b"> 🔶</span><br>
|
| 752 |
+
├─ <b>S1-F·R2a</b> UVM toolkit (GNAQ/GNA11 + vitreous + m6A) <span style="color:#f59e0b"> 🔶</span><br>
|
| 753 |
+
└─ <b>S1-F·R3a</b> pAML toolkit (FLT3-ITD + BM niche + ferroptosis) <span style="color:#f59e0b"> 🔶</span><br><br>
|
| 754 |
<span style="color:{ACC2};font-weight:600">S1-G · PHYLO-SIM</span> — 3D Models & Simulations<br>
|
| 755 |
├─ <b>Nanoparticle</b> Interactive 3D model <span style="color:{GRN}"> ✅</span><br>
|
| 756 |
├─ <b>DNA Helix</b> Double helix visualization <span style="color:{GRN}"> ✅</span><br>
|
|
|
|
| 776 |
gr.HTML(MAP_HTML)
|
| 777 |
|
| 778 |
# === S1-A · PHYLO-GENOMICS ===
|
| 779 |
+
with gr.TabItem("🧬 S1-A"):
|
| 780 |
gr.HTML(section_header(
|
| 781 |
"S1-A", "PHYLO-GENOMICS", "— What breaks in DNA",
|
| 782 |
"R1a OpenVariant ✅ · R1b Somatic classifier 🔶"
|
|
|
|
| 787 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 788 |
# R1a · OpenVariant
|
| 789 |
with gr.TabItem("R1a · OpenVariant"):
|
| 790 |
+
gr.HTML(proj_badge("S1-A·R1a", "OpenVariant — SNV Pathogenicity Classifier", "AUC=0.939"))
|
| 791 |
hgvs = gr.Textbox(label="HGVS notation", placeholder="BRCA1:p.R1699Q")
|
| 792 |
gr.Markdown("**Or enter functional scores manually:**")
|
| 793 |
with gr.Row():
|
|
|
|
| 802 |
b_v.click(predict_variant, [hgvs,sift,pp,gn], o_v)
|
| 803 |
# R1b · Somatic Classifier (в розробці)
|
| 804 |
with gr.TabItem("R1b · Somatic Classifier 🔶"):
|
| 805 |
+
gr.HTML(proj_badge("S1-A·R1b", "Somatic Mutation Classifier", "🔶 In progress"))
|
| 806 |
gr.Markdown("> This module is in active development. Coming in the next release.")
|
| 807 |
|
| 808 |
# === S1-B · PHYLO-RNA ===
|
| 809 |
+
with gr.TabItem("🔬 S1-B"):
|
| 810 |
gr.HTML(section_header(
|
| 811 |
"S1-B", "PHYLO-RNA", "— How to silence it via RNA",
|
| 812 |
"R1a miRNA ✅ · R2a siRNA ✅ · R3a lncRNA ✅ · R3b ASO ✅"
|
|
|
|
| 816 |
with gr.TabItem("R1 · miRNA silencing"):
|
| 817 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 818 |
with gr.TabItem("R1a · BRCA2 miRNA"):
|
| 819 |
+
gr.HTML(proj_badge("S1-B·R1a", "miRNA Silencing — BRCA1/2 · TP53"))
|
| 820 |
g1 = gr.Dropdown(["BRCA2","BRCA1","TP53"], value="BRCA2", label="Gene")
|
| 821 |
b1 = gr.Button("Find miRNAs", variant="primary")
|
| 822 |
o1 = gr.Dataframe(label="Top 5 downregulated miRNAs")
|
|
|
|
| 826 |
with gr.TabItem("R2 · siRNA SL"):
|
| 827 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 828 |
with gr.TabItem("R2a · TP53 siRNA"):
|
| 829 |
+
gr.HTML(proj_badge("S1-B·R2a", "siRNA Synthetic Lethal — TP53-null"))
|
| 830 |
g2 = gr.Dropdown(["LUAD","BRCA","COAD"], value="LUAD", label="Cancer type")
|
| 831 |
b2 = gr.Button("Find Targets", variant="primary")
|
| 832 |
o2 = gr.Dataframe(label="Top 5 synthetic lethal targets")
|
|
|
|
| 836 |
with gr.TabItem("R3 · lncRNA + ASO"):
|
| 837 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 838 |
with gr.TabItem("R3a · lncRNA-TREM2"):
|
| 839 |
+
gr.HTML(proj_badge("S1-B·R3a", "lncRNA-TREM2 ceRNA Network"))
|
| 840 |
b3a = gr.Button("Load ceRNA", variant="primary")
|
| 841 |
o3a = gr.Dataframe(label="ceRNA Network (R3a)")
|
| 842 |
b3a.click(lambda: pd.DataFrame(CERNA), [], o3a)
|
| 843 |
with gr.TabItem("R3b · ASO Designer"):
|
| 844 |
+
gr.HTML(proj_badge("S1-B·R3b", "ASO Designer"))
|
| 845 |
b3b = gr.Button("Load ASO Candidates", variant="primary")
|
| 846 |
o3b = gr.Dataframe(label="ASO Candidates (R3b)")
|
| 847 |
b3b.click(lambda: pd.DataFrame(ASO), [], o3b)
|
| 848 |
|
| 849 |
# === S1-C · PHYLO-DRUG ===
|
| 850 |
+
with gr.TabItem("💊 S1-C"):
|
| 851 |
gr.HTML(section_header(
|
| 852 |
"S1-C", "PHYLO-DRUG", "— Which molecule treats it",
|
| 853 |
"R1a FGFR3 ✅ · R1b SL drug mapping 🔶 · R2a Frontier 🔴⭐"
|
|
|
|
| 857 |
with gr.TabItem("R1 · RNA-directed drug"):
|
| 858 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 859 |
with gr.TabItem("R1a · FGFR3 RNA Drug"):
|
| 860 |
+
gr.HTML(proj_badge("S1-C·R1a", "FGFR3 RNA-Directed Drug Discovery", "top score 0.793"))
|
| 861 |
g4 = gr.Radio(["P1 (hairpin loop)","P10 (G-quadruplex)"],
|
| 862 |
value="P1 (hairpin loop)", label="Target pocket")
|
| 863 |
b4_drug = gr.Button("Screen Compounds", variant="primary")
|
|
|
|
| 866 |
gr.Examples([["P1 (hairpin loop)"],["P10 (G-quadruplex)"]], inputs=[g4])
|
| 867 |
b4_drug.click(predict_drug, [g4], [o4t, o4p])
|
| 868 |
with gr.TabItem("R1b · SL Drug Mapping 🔶"):
|
| 869 |
+
gr.HTML(proj_badge("S1-C·R1b", "Synthetic Lethal Drug Mapping", "🔶 In progress"))
|
| 870 |
gr.Markdown("> In development. Coming soon.")
|
| 871 |
# R2 · Frontier
|
| 872 |
with gr.TabItem("R2 · Frontier"):
|
| 873 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 874 |
with gr.TabItem("R2a · m6A×Ferroptosis×Circadian 🔴⭐"):
|
| 875 |
+
gr.HTML(proj_badge("S1-C·R2a", "m6A × Ferroptosis × Circadian", "🔴 Frontier"))
|
| 876 |
gr.Markdown(
|
| 877 |
"> **Research gap:** This triple intersection has never been studied as an integrated system.\n\n"
|
| 878 |
"> **Planned datasets:** TCGA-PAAD · GEO m6A atlases · Circadian gene panels\n\n"
|
|
|
|
| 880 |
)
|
| 881 |
|
| 882 |
# === S1-D · PHYLO-LNP ===
|
| 883 |
+
with gr.TabItem("🧪 S1-D"):
|
| 884 |
gr.HTML(section_header(
|
| 885 |
"S1-D", "PHYLO-LNP", "— How to deliver the drug",
|
| 886 |
"R1a Corona ✅ · R2a Flow ✅ · R3a Brain ✅ · R4a NLP ✅ · R5a CSF/BM 🔴⭐"
|
|
|
|
| 890 |
with gr.TabItem("R1 · Serum corona"):
|
| 891 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 892 |
with gr.TabItem("R1a · LNP Corona ML"):
|
| 893 |
+
gr.HTML(proj_badge("S1-D·R1a", "LNP Protein Corona (Serum)", "AUC=0.791"))
|
| 894 |
with gr.Row():
|
| 895 |
sz = gr.Slider(50,300,value=100,step=1,label="Size (nm)")
|
| 896 |
zt = gr.Slider(-40,10,value=-5,step=1,label="Zeta (mV)")
|
|
|
|
| 905 |
with gr.TabItem("R2 · Flow corona"):
|
| 906 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 907 |
with gr.TabItem("R2a · Flow Corona"):
|
| 908 |
+
gr.HTML(proj_badge("S1-D·R2a", "Flow Corona — Vroman Effect"))
|
| 909 |
with gr.Row():
|
| 910 |
s8 = gr.Slider(50,300,value=100,step=1,label="Size (nm)")
|
| 911 |
z8 = gr.Slider(-40,10,value=-5,step=1,label="Zeta (mV)")
|
|
|
|
| 922 |
with gr.TabItem("R3 · Brain BBB"):
|
| 923 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 924 |
with gr.TabItem("R3a · LNP Brain"):
|
| 925 |
+
gr.HTML(proj_badge("S1-D·R3a", "LNP Brain Delivery"))
|
| 926 |
smi = gr.Textbox(label="Ionizable lipid SMILES",
|
| 927 |
value="CC(C)CC(=O)OCC(COC(=O)CC(C)C)OC(=O)CC(C)C")
|
| 928 |
with gr.Row():
|
|
|
|
| 937 |
with gr.TabItem("R4 · NLP"):
|
| 938 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 939 |
with gr.TabItem("R4a · AutoCorona NLP"):
|
| 940 |
+
gr.HTML(proj_badge("S1-D·R4a", "AutoCorona NLP", "F1=0.71"))
|
| 941 |
txt = gr.Textbox(lines=5,label="Paper abstract",placeholder="Paste abstract here...")
|
| 942 |
b10 = gr.Button("Extract Data", variant="primary")
|
| 943 |
o10j = gr.Code(label="Extracted JSON", language="json")
|
|
|
|
| 952 |
with gr.TabItem("R5 · Exotic fluids 🔴⭐"):
|
| 953 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 954 |
with gr.TabItem("R5a · CSF/Vitreous/BM"):
|
| 955 |
+
gr.HTML(proj_badge("S1-D·R5a", "LNP Corona in CSF · Vitreous · Bone Marrow", "🔴 0 prior studies"))
|
| 956 |
gr.Markdown(
|
| 957 |
"> **Research gap:** Protein corona has only been characterized in serum/plasma. "
|
| 958 |
"CSF, vitreous humor, and bone marrow interstitial fluid remain completely unstudied.\n\n"
|
|
|
|
| 961 |
)
|
| 962 |
|
| 963 |
# === S1-E · PHYLO-BIOMARKERS ===
|
| 964 |
+
with gr.TabItem("🩸 S1-E"):
|
| 965 |
gr.HTML(section_header(
|
| 966 |
"S1-E", "PHYLO-BIOMARKERS", "— Detect without biopsy",
|
| 967 |
"R1a Liquid Biopsy ✅ · R1b Protein validator 🔶"
|
|
|
|
| 970 |
with gr.TabItem("R1 · Liquid biopsy"):
|
| 971 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 972 |
with gr.TabItem("R1a · Liquid Biopsy"):
|
| 973 |
+
gr.HTML(proj_badge("S1-E·R1a", "Liquid Biopsy Classifier", "AUC=0.992*"))
|
| 974 |
with gr.Row():
|
| 975 |
p1=gr.Slider(-3,3,value=0,step=0.1,label="CTHRC1")
|
| 976 |
p2=gr.Slider(-3,3,value=0,step=0.1,label="FHL2")
|
|
|
|
| 990 |
inputs=[p1,p2,p3,p4,p5,p6,p7,p8,p9,p10])
|
| 991 |
b7.click(predict_cancer, [p1,p2,p3,p4,p5,p6,p7,p8,p9,p10], [o7t,o7p])
|
| 992 |
with gr.TabItem("R1b · Protein Validator 🔶"):
|
| 993 |
+
gr.HTML(proj_badge("S1-E·R1b", "Protein Panel Validator", "🔶 In progress"))
|
| 994 |
gr.Markdown("> Coming next — validates R1a results against GEO plasma proteomics datasets.")
|
| 995 |
|
| 996 |
# === S1-F · PHYLO-RARE ===
|
| 997 |
+
with gr.TabItem("🧠 S1-F"):
|
| 998 |
gr.HTML(section_header(
|
| 999 |
"S1-F", "PHYLO-RARE", "— Where almost nobody has looked yet",
|
| 1000 |
"<b style='color:#ef4444'>⚠️ <300 cases/yr · <5% survival · 0–1 prior studies per gap</b><br>"
|
|
|
|
| 1005 |
with gr.TabItem("R1 · DIPG"):
|
| 1006 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 1007 |
with gr.TabItem("R1a · DIPG Toolkit"):
|
| 1008 |
+
gr.HTML(proj_badge("S1-F·R1a", "DIPG Toolkit", "PBTA · GSE126319"))
|
| 1009 |
gr.Markdown(
|
| 1010 |
"> **Why DIPG?** Diffuse Intrinsic Pontine Glioma — median survival 9–11 months. "
|
| 1011 |
"H3K27M oncohistone in **78%** cases. "
|
|
|
|
| 1039 |
with gr.TabItem("R2 · UVM"):
|
| 1040 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 1041 |
with gr.TabItem("R2a · UVM Toolkit"):
|
| 1042 |
+
gr.HTML(proj_badge("S1-F·R2a", "UVM Toolkit", "TCGA-UVM n=80"))
|
| 1043 |
gr.Markdown(
|
| 1044 |
"> **Why UVM?** Uveal Melanoma — metastatic 5-yr survival **15%**. "
|
| 1045 |
"GNAQ/GNA11 mutations in 78% cases. "
|
|
|
|
| 1069 |
with gr.TabItem("R3 · pAML"):
|
| 1070 |
with gr.Tabs(elem_classes="sub-tabs"):
|
| 1071 |
with gr.TabItem("R3a · pAML Toolkit"):
|
| 1072 |
+
gr.HTML(proj_badge("S1-F·R3a", "pAML Toolkit", "TARGET-AML n≈197"))
|
| 1073 |
gr.Markdown(
|
| 1074 |
"> **Why pAML?** Pediatric AML — relapse OS **<30%**. "
|
| 1075 |
"FLT3-ITD in 25% cases. "
|
|
|
|
| 1103 |
)
|
| 1104 |
|
| 1105 |
# === S1-G · 3D Lab ===
|
| 1106 |
+
with gr.TabItem("🧊 S1-G"):
|
| 1107 |
gr.HTML(section_header(
|
| 1108 |
"S1-G", "PHYLO-SIM", "— 3D Models & Simulations",
|
| 1109 |
"Interactive visualizations for learning"
|
|
|
|
| 1136 |
## 🧪 Guided Investigations
|
| 1137 |
> 🟢 Beginner → 🟡 Intermediate → 🔴 Advanced
|
| 1138 |
|
| 1139 |
+
**S1-A·R1a** OpenVariant – try BRCA1:p.R1699Q vs R1699W
|
| 1140 |
+
**S1-D·R1a** Corona – vary PEG% and observe dominant protein
|
| 1141 |
+
**S1-D·R2a** Flow Corona – compare flow 0 vs 40 cm/s
|
| 1142 |
+
**S1-B·R2a** siRNA – count "Novel" targets across cancer types
|
| 1143 |
+
**S1-E·R1a** Liquid Biopsy – find minimal signal for CANCER
|
| 1144 |
+
**S1-G·3D Lab** – explore nanoparticle, DNA, and protein corona models
|
| 1145 |
""")
|
| 1146 |
|
| 1147 |
+
# === Journal (окрема вкладка) ===
|
| 1148 |
+
with gr.TabItem("📓 Journal"):
|
| 1149 |
+
gr.Markdown("## Lab Journal — Full History")
|
| 1150 |
+
with gr.Row():
|
| 1151 |
+
filter_dropdown = gr.Dropdown(
|
| 1152 |
+
choices=["All"] + PROJECT_CODES,
|
| 1153 |
+
value="All",
|
| 1154 |
+
label="Filter by project code"
|
| 1155 |
+
)
|
| 1156 |
+
refresh_btn = gr.Button("🔄 Refresh", size="sm")
|
| 1157 |
+
clear_btn = gr.Button("🗑️ Clear Journal", size="sm")
|
| 1158 |
+
journal_display = gr.Markdown(value=load_journal())
|
| 1159 |
+
|
| 1160 |
+
refresh_btn.click(load_journal, inputs=[filter_dropdown], outputs=journal_display)
|
| 1161 |
+
clear_btn.click(clear_journal, [], journal_display).then(
|
| 1162 |
+
load_journal, inputs=[filter_dropdown], outputs=journal_display
|
| 1163 |
+
)
|
| 1164 |
+
filter_dropdown.change(load_journal, inputs=[filter_dropdown], outputs=journal_display)
|
| 1165 |
+
|
| 1166 |
+
# Права колонка – швидке введення нотаток (без відображення)
|
| 1167 |
+
with gr.Column(scale=1, min_width=260):
|
| 1168 |
+
with gr.Group(elem_classes="sidebar-journal"):
|
| 1169 |
+
gr.Markdown("## 📝 Quick Note")
|
| 1170 |
+
note_dropdown = gr.Dropdown(
|
| 1171 |
+
choices=PROJECT_CODES,
|
| 1172 |
+
value=PROJECT_CODES[0],
|
| 1173 |
+
label="Project code"
|
| 1174 |
+
)
|
| 1175 |
+
note_input = gr.Textbox(label="Your observation", placeholder="Type here...", lines=3)
|
| 1176 |
+
save_btn = gr.Button("💾 Save Note", variant="primary", size="sm")
|
| 1177 |
+
save_status = gr.Markdown("")
|
| 1178 |
+
|
| 1179 |
+
def quick_save(note, code):
|
| 1180 |
+
if note.strip():
|
| 1181 |
+
log_entry(code, "quick note", note, note)
|
| 1182 |
+
return "✅ Note saved."
|
| 1183 |
+
return "⚠️ Note is empty."
|
| 1184 |
|
| 1185 |
+
save_btn.click(quick_save, [note_input, note_dropdown], save_status)
|
|
|
|
|
|
|
| 1186 |
|
| 1187 |
gr.Markdown(
|
| 1188 |
"---\n**K R&D Lab** · MIT License · "
|