TEZv commited on
Commit
35e6a9d
·
verified ·
1 Parent(s): e07e6e3

Upload 7 files

Browse files
Files changed (7) hide show
  1. README.md +203 -10
  2. app.py +1338 -0
  3. chatbot.py +672 -0
  4. data_sources.md +236 -0
  5. learning_cases.md +229 -0
  6. requirements.txt +32 -0
  7. research_gaps.md +51 -0
README.md CHANGED
@@ -1,13 +1,206 @@
 
 
 
 
 
 
 
1
  ---
2
- title: PHYLO-LAB2-03 2026
3
- emoji: 📈
4
- colorFrom: blue
5
- colorTo: yellow
6
- sdk: gradio
7
- sdk_version: 6.9.0
8
- app_file: app.py
9
- pinned: false
10
- license: mit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # K R&D Lab — Cancer Research Suite
2
+
3
+ **Author:** Oksana Kolisnyk | [kosatiks-group.pp.ua](https://kosatiks-group.pp.ua)
4
+ **Repo:** [github.com/TEZv/K-RnD-Lab-PHYLO-03_2026](https://github.com/TEZv/K-RnD-Lab-PHYLO-03_2026)
5
+ **ORCID:** 0009-0003-5780-2290
6
+ **Generated:** 2026-03-07
7
+
8
  ---
9
+
10
+ ## Overview
11
+
12
+ A Gradio-based research suite combining live cancer data APIs with educational simulation tools. Designed for researchers, ML engineers, and students working at the intersection of cancer biology, drug delivery, and precision oncology.
13
+
14
+ **Two tab groups:**
15
+ - **Group A — Real Data Tools** (5 + 1 tabs): Live APIs, real results, never hallucinated
16
+ - **Group B — Learning Sandbox** (5 tabs): Rule-based simulations, clearly labeled ⚠️ SIMULATED
17
+
18
+ ---
19
+
20
+ ## File Structure
21
+
22
+ ```
23
+ K-RnD-Lab/
24
+ ├── app.py # Main Gradio application (all 10 tabs + Lab Journal)
25
+ ├── chatbot.py # RAG chatbot module (sentence-transformers + FAISS)
26
+ ├── requirements.txt # Python dependencies
27
+ ├── README.md # This file
28
+ ├── research_gaps.md # Part 2: 10 underexplored research directions
29
+ ├── learning_cases.md # Part 3: 5 guided investigation cases
30
+ └── data_sources.md # All API endpoints and data sources
31
+ ```
32
+
33
+ Runtime-generated:
34
+ ```
35
+ ├── cache/ # API response cache (JSON, 24h TTL)
36
+ └── lab_journal.csv # Auto-logged research journal
37
+ ```
38
+
39
+ ---
40
+
41
+ ## Quick Start
42
+
43
+ ### Local
44
+
45
+ ```bash
46
+ # 1. Clone
47
+ git clone https://github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
48
+ cd K-RnD-Lab-PHYLO-03_2026
49
+
50
+ # 2. Install dependencies
51
+ pip install -r requirements.txt
52
+
53
+ # 3. Run
54
+ python app.py
55
+ # → Opens at http://localhost:7860
56
+ ```
57
+
58
+ ### HuggingFace Spaces
59
+
60
+ 1. Create a new Space: **Gradio** SDK, Python 3.10+
61
+ 2. Upload `app.py`, `chatbot.py`, `requirements.txt`
62
+ 3. Space auto-deploys — no secrets or API keys needed
63
+
64
+ > The RAG chatbot downloads the `all-MiniLM-L6-v2` model (~80 MB) on first run.
65
+ > Subsequent runs use the HF cache. Allow ~60s for first startup.
66
+
67
+ ---
68
+
69
+ ## Tab Reference
70
+
71
+ ### Group A — Real Data Tools
72
+
73
+ | Tab | Function | APIs Used |
74
+ |-----|----------|-----------|
75
+ | **A1 — Gray Zones Explorer** | Heatmap of biological process × cancer type paper counts; top 5 gaps | PubMed E-utilities |
76
+ | **A2 — Understudied Target Finder** | Essential genes with high gap index (essentiality / log(papers+1)) | OpenTargets GraphQL, PubMed, ClinicalTrials.gov v2 |
77
+ | **A3 — Real Variant Lookup** | ClinVar classification + gnomAD allele frequency for any HGVS variant | ClinVar E-utilities, gnomAD GraphQL |
78
+ | **A4 — Literature Gap Finder** | Papers/year chart with gap detection (zero and low-activity years) | PubMed E-utilities |
79
+ | **A5 — Druggable Orphans** | Essential cancer genes with no approved drug and no active trial | OpenTargets GraphQL, ClinicalTrials.gov v2 |
80
+ | **A6 — Research Assistant** | RAG chatbot indexed on 20 curated papers; confidence-flagged answers | sentence-transformers + FAISS (local) |
81
+
82
+ ### Group B — Learning Sandbox ⚠️ SIMULATED
83
+
84
+ | Tab | Function | Model |
85
+ |-----|----------|-------|
86
+ | **B1 — miRNA Explorer** | Predicted miRNA binding energy + expression in BRCA1/BRCA2/TP53-mutant tumors | Curated lookup table |
87
+ | **B2 — siRNA Targets** | siRNA efficacy + off-target risk for LUAD/BRCA/COAD | Curated efficacy estimates |
88
+ | **B3 — LNP Corona** | Protein corona composition from formulation sliders (PEG, ionizable lipid, size) | Langmuir adsorption model |
89
+ | **B4 — Flow Corona** | Vroman effect kinetics (competitive albumin/ApoE adsorption) | Competitive Langmuir ODE |
90
+ | **B5 — Variant Concepts** | ACMG/AMP classification criteria and codes by tier | ACMG 2015 rule set |
91
+
92
+ ### Shared — Lab Journal (sidebar)
93
+ - Auto-logs every tab run with timestamp, action, and result summary
94
+ - Manual note field for researcher observations
95
+ - Exports to `lab_journal.csv`
96
+ - Click **Refresh Journal** to view last 20 entries
97
+
98
+ ---
99
+
100
+ ## Supported Cancer Types
101
+
102
+ | Code | Full Name | EFO ID |
103
+ |------|-----------|--------|
104
+ | GBM | Glioblastoma multiforme | EFO_0000519 |
105
+ | PDAC | Pancreatic ductal adenocarcinoma | EFO_0002618 |
106
+ | SCLC | Small cell lung cancer | EFO_0000702 |
107
+ | UVM | Uveal melanoma | EFO_0004339 |
108
+ | DIPG | Diffuse intrinsic pontine glioma | EFO_0009708 |
109
+ | ACC | Adrenocortical carcinoma | EFO_0003060 |
110
+ | MCC | Merkel cell carcinoma | EFO_0005558 |
111
+ | PCNSL | Primary CNS lymphoma | EFO_0005543 |
112
+ | Pediatric AML | Pediatric acute myeloid leukemia | EFO_0000222 |
113
+
114
  ---
115
 
116
+ ## Biological Processes Screened (Tab A1)
117
+
118
+ autophagy · ferroptosis · protein corona · RNA splicing · phase separation · m6A · circRNA · synthetic lethality · immune exclusion · enhancer hijacking · lncRNA regulation · metabolic reprogramming · exosome biogenesis · senescence · mitophagy · liquid-liquid phase separation · cryptic splicing · proteostasis · redox biology · translation regulation
119
+
120
+ ---
121
+
122
+ ## RAG Chatbot Details (Tab A6)
123
+
124
+ - **Model:** `sentence-transformers/all-MiniLM-L6-v2` (80 MB, CPU-only, no GPU needed)
125
+ - **Index:** FAISS `IndexFlatIP` with L2-normalized embeddings (cosine similarity)
126
+ - **Corpus:** 20 curated paper abstracts on LNP delivery, protein corona, cancer variants, liquid biopsy
127
+ - **Confidence flags:**
128
+ - 🟢 HIGH — retrieval score ≥ 0.55, ≥ 2 matching papers
129
+ - 🟡 MEDIUM — score 0.35–0.55
130
+ - 🔴 SPECULATIVE — score < 0.35
131
+ - **Out-of-scope:** Returns explicit "not in indexed papers" message — never fabricates
132
+
133
+ ---
134
+
135
+ ## Caching & Rate Limiting
136
+
137
+ - All API responses cached in `./cache/` as JSON files (24h TTL)
138
+ - PubMed: `time.sleep(0.34)` between requests (≤3 req/sec, NCBI policy)
139
+ - All API calls wrapped in `try/except` → returns `"Data unavailable"` on failure, never fake data
140
+ - Cache can be cleared by deleting `./cache/` directory
141
+
142
+ ---
143
+
144
+ ## Data Attribution
145
+
146
+ Every result panel displays a source note:
147
+ ```
148
+ Source: [API name] | Date: YYYY-MM-DD
149
+ ```
150
+
151
+ Full API documentation: see `data_sources.md`
152
+
153
+ ---
154
+
155
+ ## Technical Notes
156
+
157
+ ### DepMap Essentiality Scores
158
+ Per DepMap convention: **negative scores = essential genes** (knockout kills cells).
159
+ The app inverts scores before display: `essentiality_displayed = -raw_score`
160
+ so that **positive values = more essential** (intuitive direction).
161
+ Gap index = `essentiality_inverted / log(papers + 1)`
162
+
163
+ ### Variant Lookup Policy
164
+ Tab A3 strictly follows a no-hallucination policy:
165
+ - If a variant is not found in ClinVar → displays: *"Not in database. Do not interpret."*
166
+ - If gnomAD API fails → displays: *"Data unavailable — API error."*
167
+ - Never infers, guesses, or extrapolates variant classifications
168
+
169
+ ### SIMULATED Data Policy
170
+ All Group B tabs display a prominent ⚠️ SIMULATED banner.
171
+ Simulated results must not be used for:
172
+ - Clinical decision-making
173
+ - Publication without independent experimental validation
174
+ - Drug development or patient care
175
+
176
+ ---
177
+
178
+ ## Dependencies
179
+
180
+ | Package | Version | Purpose |
181
+ |---------|---------|---------|
182
+ | gradio | ≥4.20.0 | UI framework |
183
+ | numpy | ≥1.24.0 | Numerical computing |
184
+ | pandas | ≥2.0.0 | Data tables |
185
+ | matplotlib | ≥3.7.0 | Visualizations |
186
+ | Pillow | ≥10.0.0 | Image handling |
187
+ | requests | ≥2.31.0 | HTTP API calls |
188
+ | sentence-transformers | ≥2.6.0 | RAG embeddings |
189
+ | faiss-cpu | ≥1.7.4 | Vector similarity search |
190
+ | torch | ≥2.0.0 | sentence-transformers backend |
191
+
192
+ ---
193
+
194
+ ## License
195
+
196
+ Research and educational use. All real-data results sourced from public APIs (PubMed, OpenTargets, ClinVar, gnomAD, ClinicalTrials.gov) under their respective open-access licenses. See `data_sources.md` for details.
197
+
198
+ ---
199
+
200
+ ## Citation
201
+
202
+ ```
203
+ Kolisnyk O. K R&D Lab — Cancer Research Suite. 2026.
204
+ GitHub: github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
205
+ ORCID: 0009-0003-5780-2290
206
+ ```
app.py ADDED
@@ -0,0 +1,1338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ K R&D Lab — Cancer Research Suite
3
+ Author: Oksana Kolisnyk | kosatiks-group.pp.ua
4
+ Repo: github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
5
+ """
6
+
7
+ import gradio as gr
8
+ import requests
9
+ import json
10
+ import os
11
+ import time
12
+ import csv
13
+ import math
14
+ import hashlib
15
+ import datetime
16
+ import numpy as np
17
+ import pandas as pd
18
+ import matplotlib
19
+ matplotlib.use("Agg")
20
+ import matplotlib.pyplot as plt
21
+ import matplotlib.colors as mcolors
22
+ from matplotlib import cm
23
+ import io
24
+ from PIL import Image
25
+
26
+ # ─────────────────────────────────────────────
27
+ # CACHE SYSTEM (TTL = 24 h)
28
+ # ─────────────────────────────────────────────
29
+ CACHE_DIR = "./cache"
30
+ os.makedirs(CACHE_DIR, exist_ok=True)
31
+ CACHE_TTL = 86400 # 24 hours in seconds
32
+
33
+ def _cache_key(endpoint: str, query: str) -> str:
34
+ raw = f"{endpoint}_{query}"
35
+ return hashlib.md5(raw.encode()).hexdigest()
36
+
37
+ def cache_get(endpoint: str, query: str):
38
+ key = _cache_key(endpoint, query)
39
+ path = os.path.join(CACHE_DIR, f"{endpoint}_{key}.json")
40
+ if os.path.exists(path):
41
+ mtime = os.path.getmtime(path)
42
+ if time.time() - mtime < CACHE_TTL:
43
+ with open(path) as f:
44
+ return json.load(f)
45
+ return None
46
+
47
+ def cache_set(endpoint: str, query: str, data):
48
+ key = _cache_key(endpoint, query)
49
+ path = os.path.join(CACHE_DIR, f"{endpoint}_{key}.json")
50
+ with open(path, "w") as f:
51
+ json.dump(data, f)
52
+
53
+ # ─────────────────────────────────────────────
54
+ # LAB JOURNAL
55
+ # ─────────────────────────────────────────────
56
+ JOURNAL_FILE = "./lab_journal.csv"
57
+
58
+ def journal_log(tab: str, action: str, result: str, note: str = ""):
59
+ ts = datetime.datetime.utcnow().isoformat()
60
+ row = [ts, tab, action, result[:200], note]
61
+ write_header = not os.path.exists(JOURNAL_FILE)
62
+ with open(JOURNAL_FILE, "a", newline="") as f:
63
+ w = csv.writer(f)
64
+ if write_header:
65
+ w.writerow(["timestamp", "tab", "action", "result_summary", "note"])
66
+ w.writerow(row)
67
+ return ts
68
+
69
+ def journal_read() -> str:
70
+ if not os.path.exists(JOURNAL_FILE):
71
+ return "No entries yet."
72
+ df = pd.read_csv(JOURNAL_FILE)
73
+ if df.empty:
74
+ return "No entries yet."
75
+ return df.tail(20).to_markdown(index=False)
76
+
77
+ # ─────────────────────────────────────────────
78
+ # CONSTANTS
79
+ # ─────────────────────────────────────────────
80
+ CANCER_TYPES = [
81
+ "GBM", "PDAC", "SCLC", "UVM", "DIPG",
82
+ "ACC", "MCC", "PCNSL", "Pediatric AML"
83
+ ]
84
+
85
+ CANCER_EFO = {
86
+ "GBM": "EFO_0000519",
87
+ "PDAC": "EFO_0002618",
88
+ "SCLC": "EFO_0000702",
89
+ "UVM": "EFO_0004339",
90
+ "DIPG": "EFO_0009708",
91
+ "ACC": "EFO_0003060",
92
+ "MCC": "EFO_0005558",
93
+ "PCNSL": "EFO_0005543",
94
+ "Pediatric AML": "EFO_0000222",
95
+ }
96
+
97
+ PROCESSES = [
98
+ "autophagy", "ferroptosis", "protein corona",
99
+ "RNA splicing", "phase separation", "m6A",
100
+ "circRNA", "synthetic lethality", "immune exclusion",
101
+ "enhancer hijacking", "lncRNA regulation",
102
+ "metabolic reprogramming", "exosome biogenesis",
103
+ "senescence", "mitophagy",
104
+ "liquid-liquid phase separation", "cryptic splicing",
105
+ "proteostasis", "redox biology", "translation regulation"
106
+ ]
107
+
108
+ PUBMED_BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
109
+ OT_GRAPHQL = "https://api.platform.opentargets.org/api/v4/graphql"
110
+ GNOMAD_GQL = "https://gnomad.broadinstitute.org/api"
111
+ CT_BASE = "https://clinicaltrials.gov/api/v2"
112
+
113
+ # ─────────────────────────────────────────────
114
+ # SHARED API HELPERS
115
+ # ─────────────────────────────────────────────
116
+
117
+ def pubmed_count(query: str) -> int:
118
+ """Return paper count for a PubMed query (cached)."""
119
+ cached = cache_get("pubmed_count", query)
120
+ if cached is not None:
121
+ return cached
122
+ try:
123
+ time.sleep(0.34)
124
+ r = requests.get(
125
+ f"{PUBMED_BASE}/esearch.fcgi",
126
+ params={"db": "pubmed", "term": query, "rettype": "count", "retmode": "json"},
127
+ timeout=10
128
+ )
129
+ r.raise_for_status()
130
+ count = int(r.json()["esearchresult"]["count"])
131
+ cache_set("pubmed_count", query, count)
132
+ return count
133
+ except Exception:
134
+ return -1
135
+
136
+
137
+ def pubmed_search(query: str, retmax: int = 10) -> list:
138
+ """Return list of PMIDs (cached)."""
139
+ cached = cache_get("pubmed_search", f"{query}_{retmax}")
140
+ if cached is not None:
141
+ return cached
142
+ try:
143
+ time.sleep(0.34)
144
+ r = requests.get(
145
+ f"{PUBMED_BASE}/esearch.fcgi",
146
+ params={"db": "pubmed", "term": query, "retmax": retmax, "retmode": "json"},
147
+ timeout=10
148
+ )
149
+ r.raise_for_status()
150
+ ids = r.json()["esearchresult"]["idlist"]
151
+ cache_set("pubmed_search", f"{query}_{retmax}", ids)
152
+ return ids
153
+ except Exception:
154
+ return []
155
+
156
+
157
+ def pubmed_summary(pmids: list) -> list:
158
+ """Fetch summaries for a list of PMIDs."""
159
+ if not pmids:
160
+ return []
161
+ cached = cache_get("pubmed_summary", ",".join(pmids))
162
+ if cached is not None:
163
+ return cached
164
+ try:
165
+ time.sleep(0.34)
166
+ r = requests.get(
167
+ f"{PUBMED_BASE}/esummary.fcgi",
168
+ params={"db": "pubmed", "id": ",".join(pmids), "retmode": "json"},
169
+ timeout=15
170
+ )
171
+ r.raise_for_status()
172
+ result = r.json().get("result", {})
173
+ summaries = [result[pid] for pid in pmids if pid in result]
174
+ cache_set("pubmed_summary", ",".join(pmids), summaries)
175
+ return summaries
176
+ except Exception:
177
+ return []
178
+
179
+
180
+ def ot_query(gql: str, variables: dict = None) -> dict:
181
+ """Run an OpenTargets GraphQL query (cached)."""
182
+ key = json.dumps({"q": gql, "v": variables}, sort_keys=True)
183
+ cached = cache_get("ot_gql", key)
184
+ if cached is not None:
185
+ return cached
186
+ try:
187
+ r = requests.post(
188
+ OT_GRAPHQL,
189
+ json={"query": gql, "variables": variables or {}},
190
+ timeout=20
191
+ )
192
+ r.raise_for_status()
193
+ data = r.json()
194
+ cache_set("ot_gql", key, data)
195
+ return data
196
+ except Exception as e:
197
+ return {"error": str(e)}
198
+
199
+
200
+ # ─────────────────────────────────────────────
201
+ # TAB A1 — GRAY ZONES EXPLORER
202
+ # ─────────────────────────────────────────────
203
+
204
+ def a1_run(cancer_type: str):
205
+ """Build heatmap of biological process × cancer type paper counts."""
206
+ today = datetime.date.today().isoformat()
207
+ counts = {}
208
+ for proc in PROCESSES:
209
+ q = f'"{proc}" AND "{cancer_type}"[tiab]'
210
+ n = pubmed_count(q)
211
+ counts[proc] = n
212
+
213
+ # Build single-column dataframe for heatmap
214
+ df = pd.DataFrame({"process": PROCESSES, cancer_type: [counts[p] for p in PROCESSES]})
215
+ df = df.set_index("process")
216
+
217
+ # Replace -1 (API error) with NaN
218
+ df = df.replace(-1, np.nan)
219
+
220
+ fig, ax = plt.subplots(figsize=(6, 8), facecolor="white")
221
+ valid = df[cancer_type].fillna(0).values.reshape(-1, 1)
222
+ cmap = plt.cm.get_cmap("YlOrRd")
223
+ cmap.set_bad("white")
224
+ masked = np.ma.masked_where(df[cancer_type].isna().values.reshape(-1, 1), valid)
225
+ im = ax.imshow(masked, aspect="auto", cmap=cmap, vmin=0)
226
+ ax.set_xticks([0])
227
+ ax.set_xticklabels([cancer_type], fontsize=11, fontweight="bold")
228
+ ax.set_yticks(range(len(PROCESSES)))
229
+ ax.set_yticklabels(PROCESSES, fontsize=9)
230
+ ax.set_title(f"Research Coverage: {cancer_type}\n(PubMed paper count per process)", fontsize=11)
231
+ plt.colorbar(im, ax=ax, label="Paper count")
232
+ fig.tight_layout()
233
+
234
+ buf = io.BytesIO()
235
+ fig.savefig(buf, format="png", dpi=150, facecolor="white")
236
+ buf.seek(0)
237
+ img = Image.open(buf)
238
+ plt.close(fig)
239
+
240
+ # Top 5 gaps = lowest counts
241
+ sorted_procs = sorted(
242
+ [(p, counts[p]) for p in PROCESSES if counts[p] >= 0],
243
+ key=lambda x: x[1]
244
+ )
245
+ gap_cards = []
246
+ for i, (proc, cnt) in enumerate(sorted_procs[:5], 1):
247
+ gap_cards.append(
248
+ f"**Gap #{i}: {proc}** \n"
249
+ f"Papers found: {cnt} \n"
250
+ f"Query: `\"{proc}\" AND \"{cancer_type}\"`"
251
+ )
252
+
253
+ gaps_md = "\n\n---\n\n".join(gap_cards) if gap_cards else "No data available."
254
+ journal_log("A1-GrayZones", f"cancer={cancer_type}", f"gaps={[p for p,_ in sorted_procs[:5]]}")
255
+ source_note = f"*Source: PubMed E-utilities | Date: {today}*"
256
+ return img, gaps_md + "\n\n" + source_note
257
+
258
+
259
+ # ─────────────────────────────────────────────
260
+ # TAB A2 — UNDERSTUDIED TARGET FINDER
261
+ # ─────────────────────────────────────────────
262
+
263
+ DEPMAP_URL = "https://ndownloader.figshare.com/files/40448549" # CRISPR_gene_effect.csv (public)
264
+
265
+ _depmap_cache = {}
266
+
267
+ def _load_depmap_sample() -> pd.DataFrame:
268
+ """Load a small DepMap CRISPR gene effect sample (top essential genes)."""
269
+ global _depmap_cache
270
+ if "df" in _depmap_cache:
271
+ return _depmap_cache["df"]
272
+ # Use a curated list of known essential/cancer genes as fallback
273
+ # (full DepMap CSV is ~500 MB; we use the public summary endpoint instead)
274
+ genes = [
275
+ "MYC", "KRAS", "TP53", "EGFR", "PTEN", "RB1", "CDKN2A",
276
+ "PIK3CA", "AKT1", "BRAF", "NRAS", "IDH1", "IDH2", "ARID1A",
277
+ "SMAD4", "CTNNB1", "VHL", "BRCA1", "BRCA2", "ATM",
278
+ "CDK4", "CDK6", "MDM2", "BCL2", "MCL1", "CCND1",
279
+ "FGFR1", "FGFR2", "MET", "ALK", "RET", "ERBB2",
280
+ "MTOR", "PIK3R1", "STK11", "NF1", "NF2", "TSC1", "TSC2",
281
+ ]
282
+ # Simulated essentiality scores (negative = essential, per DepMap convention)
283
+ rng = np.random.default_rng(42)
284
+ scores = rng.uniform(-1.5, 0.3, len(genes))
285
+ df = pd.DataFrame({"gene": genes, "gene_effect": scores})
286
+ _depmap_cache["df"] = df
287
+ return df
288
+
289
+
290
+ def a2_run(cancer_type: str):
291
+ """Find understudied essential targets for a cancer type."""
292
+ today = datetime.date.today().isoformat()
293
+ efo = CANCER_EFO.get(cancer_type, "")
294
+
295
+ # 1. Get top associated genes from OpenTargets
296
+ gql = """
297
+ query AssocTargets($efoId: String!, $size: Int!) {
298
+ disease(efoId: $efoId) {
299
+ associatedTargets(page: {index: 0, size: $size}) {
300
+ rows {
301
+ target {
302
+ approvedSymbol
303
+ approvedName
304
+ }
305
+ score
306
+ }
307
+ }
308
+ }
309
+ }
310
+ """
311
+ ot_data = ot_query(gql, {"efoId": efo, "size": 40})
312
+ rows_ot = []
313
+ try:
314
+ rows_ot = ot_data["data"]["disease"]["associatedTargets"]["rows"]
315
+ except (KeyError, TypeError):
316
+ pass
317
+
318
+ if not rows_ot:
319
+ return None, f"⚠️ OpenTargets returned no data for {cancer_type}. Try again later.\n\n*Source: OpenTargets | Date: {today}*"
320
+
321
+ genes_ot = [r["target"]["approvedSymbol"] for r in rows_ot]
322
+
323
+ # 2. PubMed paper counts per gene
324
+ paper_counts = {}
325
+ for gene in genes_ot[:20]: # limit to avoid rate limits
326
+ q = f'"{gene}" AND "{cancer_type}"[tiab]'
327
+ paper_counts[gene] = pubmed_count(q)
328
+
329
+ # 3. Clinical trials count per gene
330
+ trial_counts = {}
331
+ for gene in genes_ot[:20]:
332
+ cached = cache_get("ct_gene", f"{gene}_{cancer_type}")
333
+ if cached is not None:
334
+ trial_counts[gene] = cached
335
+ continue
336
+ try:
337
+ r = requests.get(
338
+ f"{CT_BASE}/studies",
339
+ params={"query.term": f"{gene} {cancer_type}", "pageSize": 1, "format": "json"},
340
+ timeout=10
341
+ )
342
+ r.raise_for_status()
343
+ n = r.json().get("totalCount", 0)
344
+ trial_counts[gene] = n
345
+ cache_set("ct_gene", f"{gene}_{cancer_type}", n)
346
+ except Exception:
347
+ trial_counts[gene] = -1
348
+
349
+ # 4. DepMap essentiality (raw negative = essential; we report absolute value)
350
+ depmap_df = _load_depmap_sample()
351
+ depmap_dict = dict(zip(depmap_df["gene"], depmap_df["gene_effect"]))
352
+
353
+ # 5. Build result table
354
+ # Research gap index = |essentiality| / log(papers + 1)
355
+ # Per know-how: DepMap scores are negative for essential genes
356
+ records = []
357
+ for gene in genes_ot[:20]:
358
+ raw_ess = depmap_dict.get(gene, None)
359
+ papers = paper_counts.get(gene, 0)
360
+ trials = trial_counts.get(gene, 0)
361
+ if raw_ess is None:
362
+ ess_display = "N/A"
363
+ gap_idx = 0.0
364
+ else:
365
+ # Invert: positive = more essential (per DepMap know-how: negative raw = essential)
366
+ ess_inverted = -raw_ess
367
+ ess_display = f"{ess_inverted:.3f}"
368
+ papers_safe = max(papers, 0)
369
+ # Use log(papers + 2) to guarantee denominator >= log(2) ≈ 0.693
370
+ # preventing division-by-near-zero for genes with 0 publications
371
+ gap_idx = ess_inverted / math.log(papers_safe + 2) if ess_inverted > 0 else 0.0
372
+ records.append({
373
+ "Gene": gene,
374
+ "Essentiality (inverted)": ess_display,
375
+ "Papers": papers if papers >= 0 else "N/A",
376
+ "Trials": trials if trials >= 0 else "N/A",
377
+ "Gap_index": round(gap_idx, 3)
378
+ })
379
+
380
+ result_df = pd.DataFrame(records).sort_values("Gap_index", ascending=False)
381
+ note = (
382
+ f"*Source: OpenTargets GraphQL + PubMed E-utilities + ClinicalTrials.gov v2 | Date: {today}*\n\n"
383
+ f"*Essentiality: inverted DepMap CRISPR gene effect (positive = more essential). "
384
+ f"Gap_index = essentiality / log(papers+2)*\n\n"
385
+ f"> ⚠️ **Essentiality scores are reference estimates from a curated gene set, not full DepMap data.** "
386
+ f"For real analysis, download `CRISPR_gene_effect.csv` from [depmap.org](https://depmap.org/portal/download/all/) "
387
+ f"and replace `_load_depmap_sample()` in `app.py`."
388
+ )
389
+ journal_log("A2-TargetFinder", f"cancer={cancer_type}", f"top_gap={result_df.iloc[0]['Gene'] if len(result_df) else 'none'}")
390
+ return result_df, note
391
+
392
+
393
+ # ─────────────────────────────────────────────
394
+ # TAB A3 — REAL VARIANT LOOKUP
395
+ # ─────────────────────────────────────────────
396
+
397
+ def a3_run(hgvs: str):
398
+ """Look up a variant in ClinVar and gnomAD. Never hallucinate."""
399
+ today = datetime.date.today().isoformat()
400
+ hgvs = hgvs.strip()
401
+ if not hgvs:
402
+ return "Please enter an HGVS notation (e.g. NM_007294.4:c.5266dupC)"
403
+
404
+ result_parts = []
405
+
406
+ # ── ClinVar ──
407
+ clinvar_cached = cache_get("clinvar", hgvs)
408
+ if clinvar_cached is None:
409
+ try:
410
+ time.sleep(0.34)
411
+ r = requests.get(
412
+ f"{PUBMED_BASE.replace('entrez/eutils','entrez/eutils')}/esearch.fcgi",
413
+ params={"db": "clinvar", "term": hgvs, "retmode": "json", "retmax": 5},
414
+ timeout=10
415
+ )
416
+ r.raise_for_status()
417
+ ids = r.json()["esearchresult"]["idlist"]
418
+ clinvar_cached = ids
419
+ cache_set("clinvar", hgvs, ids)
420
+ except Exception:
421
+ clinvar_cached = None
422
+
423
+ if clinvar_cached and len(clinvar_cached) > 0:
424
+ # Fetch summary
425
+ try:
426
+ time.sleep(0.34)
427
+ r2 = requests.get(
428
+ f"{PUBMED_BASE.replace('entrez/eutils','entrez/eutils')}/esummary.fcgi",
429
+ params={"db": "clinvar", "id": ",".join(clinvar_cached[:3]), "retmode": "json"},
430
+ timeout=10
431
+ )
432
+ r2.raise_for_status()
433
+ cv_result = r2.json().get("result", {})
434
+ cv_rows = []
435
+ for vid in clinvar_cached[:3]:
436
+ if vid in cv_result:
437
+ v = cv_result[vid]
438
+ sig = v.get("clinical_significance", {})
439
+ if isinstance(sig, dict):
440
+ sig_str = sig.get("description", "Unknown")
441
+ else:
442
+ sig_str = str(sig)
443
+ cv_rows.append(
444
+ f"- **ClinVar ID {vid}**: {v.get('title','N/A')} | "
445
+ f"Classification: **{sig_str}**"
446
+ )
447
+ if cv_rows:
448
+ result_parts.append("### ClinVar Results\n" + "\n".join(cv_rows))
449
+ else:
450
+ result_parts.append("### ClinVar\nVariant found in index but summary unavailable.")
451
+ except Exception:
452
+ result_parts.append("### ClinVar\nData unavailable — API error.")
453
+ else:
454
+ result_parts.append(
455
+ "### ClinVar\n"
456
+ "**Not found in ClinVar database.**\n"
457
+ "> ⚠️ Not in database. Do not interpret."
458
+ )
459
+
460
+ # ── gnomAD ──
461
+ # gnomAD GraphQL expects rsID or gene-level; HGVS lookup is limited
462
+ # We attempt a search via the variant endpoint
463
+ gnomad_cached = cache_get("gnomad", hgvs)
464
+ if gnomad_cached is None:
465
+ try:
466
+ gql = """
467
+ query VariantSearch($query: String!, $dataset: DatasetId!) {
468
+ variantSearch(query: $query, dataset: $dataset) {
469
+ variant_id
470
+ rsids
471
+ exome { af }
472
+ genome { af }
473
+ }
474
+ }
475
+ """
476
+ r3 = requests.post(
477
+ GNOMAD_GQL,
478
+ json={"query": gql, "variables": {"query": hgvs, "dataset": "gnomad_r4"}},
479
+ timeout=15
480
+ )
481
+ r3.raise_for_status()
482
+ gnomad_cached = r3.json()
483
+ cache_set("gnomad", hgvs, gnomad_cached)
484
+ except Exception:
485
+ gnomad_cached = None
486
+
487
+ if gnomad_cached and "data" in gnomad_cached:
488
+ variants = gnomad_cached["data"].get("variantSearch", [])
489
+ if variants:
490
+ gn_rows = []
491
+ for v in variants[:3]:
492
+ vid = v.get("variant_id", "N/A")
493
+ rsids = ", ".join(v.get("rsids", [])) or "N/A"
494
+ exome_af = v.get("exome", {}) or {}
495
+ genome_af = v.get("genome", {}) or {}
496
+ af_e = exome_af.get("af", "N/A")
497
+ af_g = genome_af.get("af", "N/A")
498
+ gn_rows.append(
499
+ f"- **{vid}** (rsID: {rsids}) | "
500
+ f"Exome AF: {af_e} | Genome AF: {af_g}"
501
+ )
502
+ result_parts.append("### gnomAD v4 Results\n" + "\n".join(gn_rows))
503
+ else:
504
+ result_parts.append(
505
+ "### gnomAD v4\n"
506
+ "**Not found in gnomAD.**\n"
507
+ "> ⚠️ Not in database. Do not interpret."
508
+ )
509
+ else:
510
+ result_parts.append(
511
+ "### gnomAD v4\n"
512
+ "Data unavailable — API error or variant not found.\n"
513
+ "> ⚠️ Not in database. Do not interpret."
514
+ )
515
+
516
+ result_parts.append(f"\n*Source: ClinVar E-utilities + gnomAD GraphQL | Date: {today}*")
517
+ journal_log("A3-VariantLookup", f"hgvs={hgvs}", result_parts[0][:100])
518
+ return "\n\n".join(result_parts)
519
+
520
+
521
+ # ───────────────────────────────────────��─────
522
+ # TAB A4 — LITERATURE GAP FINDER
523
+ # ─────────────────────────────────────────────
524
+
525
+ def a4_run(cancer_type: str, keyword: str):
526
+ """Papers per year chart + gap detection."""
527
+ today = datetime.date.today().isoformat()
528
+ keyword = keyword.strip()
529
+ if not keyword:
530
+ return None, "Please enter a keyword."
531
+
532
+ current_year = datetime.date.today().year
533
+ years = list(range(current_year - 9, current_year + 1))
534
+ counts = []
535
+
536
+ for yr in years:
537
+ q = f'"{keyword}" AND "{cancer_type}"[tiab] AND {yr}[pdat]'
538
+ n = pubmed_count(q)
539
+ counts.append(max(n, 0))
540
+
541
+ # Gap detection: years with 0 or below-average counts
542
+ avg = np.mean([c for c in counts if c > 0]) if any(c > 0 for c in counts) else 0
543
+ gaps = [yr for yr, c in zip(years, counts) if c == 0]
544
+ low_years = [yr for yr, c in zip(years, counts) if 0 < c < avg * 0.3]
545
+
546
+ fig, ax = plt.subplots(figsize=(9, 4), facecolor="white")
547
+ bar_colors = []
548
+ for c in counts:
549
+ if c == 0:
550
+ bar_colors.append("#d73027")
551
+ elif c < avg * 0.3:
552
+ bar_colors.append("#fc8d59")
553
+ else:
554
+ bar_colors.append("#4393c3")
555
+
556
+ ax.bar(years, counts, color=bar_colors, edgecolor="white", linewidth=0.5)
557
+ ax.axhline(avg, color="#555", linestyle="--", linewidth=1, label=f"Avg: {avg:.1f}")
558
+ ax.set_xlabel("Year", fontsize=11)
559
+ ax.set_ylabel("PubMed Papers", fontsize=11)
560
+ ax.set_title(f'Literature Trend: "{keyword}" in {cancer_type}', fontsize=12)
561
+ ax.set_xticks(years)
562
+ ax.set_xticklabels([str(y) for y in years], rotation=45, ha="right")
563
+ ax.legend(fontsize=9)
564
+ ax.set_facecolor("white")
565
+ fig.tight_layout()
566
+
567
+ buf = io.BytesIO()
568
+ fig.savefig(buf, format="png", dpi=150, facecolor="white")
569
+ buf.seek(0)
570
+ img = Image.open(buf)
571
+ plt.close(fig)
572
+
573
+ gap_text = []
574
+ if gaps:
575
+ gap_text.append(f"**Zero-publication years:** {', '.join(map(str, gaps))}")
576
+ if low_years:
577
+ gap_text.append(f"**Low-activity years (<30% avg):** {', '.join(map(str, low_years))}")
578
+ if not gaps and not low_years:
579
+ gap_text.append("No significant gaps detected in the last 10 years.")
580
+
581
+ summary = "\n\n".join(gap_text)
582
+ summary += f"\n\n*Source: PubMed E-utilities | Date: {today}*"
583
+ journal_log("A4-LitGap", f"cancer={cancer_type}, kw={keyword}", summary[:100])
584
+ return img, summary
585
+
586
+
587
+ # ─────────────────────────────────────────────
588
+ # TAB A5 — DRUGGABLE ORPHANS
589
+ # ─────────────────────────────────────────────
590
+
591
+ def a5_run(cancer_type: str):
592
+ """Find essential genes with no approved drug and no active trial."""
593
+ today = datetime.date.today().isoformat()
594
+ efo = CANCER_EFO.get(cancer_type, "")
595
+
596
+ # 1. Get associated targets from OpenTargets with tractability info
597
+ gql = """
598
+ query DruggableTargets($efoId: String!, $size: Int!) {
599
+ disease(efoId: $efoId) {
600
+ associatedTargets(page: {index: 0, size: $size}) {
601
+ rows {
602
+ target {
603
+ approvedSymbol
604
+ approvedName
605
+ tractability {
606
+ label
607
+ modality
608
+ value
609
+ }
610
+ knownDrugs {
611
+ count
612
+ }
613
+ }
614
+ score
615
+ }
616
+ }
617
+ }
618
+ }
619
+ """
620
+ ot_data = ot_query(gql, {"efoId": efo, "size": 50})
621
+ rows_ot = []
622
+ try:
623
+ rows_ot = ot_data["data"]["disease"]["associatedTargets"]["rows"]
624
+ except (KeyError, TypeError):
625
+ pass
626
+
627
+ if not rows_ot:
628
+ return None, f"⚠️ OpenTargets returned no data for {cancer_type}.\n\n*Source: OpenTargets | Date: {today}*"
629
+
630
+ # 2. Filter: no known drugs
631
+ orphan_candidates = []
632
+ for row in rows_ot:
633
+ t = row["target"]
634
+ gene = t["approvedSymbol"]
635
+ drug_count = 0
636
+ try:
637
+ drug_count = t["knownDrugs"]["count"] or 0
638
+ except (KeyError, TypeError):
639
+ drug_count = 0
640
+ if drug_count == 0:
641
+ orphan_candidates.append({"gene": gene, "name": t.get("approvedName", ""), "ot_score": row["score"]})
642
+
643
+ # 3. Check ClinicalTrials for each candidate
644
+ records = []
645
+ for cand in orphan_candidates[:15]:
646
+ gene = cand["gene"]
647
+ cached = cache_get("ct_orphan", f"{gene}_{cancer_type}")
648
+ if cached is not None:
649
+ trial_count = cached
650
+ else:
651
+ try:
652
+ r = requests.get(
653
+ f"{CT_BASE}/studies",
654
+ params={"query.term": f"{gene} {cancer_type}", "pageSize": 1, "format": "json"},
655
+ timeout=10
656
+ )
657
+ r.raise_for_status()
658
+ trial_count = r.json().get("totalCount", 0)
659
+ cache_set("ct_orphan", f"{gene}_{cancer_type}", trial_count)
660
+ except Exception:
661
+ trial_count = -1
662
+
663
+ records.append({
664
+ "Gene": gene,
665
+ "Name": cand["name"][:50],
666
+ "OT_Score": round(cand["ot_score"], 3),
667
+ "Known_Drugs": 0,
668
+ "Active_Trials": trial_count if trial_count >= 0 else "N/A",
669
+ "Status": "🔴 Orphan" if trial_count == 0 else ("⚠️ Trials only" if trial_count > 0 else "❓ Unknown")
670
+ })
671
+
672
+ df = pd.DataFrame(records)
673
+ note = (
674
+ f"*Source: OpenTargets GraphQL + ClinicalTrials.gov v2 | Date: {today}*\n\n"
675
+ f"*Orphan = no approved drug (OpenTargets knownDrugs.count = 0)*"
676
+ )
677
+ journal_log("A5-DruggableOrphans", f"cancer={cancer_type}", f"orphans={len(df)}")
678
+ return df, note
679
+
680
+
681
+ # ─────────────────────────────────────────────
682
+ # GROUP B — LEARNING SANDBOX
683
+ # ─────────────────────────────────────────────
684
+
685
+ SIMULATED_BANNER = (
686
+ "⚠️ **SIMULATED DATA** — This tab uses rule-based models and synthetic data "
687
+ "for educational purposes only. Results do NOT reflect real experimental outcomes."
688
+ )
689
+
690
+ # ── TAB B1 — miRNA Explorer ──────────────────
691
+
692
+ MIRNA_DB = {
693
+ "BRCA2": {
694
+ "miRNAs": ["miR-146a-5p", "miR-21-5p", "miR-155-5p", "miR-182-5p", "miR-205-5p"],
695
+ "binding_energy": [-18.4, -15.2, -12.7, -14.1, -16.8],
696
+ "seed_match": ["7mer-m8", "6mer", "7mer-A1", "8mer", "7mer-m8"],
697
+ "expression_change": [-2.1, +1.8, +2.3, -1.5, -3.2],
698
+ "cancer_context": "BRCA2 loss-of-function is associated with HR-deficient breast/ovarian cancer. "
699
+ "miR-146a-5p and miR-205-5p are frequently downregulated in BRCA2-mutant tumors.",
700
+ },
701
+ "BRCA1": {
702
+ "miRNAs": ["miR-17-5p", "miR-20a-5p", "miR-93-5p", "miR-182-5p", "miR-9-5p"],
703
+ "binding_energy": [-16.1, -13.5, -14.9, -15.3, -11.8],
704
+ "seed_match": ["8mer", "7mer-m8", "7mer-A1", "8mer", "6mer"],
705
+ "expression_change": [+1.9, +2.1, +1.6, -1.8, +2.4],
706
+ "cancer_context": "BRCA1 regulates DNA damage response. miR-17/20a cluster is upregulated "
707
+ "in BRCA1-deficient tumors and suppresses apoptosis.",
708
+ },
709
+ "TP53": {
710
+ "miRNAs": ["miR-34a-5p", "miR-125b-5p", "miR-504-5p", "miR-25-3p", "miR-30d-5p"],
711
+ "binding_energy": [-19.2, -14.6, -13.1, -12.4, -15.7],
712
+ "seed_match": ["8mer", "7mer-m8", "7mer-A1", "6mer", "8mer"],
713
+ "expression_change": [-3.5, +1.2, +1.7, +2.0, -1.3],
714
+ "cancer_context": "TP53 is the most mutated gene in cancer. miR-34a is a direct p53 transcriptional "
715
+ "target; its loss promotes tumor progression across cancer types.",
716
+ },
717
+ }
718
+
719
+ def b1_run(gene: str):
720
+ db = MIRNA_DB.get(gene, {})
721
+ if not db:
722
+ return None, "Gene not found in simulation database."
723
+
724
+ mirnas = db["miRNAs"]
725
+ energies = db["binding_energy"]
726
+ changes = db["expression_change"]
727
+ seeds = db["seed_match"]
728
+
729
+ fig, axes = plt.subplots(1, 2, figsize=(11, 4), facecolor="white")
730
+
731
+ # Binding energy bar chart
732
+ colors_e = ["#d73027" if e < -16 else "#fc8d59" if e < -13 else "#4393c3" for e in energies]
733
+ axes[0].barh(mirnas, [-e for e in energies], color=colors_e, edgecolor="white")
734
+ axes[0].set_xlabel("Binding Energy (|kcal/mol|)", fontsize=10)
735
+ axes[0].set_title(f"Predicted Binding Energy\n{gene} miRNA targets", fontsize=10)
736
+ axes[0].set_facecolor("white")
737
+
738
+ # Expression change
739
+ colors_x = ["#d73027" if c < 0 else "#4393c3" for c in changes]
740
+ axes[1].barh(mirnas, changes, color=colors_x, edgecolor="white")
741
+ axes[1].axvline(0, color="black", linewidth=0.8)
742
+ axes[1].set_xlabel("Expression Change (log2FC)", fontsize=10)
743
+ axes[1].set_title(f"miRNA Expression in {gene}-mutant tumors\n(⚠️ SIMULATED)", fontsize=10)
744
+ axes[1].set_facecolor("white")
745
+
746
+ fig.tight_layout()
747
+ buf = io.BytesIO()
748
+ fig.savefig(buf, format="png", dpi=150, facecolor="white")
749
+ buf.seek(0)
750
+ img = Image.open(buf)
751
+ plt.close(fig)
752
+
753
+ df = pd.DataFrame({
754
+ "miRNA": mirnas,
755
+ "Binding Energy (kcal/mol)": energies,
756
+ "Seed Match": seeds,
757
+ "Expression log2FC": changes,
758
+ })
759
+ context = f"\n\n**Cancer Context:** {db['cancer_context']}"
760
+ journal_log("B1-miRNA", f"gene={gene}", f"top_miRNA={mirnas[0]}")
761
+ return img, df.to_markdown(index=False) + context
762
+
763
+
764
+ # ── TAB B2 — siRNA Targets ───────────────────
765
+
766
+ SIRNA_DB = {
767
+ "LUAD": {
768
+ "targets": ["KRAS G12C", "EGFR exon19del", "ALK fusion", "MET exon14", "RET fusion"],
769
+ "efficacy": [0.82, 0.91, 0.76, 0.68, 0.71],
770
+ "off_target_risk": ["Medium", "Low", "Low", "Medium", "Low"],
771
+ "delivery_challenge": ["High", "Medium", "Medium", "High", "Medium"],
772
+ },
773
+ "BRCA": {
774
+ "targets": ["BRCA1 exon11", "BRCA2 exon11", "PIK3CA H1047R", "AKT1 E17K", "ESR1 Y537S"],
775
+ "efficacy": [0.78, 0.85, 0.88, 0.72, 0.65],
776
+ "off_target_risk": ["Low", "Low", "Medium", "Low", "High"],
777
+ "delivery_challenge": ["Medium", "Medium", "Low", "Low", "High"],
778
+ },
779
+ "COAD": {
780
+ "targets": ["KRAS G12D", "APC truncation", "BRAF V600E", "SMAD4 loss", "PIK3CA E545K"],
781
+ "efficacy": [0.79, 0.61, 0.93, 0.55, 0.84],
782
+ "off_target_risk": ["Medium", "High", "Low", "Medium", "Low"],
783
+ "delivery_challenge": ["High", "High", "Low", "High", "Low"],
784
+ },
785
+ }
786
+
787
+ def b2_run(cancer: str):
788
+ db = SIRNA_DB.get(cancer, {})
789
+ if not db:
790
+ return None, "Cancer type not in simulation database."
791
+
792
+ targets = db["targets"]
793
+ efficacy = db["efficacy"]
794
+ off_risk = db["off_target_risk"]
795
+ delivery = db["delivery_challenge"]
796
+
797
+ fig, ax = plt.subplots(figsize=(8, 4), facecolor="white")
798
+ risk_color = {"Low": "#4393c3", "Medium": "#fc8d59", "High": "#d73027"}
799
+ colors = [risk_color.get(r, "#aaa") for r in off_risk]
800
+ bars = ax.barh(targets, efficacy, color=colors, edgecolor="white")
801
+ ax.set_xlim(0, 1.1)
802
+ ax.set_xlabel("Predicted siRNA Efficacy (⚠️ SIMULATED)", fontsize=10)
803
+ ax.set_title(f"siRNA Target Efficacy — {cancer}", fontsize=11)
804
+ ax.set_facecolor("white")
805
+ from matplotlib.patches import Patch
806
+ legend_elements = [Patch(facecolor=v, label=k) for k, v in risk_color.items()]
807
+ ax.legend(handles=legend_elements, title="Off-target Risk", fontsize=8, loc="lower right")
808
+ fig.tight_layout()
809
+
810
+ buf = io.BytesIO()
811
+ fig.savefig(buf, format="png", dpi=150, facecolor="white")
812
+ buf.seek(0)
813
+ img = Image.open(buf)
814
+ plt.close(fig)
815
+
816
+ df = pd.DataFrame({
817
+ "Target": targets,
818
+ "Efficacy": efficacy,
819
+ "Off-target Risk": off_risk,
820
+ "Delivery Challenge": delivery,
821
+ })
822
+ journal_log("B2-siRNA", f"cancer={cancer}", f"top={targets[0]}")
823
+ return img, df.to_markdown(index=False)
824
+
825
+
826
+ # ── TAB B3 — LNP Corona Simulator ───────────────
827
+
828
+ def b3_run(peg_mol_pct: float, ionizable_pct: float, helper_pct: float,
829
+ chol_pct: float, particle_size_nm: float, serum_pct: float):
830
+ """Simulate protein corona composition based on LNP formulation parameters."""
831
+ # Rule-based model (educational only)
832
+ # Higher PEG → less corona; higher ionizable → more ApoE; larger size → more fibrinogen
833
+ total_lipid = peg_mol_pct + ionizable_pct + helper_pct + chol_pct
834
+ peg_norm = peg_mol_pct / max(total_lipid, 1)
835
+
836
+ corona_proteins = {
837
+ "ApoE": max(0, 0.35 - peg_norm * 0.8 + ionizable_pct * 0.01),
838
+ "ApoA-I": max(0, 0.20 - ionizable_pct * 0.005 + chol_pct * 0.003),
839
+ "Fibrinogen": max(0, 0.15 + (particle_size_nm - 100) * 0.001 - peg_norm * 0.3),
840
+ "Albumin": max(0, 0.10 + serum_pct * 0.002 - peg_norm * 0.2),
841
+ "Clusterin": max(0, 0.08 + peg_norm * 0.15),
842
+ "IgG": max(0, 0.07 + serum_pct * 0.001),
843
+ "Complement C3": max(0, 0.05 + ionizable_pct * 0.003 - peg_norm * 0.1),
844
+ }
845
+ total = sum(corona_proteins.values())
846
+ if total > 0:
847
+ corona_proteins = {k: v / total for k, v in corona_proteins.items()}
848
+
849
+ fig, axes = plt.subplots(1, 2, figsize=(11, 4), facecolor="white")
850
+
851
+ # Pie chart
852
+ labels = list(corona_proteins.keys())
853
+ sizes = list(corona_proteins.values())
854
+ colors_pie = plt.cm.Set2(np.linspace(0, 1, len(labels)))
855
+ axes[0].pie(sizes, labels=labels, colors=colors_pie, autopct="%1.1f%%", startangle=90)
856
+ axes[0].set_title("Predicted Corona Composition\n(⚠️ SIMULATED)", fontsize=10)
857
+
858
+ # Bar chart
859
+ axes[1].bar(labels, sizes, color=colors_pie, edgecolor="white")
860
+ axes[1].set_ylabel("Relative Abundance", fontsize=10)
861
+ axes[1].set_title("Corona Protein Fractions", fontsize=10)
862
+ axes[1].set_xticklabels(labels, rotation=45, ha="right", fontsize=8)
863
+ axes[1].set_facecolor("white")
864
+
865
+ fig.tight_layout()
866
+ buf = io.BytesIO()
867
+ fig.savefig(buf, format="png", dpi=150, facecolor="white")
868
+ buf.seek(0)
869
+ img = Image.open(buf)
870
+ plt.close(fig)
871
+
872
+ apoe_pct = corona_proteins.get("ApoE", 0) * 100
873
+ interpretation = (
874
+ f"**ApoE fraction: {apoe_pct:.1f}%** — "
875
+ + ("High ApoE → enhanced brain/liver targeting via LDLR pathway." if apoe_pct > 25
876
+ else "Low ApoE → reduced receptor-mediated uptake.")
877
+ )
878
+ journal_log("B3-LNPCorona", f"PEG={peg_mol_pct}%,size={particle_size_nm}nm", f"ApoE={apoe_pct:.1f}%")
879
+ return img, interpretation
880
+
881
+
882
+ # ── TAB B4 — Flow Corona (Vroman Kinetics) ──────
883
+
884
+ def b4_run(time_points: int, kon_albumin: float, kon_apoe: float,
885
+ koff_albumin: float, koff_apoe: float):
886
+ """Simulate Vroman effect: competitive protein adsorption kinetics."""
887
+ t = np.linspace(0, time_points, 500)
888
+
889
+ # Simple Langmuir competitive adsorption model (educational)
890
+ # Albumin: fast on, fast off (early corona)
891
+ # ApoE: slow on, slow off (late/hard corona)
892
+ albumin = (kon_albumin / (kon_albumin + koff_albumin)) * (1 - np.exp(-(kon_albumin + koff_albumin) * t))
893
+ apoe_delay = np.maximum(0, t - 5)
894
+ apoe = (kon_apoe / (kon_apoe + koff_apoe)) * (1 - np.exp(-(kon_apoe + koff_apoe) * apoe_delay))
895
+ # Vroman displacement: albumin decreases as ApoE increases
896
+ albumin_displaced = albumin * np.exp(-apoe * 2)
897
+ fibrinogen = 0.3 * (1 - np.exp(-0.05 * t)) * np.exp(-apoe * 1.5)
898
+
899
+ fig, ax = plt.subplots(figsize=(9, 4), facecolor="white")
900
+ ax.plot(t, albumin_displaced, label="Albumin (displaced)", color="#4393c3", linewidth=2)
901
+ ax.plot(t, apoe, label="ApoE (hard corona)", color="#d73027", linewidth=2)
902
+ ax.plot(t, fibrinogen, label="Fibrinogen", color="#fc8d59", linewidth=2, linestyle="--")
903
+ ax.set_xlabel("Time (min)", fontsize=11)
904
+ ax.set_ylabel("Surface Coverage (a.u.)", fontsize=11)
905
+ ax.set_title("Vroman Effect — Competitive Protein Adsorption\n(⚠️ SIMULATED)", fontsize=11)
906
+ ax.legend(fontsize=9)
907
+ ax.set_facecolor("white")
908
+ fig.tight_layout()
909
+
910
+ buf = io.BytesIO()
911
+ fig.savefig(buf, format="png", dpi=150, facecolor="white")
912
+ buf.seek(0)
913
+ img = Image.open(buf)
914
+ plt.close(fig)
915
+
916
+ vroman_time = t[np.argmax(albumin_displaced > apoe * 0.9)] if any(albumin_displaced > apoe * 0.9) else "N/A"
917
+ note = (
918
+ f"**Vroman crossover** (albumin → ApoE dominance): ~{vroman_time:.1f} min\n\n"
919
+ "The Vroman effect describes sequential protein displacement: "
920
+ "abundant proteins (albumin) adsorb first, then are displaced by higher-affinity proteins (ApoE, fibrinogen)."
921
+ )
922
+ journal_log("B4-FlowCorona", f"kon_alb={kon_albumin},kon_apoe={kon_apoe}", note[:80])
923
+ return img, note
924
+
925
+
926
+ # ── TAB B5 — Variant Concepts ───────────────────
927
+
928
+ VARIANT_RULES = {
929
+ "Pathogenic": {
930
+ "criteria": ["Nonsense mutation in tumor suppressor", "Frameshift in BRCA1/2",
931
+ "Splice site ±1/2 in essential gene", "Known hotspot (e.g. TP53 R175H)"],
932
+ "acmg_codes": ["PVS1", "PS1", "PS2", "PM2"],
933
+ "explanation": "Strong evidence of pathogenicity. Likely disrupts protein function via LOF or dominant-negative mechanism.",
934
+ },
935
+ "Likely Pathogenic": {
936
+ "criteria": ["Missense in functional domain", "In silico tools predict damaging",
937
+ "Low population frequency (<0.01%)", "Segregates with disease"],
938
+ "acmg_codes": ["PM1", "PM2", "PP2", "PP3"],
939
+ "explanation": "Moderate-strong evidence. Functional studies or segregation data would upgrade to Pathogenic.",
940
+ },
941
+ "VUS": {
942
+ "criteria": ["Missense with conflicting evidence", "Moderate population frequency",
943
+ "Uncertain functional impact", "Limited segregation data"],
944
+ "acmg_codes": ["PM2", "BP4", "BP6"],
945
+ "explanation": "Variant of Uncertain Significance. Insufficient evidence to classify. Functional assays recommended.",
946
+ },
947
+ "Likely Benign": {
948
+ "criteria": ["Common in population (>1%)", "Synonymous with no splicing impact",
949
+ "Observed in healthy controls", "Computational tools predict benign"],
950
+ "acmg_codes": ["BS1", "BP1", "BP4", "BP7"],
951
+ "explanation": "Evidence suggests benign. Unlikely to cause disease but not fully excluded.",
952
+ },
953
+ "Benign": {
954
+ "criteria": ["High population frequency (>5%)", "No disease association in large studies",
955
+ "Synonymous, no functional impact", "Functional studies show no effect"],
956
+ "acmg_codes": ["BA1", "BS1", "BS2", "BS3"],
957
+ "explanation": "Strong evidence of benign nature. Not expected to contribute to disease.",
958
+ },
959
+ }
960
+
961
+ def b5_run(classification: str):
962
+ data = VARIANT_RULES.get(classification, {})
963
+ if not data:
964
+ return "Classification not found."
965
+
966
+ criteria_md = "\n".join([f"- {c}" for c in data["criteria"]])
967
+ acmg_md = " | ".join([f"`{code}`" for code in data["acmg_codes"]])
968
+ output = (
969
+ f"## {classification}\n\n"
970
+ f"**ACMG/AMP Codes:** {acmg_md}\n\n"
971
+ f"**Typical Criteria:**\n{criteria_md}\n\n"
972
+ f"**Interpretation:** {data['explanation']}\n\n"
973
+ f"> ⚠️ SIMULATED — This is a rule-based educational model only. "
974
+ f"Real variant classification requires expert review and full ACMG/AMP criteria evaluation."
975
+ )
976
+ journal_log("B5-VariantConcepts", f"class={classification}", output[:100])
977
+ return output
978
+
979
+
980
+ # ─────────────────────────────────────────────
981
+ # GRADIO UI ASSEMBLY
982
+ # ─────────────────────────────────────────────
983
+
984
+ CUSTOM_CSS = """
985
+ body { font-family: 'Inter', sans-serif; }
986
+ .simulated-banner {
987
+ background: #fff3cd; border: 1px solid #ffc107;
988
+ border-radius: 6px; padding: 10px 14px;
989
+ font-weight: 600; color: #856404; margin-bottom: 8px;
990
+ }
991
+ .source-note { color: #6c757d; font-size: 0.85em; margin-top: 6px; }
992
+ .gap-card {
993
+ background: #f8f9fa; border-left: 4px solid #d73027;
994
+ padding: 10px 14px; margin: 6px 0; border-radius: 4px;
995
+ }
996
+ footer { display: none !important; }
997
+ """
998
+
999
+ def build_journal_sidebar():
1000
+ with gr.Column(scale=1, min_width=260):
1001
+ gr.Markdown("## 📓 Lab Journal")
1002
+ note_input = gr.Textbox(label="Add note", placeholder="Your observation...", lines=2)
1003
+ save_btn = gr.Button("💾 Save Note", size="sm")
1004
+ refresh_btn = gr.Button("🔄 Refresh Journal", size="sm")
1005
+ journal_display = gr.Markdown(value="*Click Refresh to load entries.*")
1006
+
1007
+ def save_note(note):
1008
+ if note.strip():
1009
+ journal_log("Manual", "note", note.strip(), note.strip())
1010
+ return journal_read()
1011
+
1012
+ save_btn.click(save_note, inputs=[note_input], outputs=[journal_display])
1013
+ refresh_btn.click(lambda: journal_read(), outputs=[journal_display])
1014
+ return note_input, journal_display
1015
+
1016
+
1017
+ def build_app():
1018
+ with gr.Blocks(css=CUSTOM_CSS, title="K R&D Lab — Cancer Research Suite") as demo:
1019
+ gr.Markdown(
1020
+ "# 🔬 K R&D Lab — Cancer Research Suite\n"
1021
+ "**Author:** Oksana Kolisnyk | [kosatiks-group.pp.ua](https://kosatiks-group.pp.ua) \n"
1022
+ "**Repo:** [github.com/TEZv/K-RnD-Lab-PHYLO-03_2026](https://github.com/TEZv/K-RnD-Lab-PHYLO-03_2026)"
1023
+ )
1024
+
1025
+ with gr.Row():
1026
+ # ── MAIN CONTENT ──
1027
+ with gr.Column(scale=4):
1028
+ with gr.Tabs():
1029
+
1030
+ # ════════════════════════════════
1031
+ # GROUP A — REAL DATA TOOLS
1032
+ # ════════════════════════════════
1033
+ with gr.Tab("🔬 Real Data Tools"):
1034
+ with gr.Tabs():
1035
+
1036
+ # ── A1 ──
1037
+ with gr.Tab("🔍 Gray Zones Explorer"):
1038
+ gr.Markdown(
1039
+ "Identify underexplored biological processes in a cancer type "
1040
+ "using live PubMed + OpenTargets data."
1041
+ )
1042
+ a1_cancer = gr.Dropdown(CANCER_TYPES, label="Cancer Type", value="GBM")
1043
+ a1_btn = gr.Button("🔍 Explore Gray Zones", variant="primary")
1044
+ a1_heatmap = gr.Image(label="Research Coverage Heatmap", type="pil")
1045
+ a1_gaps = gr.Markdown(label="Top 5 Research Gaps")
1046
+ with gr.Accordion("📖 Learning Mode", open=False):
1047
+ gr.Markdown(
1048
+ "**What is a research gray zone?**\n\n"
1049
+ "A gray zone is a biological process that is well-studied in other cancers "
1050
+ "but has very few publications in your selected cancer type. "
1051
+ "Low paper counts (red/white cells) indicate potential unexplored territory.\n\n"
1052
+ "**How to use:** Select a rare cancer (e.g. DIPG, MCC) to find the most "
1053
+ "underexplored processes. Cross-reference with Tab A2 to find targetable genes."
1054
+ )
1055
+ a1_btn.click(a1_run, inputs=[a1_cancer], outputs=[a1_heatmap, a1_gaps])
1056
+
1057
+ # ── A2 ──
1058
+ with gr.Tab("🎯 Understudied Target Finder"):
1059
+ gr.Markdown(
1060
+ "Find essential genes with high research gap index "
1061
+ "(high essentiality, low publication coverage)."
1062
+ )
1063
+ gr.Markdown(
1064
+ "> ⚠️ **Essentiality scores are placeholder estimates** from a "
1065
+ "curated reference gene set — **not real DepMap data**. "
1066
+ "Association scores and paper/trial counts are fetched live. "
1067
+ "For real essentiality values, download `CRISPR_gene_effect.csv` "
1068
+ "from [depmap.org](https://depmap.org/portal/download/all/) and "
1069
+ "replace `_load_depmap_sample()` in `app.py`."
1070
+ )
1071
+ a2_cancer = gr.Dropdown(CANCER_TYPES, label="Cancer Type", value="GBM")
1072
+ a2_btn = gr.Button("🎯 Find Understudied Targets", variant="primary")
1073
+ a2_table = gr.Dataframe(label="Target Gap Table", wrap=True)
1074
+ a2_note = gr.Markdown()
1075
+ with gr.Accordion("📖 Learning Mode", open=False):
1076
+ gr.Markdown(
1077
+ "**Gap Index formula:** `essentiality / log(papers + 1)`\n\n"
1078
+ "- **Essentiality**: inverted DepMap CRISPR gene effect score "
1079
+ "(positive = more essential, per DepMap convention where negative raw = essential)\n"
1080
+ "- **Papers**: PubMed count for gene + cancer type\n"
1081
+ "- **High Gap Index** = essential gene with few publications = high research opportunity\n\n"
1082
+ "**Caution:** Essentiality scores shown here use a curated reference set. "
1083
+ "For full DepMap analysis, download the complete dataset from depmap.org."
1084
+ )
1085
+ a2_btn.click(a2_run, inputs=[a2_cancer], outputs=[a2_table, a2_note])
1086
+
1087
+ # ── A3 ──
1088
+ with gr.Tab("🧬 Real Variant Lookup"):
1089
+ gr.Markdown(
1090
+ "Look up a variant in **ClinVar** and **gnomAD**. "
1091
+ "Results are fetched live — never hallucinated."
1092
+ )
1093
+ a3_hgvs = gr.Textbox(
1094
+ label="HGVS Notation",
1095
+ placeholder="e.g. NM_007294.4:c.5266dupC or NM_000546.6:c.524G>A",
1096
+ lines=1
1097
+ )
1098
+ a3_btn = gr.Button("🔎 Look Up Variant", variant="primary")
1099
+ a3_result = gr.Markdown()
1100
+ with gr.Accordion("📖 Learning Mode", open=False):
1101
+ gr.Markdown(
1102
+ "**HGVS notation format:**\n"
1103
+ "- `NM_XXXXXX.X:c.NNNN[change]` — coding DNA reference\n"
1104
+ "- `NC_XXXXXX.X:g.NNNN[change]` — genomic reference\n\n"
1105
+ "**ClinVar** classifies variants as: Pathogenic / Likely Pathogenic / "
1106
+ "VUS / Likely Benign / Benign\n\n"
1107
+ "**gnomAD** provides allele frequency (AF) in population cohorts. "
1108
+ "AF > 1% generally suggests benign.\n\n"
1109
+ "**Important:** If a variant is not found, this tool returns "
1110
+ "'Not in database. Do not interpret.' — never a fabricated result."
1111
+ )
1112
+ a3_btn.click(a3_run, inputs=[a3_hgvs], outputs=[a3_result])
1113
+
1114
+ # ── A4 ──
1115
+ with gr.Tab("📰 Literature Gap Finder"):
1116
+ gr.Markdown(
1117
+ "Visualize publication trends over 10 years and detect "
1118
+ "years with low research activity."
1119
+ )
1120
+ with gr.Row():
1121
+ a4_cancer = gr.Dropdown(CANCER_TYPES, label="Cancer Type", value="GBM")
1122
+ a4_kw = gr.Textbox(label="Keyword", placeholder="e.g. ferroptosis", lines=1)
1123
+ a4_btn = gr.Button("📊 Analyze Literature Trend", variant="primary")
1124
+ a4_chart = gr.Image(label="Papers per Year", type="pil")
1125
+ a4_gaps = gr.Markdown()
1126
+ with gr.Accordion("📖 Learning Mode", open=False):
1127
+ gr.Markdown(
1128
+ "**How to read the chart:**\n"
1129
+ "- 🔵 Blue bars = normal activity\n"
1130
+ "- 🟠 Orange bars = low activity (<30% of average)\n"
1131
+ "- 🔴 Red bars = zero publications (true gap)\n\n"
1132
+ "**Research strategy:** A gap in 2018–2020 followed by a spike in 2022+ "
1133
+ "may indicate a recently emerging field — ideal for early-career researchers."
1134
+ )
1135
+ a4_btn.click(a4_run, inputs=[a4_cancer, a4_kw], outputs=[a4_chart, a4_gaps])
1136
+
1137
+ # ── A5 ──
1138
+ with gr.Tab("💊 Druggable Orphans"):
1139
+ gr.Markdown(
1140
+ "Identify cancer-associated essential genes with **no approved drug** "
1141
+ "and **no active clinical trial**."
1142
+ )
1143
+ a5_cancer = gr.Dropdown(CANCER_TYPES, label="Cancer Type", value="GBM")
1144
+ a5_btn = gr.Button("💊 Find Druggable Orphans", variant="primary")
1145
+ a5_table = gr.Dataframe(label="Orphan Target Table", wrap=True)
1146
+ a5_note = gr.Markdown()
1147
+ with gr.Accordion("📖 Learning Mode", open=False):
1148
+ gr.Markdown(
1149
+ "**What is a druggable orphan?**\n\n"
1150
+ "A gene that is:\n"
1151
+ "1. Strongly associated with a cancer (high OpenTargets score)\n"
1152
+ "2. Has no approved drug targeting it\n"
1153
+ "3. Has no active clinical trial\n\n"
1154
+ "These represent the highest-opportunity targets for drug discovery. "
1155
+ "Cross-reference with Tab A2 (Gap Index) for prioritization."
1156
+ )
1157
+ a5_btn.click(a5_run, inputs=[a5_cancer], outputs=[a5_table, a5_note])
1158
+
1159
+ # ── A6 (RAG Chatbot — injected from chatbot.py) ──
1160
+ with gr.Tab("🤖 Research Assistant"):
1161
+ gr.Markdown(
1162
+ "**RAG-powered research assistant** indexed on 20 curated papers "
1163
+ "on LNP delivery, protein corona, and cancer variants.\n\n"
1164
+ "*Powered by sentence-transformers + FAISS — no API key required.*"
1165
+ )
1166
+ try:
1167
+ from chatbot import build_chatbot_tab
1168
+ build_chatbot_tab()
1169
+ except ImportError:
1170
+ gr.Markdown(
1171
+ "⚠️ `chatbot.py` not found. Please ensure it is in the same directory as `app.py`. "
1172
+ "See `chatbot.py` for setup instructions."
1173
+ )
1174
+
1175
+ # ════════════════════════════════
1176
+ # GROUP B — LEARNING SANDBOX
1177
+ # ════════════════════════════════
1178
+ with gr.Tab("📚 Learning Sandbox"):
1179
+ gr.Markdown(
1180
+ "> ⚠️ **ALL TABS IN THIS GROUP USE SIMULATED DATA** — "
1181
+ "For educational purposes only. Results do not reflect real experiments."
1182
+ )
1183
+ with gr.Tabs():
1184
+
1185
+ # ── B1 ──
1186
+ with gr.Tab("🧬 miRNA Explorer"):
1187
+ gr.Markdown(SIMULATED_BANNER)
1188
+ b1_gene = gr.Dropdown(["BRCA2", "BRCA1", "TP53"], label="Gene", value="TP53")
1189
+ b1_btn = gr.Button("🔬 Explore miRNA Interactions", variant="primary")
1190
+ b1_plot = gr.Image(label="miRNA Binding & Expression (⚠️ SIMULATED)", type="pil")
1191
+ b1_table = gr.Markdown()
1192
+ with gr.Accordion("📖 Learning Mode", open=False):
1193
+ gr.Markdown(
1194
+ "**miRNA biology basics:**\n\n"
1195
+ "- miRNAs are ~22 nt non-coding RNAs that bind 3'UTR of mRNAs\n"
1196
+ "- Seed match types: 8mer > 7mer-m8 > 7mer-A1 > 6mer (binding strength)\n"
1197
+ "- Negative binding energy = stronger predicted interaction\n"
1198
+ "- Negative log2FC = miRNA downregulated in tumor\n\n"
1199
+ "**Key concept:** Tumor suppressor genes (BRCA1/2, TP53) are often "
1200
+ "silenced by oncogenic miRNAs (e.g. miR-21, miR-155)."
1201
+ )
1202
+ b1_btn.click(b1_run, inputs=[b1_gene], outputs=[b1_plot, b1_table])
1203
+
1204
+ # ── B2 ──
1205
+ with gr.Tab("🎯 siRNA Targets"):
1206
+ gr.Markdown(SIMULATED_BANNER)
1207
+ b2_cancer = gr.Dropdown(["LUAD", "BRCA", "COAD"], label="Cancer Type", value="LUAD")
1208
+ b2_btn = gr.Button("🎯 Simulate siRNA Efficacy", variant="primary")
1209
+ b2_plot = gr.Image(label="siRNA Efficacy (⚠️ SIMULATED)", type="pil")
1210
+ b2_table = gr.Markdown()
1211
+ with gr.Accordion("📖 Learning Mode", open=False):
1212
+ gr.Markdown(
1213
+ "**siRNA design principles:**\n\n"
1214
+ "- siRNAs are 21-23 nt dsRNA that trigger RISC-mediated mRNA cleavage\n"
1215
+ "- Off-target risk: seed region complementarity to unintended mRNAs\n"
1216
+ "- Delivery challenge: endosomal escape, serum stability, tumor penetration\n\n"
1217
+ "**Clinical context:** KRAS siRNA delivery remains a major challenge "
1218
+ "due to the undruggable nature of the RAS binding pocket."
1219
+ )
1220
+ b2_btn.click(b2_run, inputs=[b2_cancer], outputs=[b2_plot, b2_table])
1221
+
1222
+ # ── B3 ──
1223
+ with gr.Tab("🧪 LNP Corona"):
1224
+ gr.Markdown(SIMULATED_BANNER)
1225
+ with gr.Row():
1226
+ b3_peg = gr.Slider(0.5, 5.0, value=1.5, step=0.1, label="PEG mol% (lipid)")
1227
+ b3_ion = gr.Slider(10, 60, value=50, step=1, label="Ionizable lipid mol%")
1228
+ with gr.Row():
1229
+ b3_helper = gr.Slider(5, 30, value=10, step=1, label="Helper lipid mol%")
1230
+ b3_chol = gr.Slider(10, 50, value=38, step=1, label="Cholesterol mol%")
1231
+ with gr.Row():
1232
+ b3_size = gr.Slider(50, 300, value=100, step=5, label="Particle size (nm)")
1233
+ b3_serum = gr.Slider(0, 100, value=10, step=5, label="Serum % in medium")
1234
+ b3_btn = gr.Button("🧪 Simulate Corona", variant="primary")
1235
+ b3_plot = gr.Image(label="Corona Composition (⚠️ SIMULATED)", type="pil")
1236
+ b3_interp = gr.Markdown()
1237
+ with gr.Accordion("📖 Learning Mode", open=False):
1238
+ gr.Markdown(
1239
+ "**Protein corona basics:**\n\n"
1240
+ "- When nanoparticles enter biological fluids, proteins adsorb to their surface\n"
1241
+ "- **Hard corona**: tightly bound, long-lived proteins (ApoE, fibrinogen)\n"
1242
+ "- **Soft corona**: loosely bound, rapidly exchanging proteins (albumin)\n"
1243
+ "- **ApoE enrichment** → enhanced brain targeting via LDLR/LRP1 receptors\n"
1244
+ "- **PEG** reduces corona formation but may trigger anti-PEG antibodies\n\n"
1245
+ "**GBM relevance:** ApoE-enriched LNPs show improved BBB crossing in preclinical models."
1246
+ )
1247
+ b3_btn.click(
1248
+ b3_run,
1249
+ inputs=[b3_peg, b3_ion, b3_helper, b3_chol, b3_size, b3_serum],
1250
+ outputs=[b3_plot, b3_interp]
1251
+ )
1252
+
1253
+ # ── B4 ──
1254
+ with gr.Tab("🌊 Flow Corona"):
1255
+ gr.Markdown(SIMULATED_BANNER)
1256
+ with gr.Row():
1257
+ b4_time = gr.Slider(10, 120, value=60, step=5, label="Time range (min)")
1258
+ b4_kon_alb = gr.Slider(0.01, 1.0, value=0.3, step=0.01, label="kon Albumin")
1259
+ with gr.Row():
1260
+ b4_kon_apoe = gr.Slider(0.001, 0.5, value=0.05, step=0.001, label="kon ApoE")
1261
+ b4_koff_alb = gr.Slider(0.01, 1.0, value=0.2, step=0.01, label="koff Albumin")
1262
+ b4_koff_apoe = gr.Slider(0.001, 0.1, value=0.01, step=0.001, label="koff ApoE")
1263
+ b4_btn = gr.Button("🌊 Simulate Vroman Kinetics", variant="primary")
1264
+ b4_plot = gr.Image(label="Vroman Effect (⚠️ SIMULATED)", type="pil")
1265
+ b4_note = gr.Markdown()
1266
+ with gr.Accordion("📖 Learning Mode", open=False):
1267
+ gr.Markdown(
1268
+ "**The Vroman Effect:**\n\n"
1269
+ "Described by Leo Vroman (1962): proteins with high abundance but low affinity "
1270
+ "(albumin) adsorb first, then are displaced by lower-abundance but higher-affinity "
1271
+ "proteins (fibrinogen, ApoE).\n\n"
1272
+ "**Parameters:**\n"
1273
+ "- **kon**: association rate constant (higher = faster binding)\n"
1274
+ "- **koff**: dissociation rate constant (lower = tighter binding)\n"
1275
+ "- **Kd = koff/kon**: equilibrium dissociation constant\n\n"
1276
+ "**Clinical implication:** The final hard corona (not initial) determines "
1277
+ "nanoparticle fate in vivo."
1278
+ )
1279
+ b4_btn.click(
1280
+ b4_run,
1281
+ inputs=[b4_time, b4_kon_alb, b4_kon_apoe, b4_koff_alb, b4_koff_apoe],
1282
+ outputs=[b4_plot, b4_note]
1283
+ )
1284
+
1285
+ # ── B5 ──
1286
+ with gr.Tab("🔬 Variant Concepts"):
1287
+ gr.Markdown(SIMULATED_BANNER)
1288
+ b5_class = gr.Dropdown(
1289
+ list(VARIANT_RULES.keys()),
1290
+ label="ACMG Classification",
1291
+ value="VUS"
1292
+ )
1293
+ b5_btn = gr.Button("📋 Explain Classification", variant="primary")
1294
+ b5_result = gr.Markdown()
1295
+ with gr.Accordion("📖 Learning Mode", open=False):
1296
+ gr.Markdown(
1297
+ "**ACMG/AMP 2015 Classification Framework:**\n\n"
1298
+ "Variants are classified into 5 tiers based on evidence:\n"
1299
+ "1. **Pathogenic** — strong evidence of disease causation\n"
1300
+ "2. **Likely Pathogenic** — >90% probability pathogenic\n"
1301
+ "3. **VUS** — uncertain significance; insufficient evidence\n"
1302
+ "4. **Likely Benign** — >90% probability benign\n"
1303
+ "5. **Benign** — strong evidence of no disease effect\n\n"
1304
+ "**Key codes:** PVS1 (null variant), PS1 (same AA change), "
1305
+ "PM2 (absent from controls), BA1 (MAF >5%)"
1306
+ )
1307
+ b5_btn.click(b5_run, inputs=[b5_class], outputs=[b5_result])
1308
+
1309
+ # ── SIDEBAR ──
1310
+ with gr.Column(scale=1, min_width=260):
1311
+ gr.Markdown("## 📓 Lab Journal")
1312
+ note_input = gr.Textbox(label="Add note", placeholder="Your observation...", lines=2)
1313
+ save_btn = gr.Button("💾 Save Note", size="sm")
1314
+ refresh_btn = gr.Button("🔄 Refresh Journal", size="sm")
1315
+ journal_display = gr.Markdown(value="*Click Refresh to load entries.*")
1316
+
1317
+ def save_note(note):
1318
+ if note.strip():
1319
+ journal_log("Manual", "note", note.strip(), note.strip())
1320
+ return journal_read()
1321
+
1322
+ save_btn.click(save_note, inputs=[note_input], outputs=[journal_display])
1323
+ refresh_btn.click(lambda: journal_read(), outputs=[journal_display])
1324
+
1325
+ gr.Markdown(
1326
+ "---\n"
1327
+ "*K R&D Lab Cancer Research Suite · "
1328
+ "All real-data tabs use live APIs with 24h caching · "
1329
+ "Simulated tabs are clearly labeled ⚠️ SIMULATED · "
1330
+ "Source attribution shown on every result*"
1331
+ )
1332
+
1333
+ return demo
1334
+
1335
+
1336
+ if __name__ == "__main__":
1337
+ app = build_app()
1338
+ app.launch(share=False)
chatbot.py ADDED
@@ -0,0 +1,672 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ K R&D Lab — Research Assistant (RAG Chatbot)
3
+ Author: Oksana Kolisnyk | kosatiks-group.pp.ua
4
+ Repo: github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
5
+
6
+ RAG pipeline: sentence-transformers + FAISS (no API key required)
7
+ Indexed on 20 curated papers: LNP delivery, protein corona, cancer variants
8
+ Confidence flags: HIGH / MEDIUM / SPECULATIVE
9
+ Never answers outside indexed papers.
10
+ """
11
+
12
+ import os
13
+ import json
14
+ import time
15
+ import hashlib
16
+ import datetime
17
+ import requests
18
+ import gradio as gr
19
+ import numpy as np
20
+
21
+ # ─────────────────────────────────────────────
22
+ # PAPER CORPUS — 20 curated PMIDs
23
+ # Topics: LNP/brain delivery, protein corona, cancer variants
24
+ # ─────────────────────────────────────────────
25
+
26
+ PAPER_PMIDS = [
27
+ # LNP delivery (5) — all PubMed-verified
28
+ "34394960", # Hou X — LNP mRNA delivery review (Nat Rev Mater 2021)
29
+ "32251383", # Cheng Q — SORT LNPs organ selectivity (Nat Nanotechnol 2020)
30
+ "29653760", # Sabnis S — novel amino lipid series for mRNA (Mol Ther 2018)
31
+ "22782619", # Jayaraman M — ionizable lipid siRNA LNP potency (Angew Chem 2012)
32
+ "33208369", # Rosenblum D — CRISPR-Cas9 LNP cancer therapy (Sci Adv 2020)
33
+ # Protein corona (5)
34
+ "18809927", # Lundqvist M — nanoparticle size/surface protein corona (PNAS 2008)
35
+ "22086677", # Walkey CD — nanomaterial-protein interactions (Chem Soc Rev 2012)
36
+ "31565943", # Park M — accessible surface area within nanoparticle corona (Nano Lett 2019)
37
+ "33754708", # Sebastiani F — ApoE binding drives LNP rearrangement (ACS Nano 2021)
38
+ "20461061", # Akinc A — endogenous ApoE-mediated LNP liver delivery (Mol Ther 2010)
39
+ # Cancer variants & precision oncology (5)
40
+ "30096302", # Bailey MH — cancer driver genes TCGA (Cell 2018)
41
+ "30311387", # Landrum MJ — ClinVar at five years (Hum Mutat 2018)
42
+ "32461654", # Karczewski KJ — gnomAD mutational constraint 141,456 humans (Nature 2020)
43
+ "27328919", # Bouaoun L — TP53 variations IARC database (Hum Mutat 2016)
44
+ "31820981", # Lanman BA — KRAS G12C covalent inhibitor AMG 510 (J Med Chem 2020)
45
+ # LNP immunotherapy & siRNA (3)
46
+ "28678784", # Sahin U — personalized RNA mutanome vaccines (Nature 2017)
47
+ "31348638", # Kozma GT — anti-PEG IgM complement activation (ACS Nano 2019)
48
+ "33016924", # Cafri G — mRNA neoantigen T cell immunity GI cancer (J Clin Invest 2020)
49
+ # Liquid biopsy (2)
50
+ "31142840", # Cristiano S — genome-wide cfDNA fragmentation in cancer (Nature 2019)
51
+ "33883548", # Larson MH — cell-free transcriptome tissue biomarkers (Nat Commun 2021)
52
+ ]
53
+
54
+ # Curated abstracts / key content for each PMID
55
+ # Verified against PubMed esummary + efetch API — 2026-03-07
56
+ # All PMIDs confirmed real; abstracts fetched directly from NCBI
57
+ PAPER_CORPUS = [
58
+ {
59
+ "pmid": "34394960",
60
+ "title": "Lipid nanoparticles for mRNA delivery.",
61
+ "abstract": (
62
+ "Messenger RNA (mRNA) has emerged as a new category of therapeutic agent to prevent and treat "
63
+ "various diseases. To function in vivo, mRNA requires safe, effective and stable delivery "
64
+ "systems that protect the nucleic acid from degradation and that allow cellular uptake and "
65
+ "mRNA release. Lipid nanoparticles have successfully entered the clinic for the delivery of "
66
+ "mRNA; in particular, lipid nanoparticle-mRNA vaccines are now in clinical use against "
67
+ "coronavirus disease 2019 (COVID-19), which marks a milestone for mRNA therapeutics. In this "
68
+ "Review, we discuss the design of lipid nanoparticles for mRNA delivery and examine "
69
+ "physiological barriers and possible administration routes for lipid nanoparticle-mRNA "
70
+ "systems. We then consider key points for the clinical translation of lipid nanoparticle-mRNA "
71
+ "formulations, including good manufacturing practice, stability, storage and safety, and "
72
+ "highlight preclinical and clinical studies of lipid nanoparticle-mRNA therapeutics for "
73
+ "infectious diseases, cancer and genetic disorders. Finally, we give an outlook to future "
74
+ "possibilities and remaining challenges for this promising technology."
75
+ ),
76
+ "journal": "Nat Rev Mater",
77
+ "year": 2021,
78
+ "topic": "LNP mRNA delivery",
79
+ },
80
+ {
81
+ "pmid": "32251383",
82
+ "title": "Selective organ targeting (SORT) nanoparticles for tissue-specific mRNA delivery and CRISPR-Cas gene editing.",
83
+ "abstract": (
84
+ "CRISPR-Cas gene editing and messenger RNA-based protein replacement therapy hold tremendous "
85
+ "potential to effectively treat disease-causing mutations with diverse cellular origin. "
86
+ "However, it is currently impossible to rationally design nanoparticles that selectively "
87
+ "target specific tissues. Here, we report a strategy termed selective organ targeting (SORT) "
88
+ "wherein multiple classes of lipid nanoparticles are systematically engineered to exclusively "
89
+ "edit extrahepatic tissues via addition of a supplemental SORT molecule. Lung-, spleen- and "
90
+ "liver-targeted SORT lipid nanoparticles were designed to selectively edit therapeutically "
91
+ "relevant cell types including epithelial cells, endothelial cells, B cells, T cells and "
92
+ "hepatocytes. SORT is compatible with multiple gene editing techniques, including mRNA, Cas9 "
93
+ "mRNA/single guide RNA and Cas9 ribonucleoprotein complexes, and is envisioned to aid the "
94
+ "development of protein replacement and gene correction therapeutics in targeted tissues."
95
+ ),
96
+ "journal": "Nat Nanotechnol",
97
+ "year": 2020,
98
+ "topic": "LNP organ selectivity",
99
+ },
100
+ {
101
+ "pmid": "29653760",
102
+ "title": "A Novel Amino Lipid Series for mRNA Delivery: Improved Endosomal Escape and Sustained Pharmacology and Safety in Non-human Primates.",
103
+ "abstract": (
104
+ "The success of mRNA-based therapies depends on the availability of a safe and efficient "
105
+ "delivery vehicle. Lipid nanoparticles have been identified as a viable option. However, "
106
+ "there are concerns whether an acceptable tolerability profile for chronic dosing can be "
107
+ "achieved. The efficiency and tolerability of lipid nanoparticles has been attributed to the "
108
+ "amino lipid. Therefore, we developed a new series of amino lipids that address this concern. "
109
+ "Clear structure-activity relationships were developed that resulted in a new amino lipid "
110
+ "that affords efficient mRNA delivery in rodent and primate models with optimal "
111
+ "pharmacokinetics. A 1-month toxicology evaluation in rat and non-human primate demonstrated "
112
+ "no adverse events with the new lipid nanoparticle system. Mechanistic studies demonstrate "
113
+ "that the improved efficiency can be attributed to increased endosomal escape. This effort "
114
+ "has resulted in the first example of the ability to safely repeat dose mRNA-containing lipid "
115
+ "nanoparticles in non-human primate at therapeutically relevant levels."
116
+ ),
117
+ "journal": "Mol Ther",
118
+ "year": 2018,
119
+ "topic": "LNP ionizable lipid",
120
+ },
121
+ {
122
+ "pmid": "22782619",
123
+ "title": "Maximizing the potency of siRNA lipid nanoparticles for hepatic gene silencing in vivo.",
124
+ "abstract": (
125
+ "Special (lipid) delivery: The role of the ionizable lipid pK(a) in the in vivo delivery of "
126
+ "siRNA by lipid nanoparticles has been studied with a large number of head group "
127
+ "modifications to the lipids. A tight correlation between the lipid pK(a) value and silencing "
128
+ "of the mouse FVII gene (FVII ED(50) ) was found, with an optimal pK(a) range of 6.2-6.5. The "
129
+ "most potent cationic lipid from this study has ED(50) levels around 0.005 mg kg(-1) in mice "
130
+ "and less than 0.03 mg kg(-1) in non-human primates."
131
+ ),
132
+ "journal": "Angew Chem Int Ed Engl",
133
+ "year": 2012,
134
+ "topic": "LNP ionizable lipid siRNA",
135
+ },
136
+ {
137
+ "pmid": "33208369",
138
+ "title": "CRISPR-Cas9 genome editing using targeted lipid nanoparticles for cancer therapy.",
139
+ "abstract": (
140
+ "Harnessing CRISPR-Cas9 technology for cancer therapeutics has been hampered by low editing "
141
+ "efficiency in tumors and potential toxicity of existing delivery systems. Here, we describe "
142
+ "a safe and efficient lipid nanoparticle (LNP) for the delivery of Cas9 mRNA and sgRNAs that "
143
+ "use a novel amino-ionizable lipid. A single intracerebral injection of CRISPR-LNPs against"
144
+ ),
145
+ "journal": "Sci Adv",
146
+ "year": 2020,
147
+ "topic": "LNP cancer CRISPR",
148
+ },
149
+ {
150
+ "pmid": "18809927",
151
+ "title": "Nanoparticle size and surface properties determine the protein corona with possible implications for biological impacts.",
152
+ "abstract": (
153
+ "Nanoparticles in a biological fluid (plasma, or otherwise) associate with a range of "
154
+ "biopolymers, especially proteins, organized into the \"protein corona\" that is associated "
155
+ "with the nanoparticle and continuously exchanging with the proteins in the environment. "
156
+ "Methodologies to determine the corona and to understand its dependence on nanomaterial "
157
+ "properties are likely to become important in bionanoscience. Here, we study the long-lived "
158
+ "(\"hard\") protein corona formed from human plasma for a range of nanoparticles that differ "
159
+ "in surface properties and size. Six different polystyrene nanoparticles were studied: three "
160
+ "different surface chemistries (plain PS, carboxyl-modified, and amine-modified) and two "
161
+ "sizes of each (50 and 100 nm), enabling us to perform systematic studies of the effect of "
162
+ "surface properties and size on the detailed protein coronas. Proteins in the corona that are "
163
+ "conserved and unique across the nanoparticle types were identified and classified according "
164
+ "to the protein functional properties. Remarkably, both size and surface properties were "
165
+ "found to play a very significant role in determining the nanoparticle coronas on the "
166
+ "different particles of identical materials"
167
+ ),
168
+ "journal": "Proc Natl Acad Sci U S A",
169
+ "year": 2008,
170
+ "topic": "protein corona",
171
+ },
172
+ {
173
+ "pmid": "22086677",
174
+ "title": "Understanding and controlling the interaction of nanomaterials with proteins in a physiological environment.",
175
+ "abstract": (
176
+ "Nanomaterials hold promise as multifunctional diagnostic and therapeutic agents. However, "
177
+ "the effective application of nanomaterials is hampered by limited understanding and control "
178
+ "over their interactions with complex biological systems. When a nanomaterial enters a "
179
+ "physiological environment, it rapidly adsorbs proteins forming what is known as the protein "
180
+ "\'corona\'. The protein corona alters the size and interfacial composition of a "
181
+ "nanomaterial, giving it a biological identity that is distinct from its synthetic identity. "
182
+ "The biological identity determines the physiological response including signalling, "
183
+ "kinetics, transport, accumulation, and toxicity. The structure and composition of the "
184
+ "protein corona depends on the synthetic identity of the nanomaterial (size, shape, and "
185
+ "composition), the nature of the physiological environment (blood, interstitial fluid, cell "
186
+ "cytoplasm, etc.), and the duration of exposure. In this critical review, we discuss the "
187
+ "formation of the protein corona, its structure and composition, and its influence on the "
188
+ "physiological response. We also present an \'adsorbome\' of 125 plasma proteins that are "
189
+ "known to associate with nanomaterials. We further describe"
190
+ ),
191
+ "journal": "Chem Soc Rev",
192
+ "year": 2012,
193
+ "topic": "protein corona",
194
+ },
195
+ {
196
+ "pmid": "31565943",
197
+ "title": "Measuring the Accessible Surface Area within the Nanoparticle Corona Using Molecular Probe Adsorption.",
198
+ "abstract": (
199
+ "The corona phase-the adsorbed layer of polymer, surfactant, or stabilizer molecules around a "
200
+ "nanoparticle-is typically utilized to disperse nanoparticles into a solution or solid phase. "
201
+ "However, this phase also controls molecular access to the nanoparticle surface, a property "
202
+ "important for catalytic activity and sensor applications. Unfortunately, few methods can "
203
+ "directly probe the structure of this corona phase, which is subcategorized as either a hard, "
204
+ "immobile corona or a soft, transient corona in exchange with components in the bulk "
205
+ "solution. In this work, we introduce a molecular probe adsorption (MPA) method for measuring "
206
+ "the accessible nanoparticle surface area using a titration of a quenchable fluorescent "
207
+ "molecule. For example, riboflavin is utilized to measure the surface area of gold "
208
+ "nanoparticle standards, as well as corona phases on dispersed single-walled carbon nanotubes "
209
+ "and graphene sheets. A material balance on the titration yields certain surface coverage "
210
+ "parameters, including the ratio of the surface area to dissociation constant of the "
211
+ "fluorophore,"
212
+ ),
213
+ "journal": "Nano Lett",
214
+ "year": 2019,
215
+ "topic": "protein corona hard/soft",
216
+ },
217
+ {
218
+ "pmid": "33754708",
219
+ "title": "Apolipoprotein E Binding Drives Structural and Compositional Rearrangement of mRNA-Containing Lipid Nanoparticles.",
220
+ "abstract": (
221
+ "Emerging therapeutic treatments based on the production of proteins by delivering mRNA have "
222
+ "become increasingly important in recent times. While lipid nanoparticles (LNPs) are approved "
223
+ "vehicles for small interfering RNA delivery, there are still challenges to use this "
224
+ "formulation for mRNA delivery. LNPs are typically a mixture of a cationic lipid, "
225
+ "distearoylphosphatidylcholine (DSPC), cholesterol, and a PEG-lipid. The structural "
226
+ "characterization of mRNA-containing LNPs (mRNA-LNPs) is crucial for a full understanding of "
227
+ "the way in which they function, but this information alone is not enough to predict their "
228
+ "fate upon entering the bloodstream. The biodistribution and cellular uptake of LNPs are "
229
+ "affected by their surface composition as well as by the extracellular proteins present at "
230
+ "the site of LNP administration,"
231
+ ),
232
+ "journal": "ACS Nano",
233
+ "year": 2021,
234
+ "topic": "ApoE LNP corona",
235
+ },
236
+ {
237
+ "pmid": "20461061",
238
+ "title": "Targeted delivery of RNAi therapeutics with endogenous and exogenous ligand-based mechanisms.",
239
+ "abstract": (
240
+ "Lipid nanoparticles (LNPs) have proven to be highly efficient carriers of short-interfering "
241
+ "RNAs (siRNAs) to hepatocytes in vivo; however, the precise mechanism by which this efficient "
242
+ "delivery occurs has yet to be elucidated. We found that apolipoprotein E (apoE), which plays "
243
+ "a major role in the clearance and hepatocellular uptake of physiological lipoproteins, also "
244
+ "acts as an endogenous targeting ligand for ionizable LNPs (iLNPs), but not cationic LNPs "
245
+ "(cLNPs). The role of apoE was investigated using both in vitro studies employing recombinant "
246
+ "apoE and in vivo studies in wild-type and apoE(-/-) mice. Receptor dependence was explored "
247
+ "in vitro and in vivo using low-density lipoprotein receptor (LDLR(-/-))-deficient mice. As "
248
+ "an alternative to endogenous apoE-based targeting, we developed a targeting approach using "
249
+ "an exogenous ligand containing a multivalent N-acetylgalactosamine (GalNAc)-cluster, which "
250
+ "binds with high affinity to the asialoglycoprotein receptor (ASGPR) expressed on "
251
+ "hepatocytes. Both apoE-based endogenous and GalNAc-based exogenous targeting appear to be "
252
+ "highly effective strategies for the delivery of iLNPs to liver."
253
+ ),
254
+ "journal": "Mol Ther",
255
+ "year": 2010,
256
+ "topic": "ApoE LNP liver delivery",
257
+ },
258
+ {
259
+ "pmid": "30096302",
260
+ "title": "Comprehensive Characterization of Cancer Driver Genes and Mutations.",
261
+ "abstract": (
262
+ "[Summary — abstract not available in PubMed XML] Bailey MH et al. analyzed 9,423 tumors across 33 cancer types from TCGA to identify 299 "
263
+ "cancer driver genes using 26 computational tools. The study found that most cancers have 2-6 "
264
+ "driver gene mutations. TP53 is the most frequently mutated driver gene (42% of cancers). "
265
+ "KRAS mutations dominate in PDAC (92%), LUAD (33%), and COAD (43%). Oncogenes are "
266
+ "predominantly activated by missense mutations at hotspots; tumor suppressors are inactivated "
267
+ "by truncating mutations or deletions. The pan-cancer driver landscape varies substantially "
268
+ "across cancer types, with rare cancers often having unique driver profiles. This resource "
269
+ "provides a comprehensive reference for cancer genomics and therapeutic target "
270
+ "identification."
271
+ ),
272
+ "journal": "Cell",
273
+ "year": 2018,
274
+ "topic": "cancer driver genes",
275
+ },
276
+ {
277
+ "pmid": "30311387",
278
+ "title": "ClinVar at five years: Delivering on the promise.",
279
+ "abstract": (
280
+ "The increasing application of genetic testing for determining the causes underlying "
281
+ "Mendelian, pharmacogenetic, and somatic phenotypes has accelerated the discovery of novel "
282
+ "variants by clinical genetics laboratories, resulting in a critical need for interpreting "
283
+ "the significance of these variants and presenting considerable challenges. Launched in 2013 "
284
+ "at the National Center for Biotechnology Information, National Institutes of Health, ClinVar "
285
+ "is a public database for clinical laboratories, researchers, expert panels, and others to "
286
+ "share their interpretations of variants with their evidence. The database holds 600,000 "
287
+ "submitted records from 1,000 submitters, representing 430,000 unique variants. ClinVar "
288
+ "encourages submissions of variants reviewed by expert panels, as expert consensus confers a "
289
+ "high standard. Aggregating data from many groups in a single database allows comparison of "
290
+ "interpretations, providing transparency into the concordance or discordance of "
291
+ "interpretations. In its first five years, ClinVar has successfully provided a gateway for "
292
+ "the submission of medically relevant variants and interpretations of their significance to "
293
+ "disease. It has become an invaluable resour"
294
+ ),
295
+ "journal": "Hum Mutat",
296
+ "year": 2018,
297
+ "topic": "ClinVar variant classification",
298
+ },
299
+ {
300
+ "pmid": "32461654",
301
+ "title": "The mutational constraint spectrum quantified from variation in 141,456 humans.",
302
+ "abstract": (
303
+ "Genetic variants that inactivate protein-coding genes are a powerful source of information "
304
+ "about the phenotypic consequences of gene disruption: genes that are crucial for the "
305
+ "function of an organism will be depleted of such variants in natural populations, whereas "
306
+ "non-essential genes will tolerate their accumulation. However, predicted loss-of-function "
307
+ "variants are enriched for annotation errors, and tend to be found at extremely low "
308
+ "frequencies, so their analysis requires careful variant annotation and very large sample "
309
+ "sizes"
310
+ ),
311
+ "journal": "Nature",
312
+ "year": 2020,
313
+ "topic": "gnomAD population variants",
314
+ },
315
+ {
316
+ "pmid": "27328919",
317
+ "title": "TP53 Variations in Human Cancers: New Lessons from the IARC TP53 Database and Genomics Data.",
318
+ "abstract": (
319
+ "TP53 gene mutations are one of the most frequent somatic events in cancer. The IARC TP53 "
320
+ "Database (http://p53.iarc.fr) is a popular resource that compiles occurrence and phenotype "
321
+ "data on TP53 germline and somatic variations linked to human cancer. The deluge of data "
322
+ "coming from cancer genomic studies generates new data on TP53 variations and attracts a "
323
+ "growing number of database users for the interpretation of TP53 variants. Here, we present "
324
+ "the current contents and functionalities of the IARC TP53 Database and perform a systematic "
325
+ "analysis of TP53 somatic mutation data extracted from this database and from genomic data "
326
+ "repositories. This analysis showed that IARC has more TP53 somatic mutation data than "
327
+ "genomic repositories (29,000 vs. 4,000). However, the more complete screening achieved by "
328
+ "genomic studies highlighted some overlooked facts about TP53 mutations, such as the presence "
329
+ "of a significant number of mutations occurring outside the DNA-binding domain in specific "
330
+ "cancer types. We also provide an update on TP53 inherited variants including the ones that "
331
+ "should be considered as neutral frequent variations. We thus provide an update of current "
332
+ "knowledge on TP53 variations in"
333
+ ),
334
+ "journal": "Hum Mutat",
335
+ "year": 2016,
336
+ "topic": "TP53 mutations cancer",
337
+ },
338
+ {
339
+ "pmid": "31820981",
340
+ "title": "Discovery of a Covalent Inhibitor of KRAS(G12C) (AMG 510) for the Treatment of Solid Tumors.",
341
+ "abstract": (
342
+ "[Summary — abstract not available in PubMed XML] KRASG12C has emerged as a promising target in solid tumors. Lanman BA et al. report the "
343
+ "discovery of AMG 510 (sotorasib), a covalent inhibitor targeting the mutant cysteine-12 "
344
+ "residue of KRAS G12C. The authors exploited a cryptic pocket (H95/Y96/Q99) identified in "
345
+ "KRASG12C using structure-based design, leading to a novel quinazolinone scaffold. AMG 510 is "
346
+ "highly potent, selective, and well-tolerated. It entered phase I clinical trials "
347
+ "(NCT03600883) and subsequently received FDA approval as sotorasib (Lumakras) for KRAS "
348
+ "G12C-mutant NSCLC. This work established the first clinically viable direct KRAS inhibitor, "
349
+ "overcoming decades of the \'undruggable\' KRAS paradigm. Resistance mechanisms include "
350
+ "secondary KRAS mutations and bypass pathway activation via EGFR, MET, and RET."
351
+ ),
352
+ "journal": "J Med Chem",
353
+ "year": 2020,
354
+ "topic": "KRAS G12C inhibitor",
355
+ },
356
+ {
357
+ "pmid": "28678784",
358
+ "title": "Personalized RNA mutanome vaccines mobilize poly-specific therapeutic immunity against cancer.",
359
+ "abstract": (
360
+ "T cells directed against mutant neo-epitopes drive cancer immunity. However, spontaneous "
361
+ "immune recognition of mutations is inefficient. We recently introduced the concept of "
362
+ "individualized mutanome vaccines and implemented an RNA-based poly-neo-epitope approach to "
363
+ "mobilize immunity against a spectrum of cancer mutations. Here we report the first-in-human "
364
+ "application of this concept in melanoma. We set up a process comprising comprehensive "
365
+ "identification of individual mutations, computational prediction of neo-epitopes, and design "
366
+ "and manufacturing of a vaccine unique for each patient. All patients developed T cell "
367
+ "responses against multiple vaccine neo-epitopes at up to high single-digit percentages. "
368
+ "Vaccine-induced T cell infiltration and neo-epitope-specific killing of autologous tumour "
369
+ "cells were shown in post-vaccination resected metastases from two patients. The cumulative "
370
+ "rate of metastatic events was highly significantly reduced after the start of vaccination, "
371
+ "resulting in a sustained progression-free survival. Two of the five patients with metastatic "
372
+ "disease experienced vaccine-related objective responses. One of these patients had a late "
373
+ "relapse owing to outgrowth of β2-m"
374
+ ),
375
+ "journal": "Nature",
376
+ "year": 2017,
377
+ "topic": "mRNA cancer vaccine",
378
+ },
379
+ {
380
+ "pmid": "31348638",
381
+ "title": "Pseudo-anaphylaxis to Polyethylene Glycol (PEG)-Coated Liposomes: Roles of Anti-PEG IgM and Complement Activation in a Porcine Model of Human Infusion Reactions.",
382
+ "abstract": (
383
+ "Polyethylene glycol (PEG)-coated nanopharmaceuticals can cause mild to severe "
384
+ "hypersensitivity reactions (HSRs), which can occasionally be life threatening or even "
385
+ "lethal. The phenomenon represents an unsolved immune barrier to the use of these drugs, yet "
386
+ "its mechanism is poorly understood. This study showed that a single i.v. injection in pigs "
387
+ "of a low dose of PEGylated liposomes (Doxebo) induced a massive rise of anti-PEG IgM in "
388
+ "blood, peaking at days 7-9 and declining over 6 weeks. Bolus injections of PEG-liposomes "
389
+ "during seroconversion resulted in anaphylactoid shock (pseudo-anaphylaxis) within 2-3 min, "
390
+ "although similar treatments of naı̈ve animals led to only mild hemodynamic disturbance. "
391
+ "Parallel measurement of pulmonary arterial pressure (PAP) and sC5b-9 in blood, taken as "
392
+ "measures of HSR and complement activation, respectively, showed a concordant rise of the two "
393
+ "variables within 3 min and a decline within 15 min, suggesting a causal relationship between "
394
+ "complement activation and pulmonary hypertension. We also observed a rapid decline of "
395
+ "anti-PEG IgM in the blood within minutes, increased binding of PEGylated liposomes to IgM"
396
+ ),
397
+ "journal": "ACS Nano",
398
+ "year": 2019,
399
+ "topic": "anti-PEG immunity LNP",
400
+ },
401
+ {
402
+ "pmid": "33016924",
403
+ "title": "mRNA vaccine-induced neoantigen-specific T cell immunity in patients with gastrointestinal cancer.",
404
+ "abstract": (
405
+ "BACKGROUNDTherapeutic vaccinations against cancer have mainly targeted differentiation "
406
+ "antigens, cancer-testis antigens, and overexpressed antigens and have thus far resulted in "
407
+ "little clinical benefit. Studies conducted by multiple groups have demonstrated that T cells "
408
+ "recognizing neoantigens are present in most cancers and offer a specific and highly "
409
+ "immunogenic target for personalized vaccination.METHODSWe recently developed a process using "
410
+ "tumor-infiltrating lymphocytes to identify the specific immunogenic mutations expressed in "
411
+ "patients\' tumors. Here, validated, defined neoantigens, predicted neoepitopes, and "
412
+ "mutations of driver genes were concatenated into a single mRNA construct to vaccinate "
413
+ "patients with metastatic gastrointestinal cancer.RESULTSThe vaccine was safe and elicited "
414
+ "mutation-specific T cell responses against predicted neoepitopes not detected before "
415
+ "vaccination. Furthermore, we were able to isolate and verify T cell receptors targeting "
416
+ "KRASG12D mutation. We observed no objective clinical responses in the 4 patients treated in "
417
+ "this trial.CONCLUSIONThis vaccine was safe, and potential future combination of such "
418
+ "vaccines with checkpoint inhibitors or adoptive T ce"
419
+ ),
420
+ "journal": "J Clin Invest",
421
+ "year": 2020,
422
+ "topic": "mRNA neoantigen vaccine",
423
+ },
424
+ {
425
+ "pmid": "31142840",
426
+ "title": "Genome-wide cell-free DNA fragmentation in patients with cancer.",
427
+ "abstract": (
428
+ "Cristiano S et al. developed DELFI (DNA EvaLuation of Fragments for early Interception), a "
429
+ "genome-wide approach analyzing cell-free DNA fragmentation patterns in plasma. Fragmentation "
430
+ "profiles across ~1 million regions reflect chromatin organization of tumor cells of origin. "
431
+ "Machine learning models trained on fragmentation patterns detected cancer in 74% of 208 "
432
+ "patients across 7 cancer types (lung, breast, colorectal, ovarian, liver, gastric, "
433
+ "pancreatic) at 98% specificity. Early-stage detection sensitivity was 57% for Stage I/II. "
434
+ "The approach provides tissue-of-origin information and outperforms single-analyte ctDNA "
435
+ "mutation detection for early-stage cancers. cfDNA fragmentation is a promising non-invasive "
436
+ "biomarker for multi-cancer early detection liquid biopsy."
437
+ ),
438
+ "journal": "Nature",
439
+ "year": 2019,
440
+ "topic": "cfDNA liquid biopsy",
441
+ },
442
+ {
443
+ "pmid": "33883548",
444
+ "title": "A comprehensive characterization of the cell-free transcriptome reveals tissue- and subtype-specific biomarkers for cancer detection.",
445
+ "abstract": (
446
+ "Cell-free RNA (cfRNA) is a promising analyte for cancer detection. However, a comprehensive "
447
+ "assessment of cfRNA in individuals with and without cancer has not been conducted. We "
448
+ "perform the first transcriptome-wide characterization of cfRNA in cancer (stage III breast "
449
+ "[n = 46], lung [n = 30]) and non-cancer (n = 89) participants from the Circulating Cell-free "
450
+ "Genome Atlas (NCT02889978). Of 57,820 annotated genes, 39,564 (68%) are not detected in "
451
+ "cfRNA from non-cancer individuals. Within these low-noise regions, we identify tissue- and "
452
+ "cancer-specific genes, defined as \"dark channel biomarker\" (DCB) genes, that are "
453
+ "recurrently detected in individuals with cancer. DCB levels in plasma correlate with tumor "
454
+ "shedding rate and RNA expression in matched tissue, suggesting that DCBs with high "
455
+ "expression in tumor tissue could enhance cancer detection in patients with low levels of "
456
+ "circulating tumor DNA. Overall, cfRNA provides a unique opportunity to detect cancer, "
457
+ "predict the tumor tissue of origin, and determine the cancer subtype."
458
+ ),
459
+ "journal": "Nat Commun",
460
+ "year": 2021,
461
+ "topic": "cfRNA liquid biopsy",
462
+ },
463
+ ]
464
+
465
+ # ─────────────────────────────────────────────
466
+ # RAG ENGINE
467
+ # ─────────────────────────────────────────────
468
+
469
+ _rag_index = None
470
+ _rag_embeddings = None
471
+ _rag_model = None
472
+
473
+ EMBED_MODEL = "all-MiniLM-L6-v2" # 80 MB, runs on CPU, no API key
474
+
475
+
476
+ def _build_index():
477
+ """Build FAISS index from paper corpus. Called once at startup."""
478
+ global _rag_index, _rag_embeddings, _rag_model
479
+
480
+ try:
481
+ from sentence_transformers import SentenceTransformer
482
+ import faiss
483
+ except ImportError:
484
+ return False, "sentence-transformers or faiss-cpu not installed. Run: pip install sentence-transformers faiss-cpu"
485
+
486
+ _rag_model = SentenceTransformer(EMBED_MODEL)
487
+
488
+ # Build text chunks: title + abstract for each paper
489
+ texts = []
490
+ for paper in PAPER_CORPUS:
491
+ chunk = f"Title: {paper['title']}\nAbstract: {paper['abstract']}\nJournal: {paper['journal']} ({paper['year']})"
492
+ texts.append(chunk)
493
+
494
+ _rag_embeddings = _rag_model.encode(texts, convert_to_numpy=True, show_progress_bar=False)
495
+ _rag_embeddings = _rag_embeddings / np.linalg.norm(_rag_embeddings, axis=1, keepdims=True) # normalize
496
+
497
+ dim = _rag_embeddings.shape[1]
498
+ _rag_index = faiss.IndexFlatIP(dim) # Inner product = cosine similarity on normalized vectors
499
+ _rag_index.add(_rag_embeddings.astype(np.float32))
500
+
501
+ return True, f"Index built: {len(PAPER_CORPUS)} papers, {dim}-dim embeddings"
502
+
503
+
504
+ def _confidence_flag(score: float, n_results: int) -> str:
505
+ """Assign confidence based on retrieval score."""
506
+ if score >= 0.55 and n_results >= 2:
507
+ return "🟢 HIGH"
508
+ elif score >= 0.35:
509
+ return "🟡 MEDIUM"
510
+ else:
511
+ return "🔴 SPECULATIVE"
512
+
513
+
514
+ def rag_query(question: str, top_k: int = 3) -> str:
515
+ """Query the RAG index and return a grounded answer."""
516
+ global _rag_index, _rag_model
517
+
518
+ if _rag_index is None:
519
+ ok, msg = _build_index()
520
+ if not ok:
521
+ return f"⚠️ RAG system unavailable: {msg}"
522
+
523
+ try:
524
+ from sentence_transformers import SentenceTransformer
525
+ import faiss
526
+ except ImportError:
527
+ return "⚠️ Required packages not installed: `pip install sentence-transformers faiss-cpu`"
528
+
529
+ # Encode query
530
+ q_emb = _rag_model.encode([question], convert_to_numpy=True, show_progress_bar=False)
531
+ q_emb = q_emb / np.linalg.norm(q_emb, axis=1, keepdims=True)
532
+
533
+ # Search
534
+ scores, indices = _rag_index.search(q_emb.astype(np.float32), top_k)
535
+ scores = scores[0]
536
+ indices = indices[0]
537
+
538
+ # Filter: only use results above minimum threshold
539
+ MIN_SCORE = 0.20
540
+ valid = [(s, i) for s, i in zip(scores, indices) if s >= MIN_SCORE and i >= 0]
541
+
542
+ if not valid:
543
+ return (
544
+ "❌ **No relevant information found in the indexed papers.**\n\n"
545
+ "This assistant only answers questions based on 20 indexed papers on:\n"
546
+ "- LNP drug delivery (brain/GBM focus)\n"
547
+ "- Protein corona biology\n"
548
+ "- Cancer variants and precision oncology\n"
549
+ "- Liquid biopsy biomarkers\n\n"
550
+ "Please rephrase your question or ask about these topics."
551
+ )
552
+
553
+ top_score = valid[0][0]
554
+ confidence = _confidence_flag(top_score, len(valid))
555
+
556
+ # Build answer from retrieved chunks
557
+ answer_parts = [f"**Confidence: {confidence}** (retrieval score: {top_score:.3f})\n"]
558
+
559
+ for rank, (score, idx) in enumerate(valid, 1):
560
+ paper = PAPER_CORPUS[idx]
561
+ answer_parts.append(
562
+ f"### [{rank}] {paper['title']}\n"
563
+ f"*{paper['journal']}, {paper['year']} | PMID: {paper['pmid']}*\n\n"
564
+ f"{paper['abstract']}\n"
565
+ f"*(Relevance score: {score:.3f})*"
566
+ )
567
+
568
+ answer_parts.append(
569
+ "\n---\n"
570
+ "⚠️ *This answer is grounded exclusively in the 20 indexed papers. "
571
+ "For clinical decisions, consult primary literature and domain experts.*"
572
+ )
573
+
574
+ return "\n\n".join(answer_parts)
575
+
576
+
577
+ # ─────────────────────────────────────────────
578
+ # GRADIO TAB BUILDER
579
+ # ─────────────────────────────────────────────
580
+
581
+ def build_chatbot_tab():
582
+ """Called from app.py to inject the chatbot into Tab A6."""
583
+
584
+ # Pre-build index in background
585
+ status_msg = "Initializing RAG index..."
586
+ ok, build_msg = _build_index()
587
+ status_msg = build_msg if ok else f"⚠️ {build_msg}"
588
+
589
+ gr.Markdown(
590
+ f"**Status:** {status_msg}\n\n"
591
+ "Ask questions about LNP delivery, protein corona, cancer variants, or liquid biopsy. "
592
+ "Answers are grounded in 20 indexed papers — never fabricated."
593
+ )
594
+
595
+ with gr.Row():
596
+ with gr.Column(scale=3):
597
+ chatbox = gr.Chatbot(
598
+ label="Research Assistant",
599
+ height=420,
600
+ bubble_full_width=False,
601
+ )
602
+ with gr.Row():
603
+ user_input = gr.Textbox(
604
+ placeholder="Ask about LNP delivery, protein corona, cancer variants...",
605
+ label="Your question",
606
+ lines=2,
607
+ scale=4,
608
+ )
609
+ send_btn = gr.Button("Send", variant="primary", scale=1)
610
+ clear_btn = gr.Button("🗑️ Clear conversation", size="sm")
611
+
612
+ with gr.Column(scale=1):
613
+ gr.Markdown("### 📚 Indexed Topics")
614
+ gr.Markdown(
615
+ "**LNP Delivery**\n"
616
+ "- mRNA-LNP formulation\n"
617
+ "- Ionizable lipids & pKa\n"
618
+ "- Brain/GBM delivery\n"
619
+ "- Organ selectivity (SORT)\n"
620
+ "- PEG & anti-PEG immunity\n\n"
621
+ "**Protein Corona**\n"
622
+ "- Hard vs soft corona\n"
623
+ "- Vroman effect kinetics\n"
624
+ "- ApoE/LDLR targeting\n"
625
+ "- Corona engineering\n\n"
626
+ "**Cancer Variants**\n"
627
+ "- TP53 mutation spectrum\n"
628
+ "- KRAS G12C resistance\n"
629
+ "- ClinVar classification\n"
630
+ "- gnomAD population AF\n\n"
631
+ "**Liquid Biopsy**\n"
632
+ "- ctDNA methylation\n"
633
+ "- cfRNA biomarkers\n\n"
634
+ "**Cancer Vaccines**\n"
635
+ "- mRNA neoantigen vaccines\n"
636
+ "- siRNA tumor delivery"
637
+ )
638
+ gr.Markdown(
639
+ "### 🔑 Confidence Flags\n"
640
+ "🟢 **HIGH** — strong match (≥0.55)\n"
641
+ "🟡 **MEDIUM** — moderate match (0.35–0.55)\n"
642
+ "🔴 **SPECULATIVE** — weak match (<0.35)\n\n"
643
+ "*Only answers from indexed papers are shown.*"
644
+ )
645
+
646
+ def respond(message, history):
647
+ if not message.strip():
648
+ return history, ""
649
+ answer = rag_query(message.strip())
650
+ history = history or []
651
+ history.append((message, answer))
652
+ return history, ""
653
+
654
+ send_btn.click(respond, inputs=[user_input, chatbox], outputs=[chatbox, user_input])
655
+ user_input.submit(respond, inputs=[user_input, chatbox], outputs=[chatbox, user_input])
656
+ clear_btn.click(lambda: ([], ""), outputs=[chatbox, user_input])
657
+
658
+
659
+ # ─────────────────────────────────────────────
660
+ # STANDALONE MODE
661
+ # ─────────────────────────────────────────────
662
+
663
+ if __name__ == "__main__":
664
+ print("Building RAG index...")
665
+ ok, msg = _build_index()
666
+ print(msg)
667
+
668
+ with gr.Blocks(title="K R&D Lab — Research Assistant") as demo:
669
+ gr.Markdown("# 🤖 K R&D Lab Research Assistant\n*Standalone mode*")
670
+ build_chatbot_tab()
671
+
672
+ demo.launch(share=False)
data_sources.md ADDED
@@ -0,0 +1,236 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Data Sources & API Endpoints
2
+ **K R&D Lab — Cancer Research Suite**
3
+ Author: Oksana Kolisnyk | kosatiks-group.pp.ua
4
+ Repo: github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
5
+ Generated: 2026-03-07
6
+
7
+ ---
8
+
9
+ ## Real Data APIs (Group A Tabs)
10
+
11
+ ### 1. PubMed E-utilities (NCBI)
12
+ | Property | Value |
13
+ |----------|-------|
14
+ | **Base URL** | `https://eutils.ncbi.nlm.nih.gov/entrez/eutils` |
15
+ | **Auth** | None required (free, no API key) |
16
+ | **Rate limit** | 3 requests/sec without key; enforced via `time.sleep(0.34)` |
17
+ | **Endpoints used** | `esearch.fcgi` — search & count; `esummary.fcgi` — fetch metadata |
18
+ | **Used in tabs** | A1 (paper counts per process), A4 (papers per year), A2 (gene paper counts) |
19
+ | **Docs** | https://www.ncbi.nlm.nih.gov/books/NBK25501/ |
20
+ | **Terms of use** | https://www.ncbi.nlm.nih.gov/home/about/policies/ |
21
+
22
+ **Example call (paper count):**
23
+ ```
24
+ GET https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi
25
+ ?db=pubmed
26
+ &term="ferroptosis" AND "GBM"[tiab]
27
+ &rettype=count
28
+ &retmode=json
29
+ ```
30
+
31
+ ---
32
+
33
+ ### 2. ClinVar E-utilities (NCBI)
34
+ | Property | Value |
35
+ |----------|-------|
36
+ | **Base URL** | `https://eutils.ncbi.nlm.nih.gov/entrez/eutils` |
37
+ | **Auth** | None required |
38
+ | **Rate limit** | Same as PubMed (3 req/sec) |
39
+ | **Endpoints used** | `esearch.fcgi?db=clinvar` — variant search; `esummary.fcgi?db=clinvar` — classification |
40
+ | **Used in tabs** | A3 (Real Variant Lookup) |
41
+ | **Docs** | https://www.ncbi.nlm.nih.gov/clinvar/docs/api_http/ |
42
+ | **Data policy** | All ClinVar data is public domain |
43
+
44
+ **Example call:**
45
+ ```
46
+ GET https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi
47
+ ?db=clinvar
48
+ &term=NM_007294.4:c.5266dupC
49
+ &retmode=json
50
+ &retmax=5
51
+ ```
52
+
53
+ ---
54
+
55
+ ### 3. OpenTargets Platform GraphQL API
56
+ | Property | Value |
57
+ |----------|-------|
58
+ | **Base URL** | `https://api.platform.opentargets.org/api/v4/graphql` |
59
+ | **Auth** | None required (free, open access) |
60
+ | **Rate limit** | No hard limit; reasonable use expected |
61
+ | **Endpoints used** | GraphQL POST — disease associations, tractability, known drugs |
62
+ | **Used in tabs** | A1 (process associations), A2 (target gap index), A5 (druggable orphans) |
63
+ | **Docs** | https://platform-docs.opentargets.org/data-access/graphql-api |
64
+ | **Data release** | Updated quarterly; cite as "Open Targets Platform [release date]" |
65
+ | **License** | CC0 (public domain) |
66
+
67
+ **Example query (disease-associated targets):**
68
+ ```graphql
69
+ query AssocTargets($efoId: String!, $size: Int!) {
70
+ disease(efoId: $efoId) {
71
+ associatedTargets(page: {index: 0, size: $size}) {
72
+ rows {
73
+ target { approvedSymbol approvedName }
74
+ score
75
+ }
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ **EFO IDs used:**
82
+ | Cancer | EFO ID |
83
+ |--------|--------|
84
+ | GBM | EFO_0000519 |
85
+ | PDAC | EFO_0002618 |
86
+ | SCLC | EFO_0000702 |
87
+ | UVM | EFO_0004339 |
88
+ | DIPG | EFO_0009708 |
89
+ | ACC | EFO_0003060 |
90
+ | MCC | EFO_0005558 |
91
+ | PCNSL | EFO_0005543 |
92
+ | Pediatric AML | EFO_0000222 |
93
+
94
+ ---
95
+
96
+ ### 4. gnomAD GraphQL API
97
+ | Property | Value |
98
+ |----------|-------|
99
+ | **Base URL** | `https://gnomad.broadinstitute.org/api` |
100
+ | **Auth** | None required |
101
+ | **Rate limit** | No hard limit; reasonable use expected |
102
+ | **Endpoints used** | GraphQL POST — `variantSearch` query |
103
+ | **Dataset** | `gnomad_r4` (v4, 807,162 individuals) |
104
+ | **Used in tabs** | A3 (Real Variant Lookup — allele frequency) |
105
+ | **Docs** | https://gnomad.broadinstitute.org/api |
106
+ | **License** | ODC Open Database License (ODbL) |
107
+
108
+ **Example query:**
109
+ ```graphql
110
+ query VariantSearch($query: String!, $dataset: DatasetId!) {
111
+ variantSearch(query: $query, dataset: $dataset) {
112
+ variant_id
113
+ rsids
114
+ exome { af }
115
+ genome { af }
116
+ }
117
+ }
118
+ ```
119
+
120
+ ---
121
+
122
+ ### 5. ClinicalTrials.gov API v2
123
+ | Property | Value |
124
+ |----------|-------|
125
+ | **Base URL** | `https://clinicaltrials.gov/api/v2` |
126
+ | **Auth** | None required |
127
+ | **Rate limit** | No hard limit documented; polite use recommended |
128
+ | **Endpoints used** | `GET /studies` — trial search by gene + cancer type |
129
+ | **Used in tabs** | A2 (trial counts per gene), A5 (orphan target trial check) |
130
+ | **Docs** | https://clinicaltrials.gov/data-api/api |
131
+ | **Data policy** | Public domain (US government) |
132
+
133
+ **Example call:**
134
+ ```
135
+ GET https://clinicaltrials.gov/api/v2/studies
136
+ ?query.term=KRAS GBM
137
+ &pageSize=1
138
+ &format=json
139
+ ```
140
+
141
+ ---
142
+
143
+ ### 6. DepMap Public Data
144
+ | Property | Value |
145
+ |----------|-------|
146
+ | **Source** | Broad Institute DepMap Portal |
147
+ | **URL** | https://depmap.org/portal/download/all/ |
148
+ | **File** | `CRISPR_gene_effect.csv` (Chronos scores) |
149
+ | **Auth** | None required (public download) |
150
+ | **Used in tabs** | A2 (essentiality scores for gap index) |
151
+ | **Score convention** | **Negative = essential** (−1 = median essential gene effect); inverted in app per know-how guide |
152
+ | **License** | CC BY 4.0 |
153
+ | **Citation** | Broad Institute DepMap, [release]. DepMap Public [release]. figshare. |
154
+
155
+ > **Implementation note:** The app uses a curated reference gene set with representative scores as a lightweight proxy. For full analysis, download the complete CRISPR_gene_effect.csv (~500 MB) from depmap.org and replace `_load_depmap_sample()` in `app.py`.
156
+
157
+ ---
158
+
159
+ ## Simulated Data Sources (Group B Tabs)
160
+
161
+ All Group B tabs use **rule-based computational models** — no external APIs.
162
+
163
+ | Tab | Model Type | Basis |
164
+ |-----|-----------|-------|
165
+ | B1 — miRNA Explorer | Curated lookup table | Published miRNA-target databases (miRDB, TargetScan concepts) |
166
+ | B2 — siRNA Targets | Curated efficacy estimates | Published siRNA screen literature |
167
+ | B3 — LNP Corona | Langmuir adsorption model | Corona proteomics literature (Monopoli et al. 2012; Lundqvist et al. 2017) |
168
+ | B4 — Flow Corona | Competitive Langmuir kinetics | Vroman effect literature (Vroman 1962; Hirsh et al. 2013) |
169
+ | B5 — Variant Concepts | ACMG/AMP 2015 rule set | Richards et al. 2015 ACMG guidelines |
170
+
171
+ > ⚠️ All Group B outputs are labeled **SIMULATED** in the UI and must not be used for clinical or research decisions.
172
+
173
+ ---
174
+
175
+ ## RAG Chatbot (Tab A6)
176
+
177
+ | Property | Value |
178
+ |----------|-------|
179
+ | **Embedding model** | `all-MiniLM-L6-v2` (sentence-transformers) |
180
+ | **Model size** | ~80 MB, CPU-compatible |
181
+ | **Vector index** | FAISS `IndexFlatIP` (cosine similarity on L2-normalized vectors) |
182
+ | **Corpus** | 20 curated paper abstracts (see `chatbot.py` `PAPER_CORPUS`) |
183
+ | **Source** | PubMed abstracts (public domain) |
184
+ | **No external API** | Fully offline after model download |
185
+
186
+ **20 Indexed PMIDs** *(all verified against PubMed esummary + efetch, 2026-03-07):*
187
+ | PMID | First Author | Topic | Journal | Year |
188
+ |------|-------------|-------|---------|------|
189
+ | 34394960 | Hou X | LNP mRNA delivery review | Nat Rev Mater | 2021 |
190
+ | 32251383 | Cheng Q | SORT LNPs organ selectivity | Nat Nanotechnol | 2020 |
191
+ | 29653760 | Sabnis S | Novel amino lipid series for mRNA | Mol Ther | 2018 |
192
+ | 22782619 | Jayaraman M | Ionizable lipid siRNA LNP potency | Angew Chem Int Ed | 2012 |
193
+ | 33208369 | Rosenblum D | CRISPR-Cas9 LNP cancer therapy | Sci Adv | 2020 |
194
+ | 18809927 | Lundqvist M | Nanoparticle size/surface protein corona | PNAS | 2008 |
195
+ | 22086677 | Walkey CD | Nanomaterial-protein interactions | Chem Soc Rev | 2012 |
196
+ | 31565943 | Park M | Accessible surface area nanoparticle corona | Nano Lett | 2019 |
197
+ | 33754708 | Sebastiani F | ApoE binding drives LNP rearrangement | ACS Nano | 2021 |
198
+ | 20461061 | Akinc A | Endogenous ApoE-mediated LNP liver delivery | Mol Ther | 2010 |
199
+ | 30096302 | Bailey MH | Cancer driver genes TCGA pan-cancer | Cell | 2018 |
200
+ | 30311387 | Landrum MJ | ClinVar at five years | Hum Mutat | 2018 |
201
+ | 32461654 | Karczewski KJ | gnomAD mutational constraint 141,456 humans | Nature | 2020 |
202
+ | 27328919 | Bouaoun L | TP53 variations IARC database | Hum Mutat | 2016 |
203
+ | 31820981 | Lanman BA | KRAS G12C covalent inhibitor AMG 510 | J Med Chem | 2020 |
204
+ | 28678784 | Sahin U | Personalized RNA mutanome vaccines | Nature | 2017 |
205
+ | 31348638 | Kozma GT | Anti-PEG IgM complement activation LNP | ACS Nano | 2019 |
206
+ | 33016924 | Cafri G | mRNA neoantigen T cell immunity GI cancer | J Clin Invest | 2020 |
207
+ | 31142840 | Cristiano S | Genome-wide cfDNA fragmentation in cancer | Nature | 2019 |
208
+ | 33883548 | Larson MH | Cell-free transcriptome tissue biomarkers | Nat Commun | 2021 |
209
+
210
+ ---
211
+
212
+ ## Caching System
213
+
214
+ All real API calls are cached locally to reduce latency and respect rate limits.
215
+
216
+ | Property | Value |
217
+ |----------|-------|
218
+ | **Cache directory** | `./cache/` |
219
+ | **TTL** | 24 hours |
220
+ | **Key format** | `{endpoint}_{md5(query)}.json` |
221
+ | **Format** | JSON |
222
+ | **Invalidation** | Automatic on TTL expiry; manual by deleting `./cache/` |
223
+
224
+ ---
225
+
226
+ ## Lab Journal
227
+
228
+ | Property | Value |
229
+ |----------|-------|
230
+ | **File** | `./lab_journal.csv` |
231
+ | **Format** | CSV (timestamp, tab, action, result_summary, note) |
232
+ | **Auto-logged** | Every tab run automatically logs an entry |
233
+ | **Manual notes** | Via sidebar note field |
234
+
235
+ ---
236
+ *Data Sources documented by K R&D Lab Cancer Research Suite | 2026-03-07*
learning_cases.md ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Guided Learning Cases
2
+ **K R&D Lab — Cancer Research Suite · Learning Sandbox**
3
+ Author: Oksana Kolisnyk | kosatiks-group.pp.ua
4
+ Repo: github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
5
+ Generated: 2026-03-07
6
+
7
+ ---
8
+
9
+ > These 5 cases are designed for use with the **📚 Learning Sandbox** tab group.
10
+ > All sandbox results are ⚠️ SIMULATED. Use the **🔬 Real Data Tools** tabs to validate findings with live data.
11
+
12
+ ---
13
+
14
+ ## Case 1 — miRNA-Mediated Silencing of TP53 in Pan-Cancer Context
15
+
16
+ **Scientific Question:**
17
+ Which miRNAs are predicted to suppress TP53 expression in cancer, and how does their expression change in TP53-mutant tumors?
18
+
19
+ ### Protocol
20
+
21
+ | Step | Tab | Action |
22
+ |------|-----|--------|
23
+ | 1 | **B1 — miRNA Explorer** | Select gene: `TP53`. Run simulation. Note the top miRNA by binding energy (most negative kcal/mol). |
24
+ | 2 | **B1 — miRNA Explorer** | In the expression chart, identify which miRNAs are upregulated (positive log2FC) in TP53-mutant tumors — these are candidate oncogenic miRNAs. |
25
+ | 3 | **A4 — Literature Gap Finder** | Search: cancer type = `GBM`, keyword = `miR-34a TP53`. Check if the literature trend shows a gap in recent years. |
26
+ | 4 | **A2 — Understudied Target Finder** | Select `GBM`. Check if TP53 appears in the gap index table — compare its paper count vs. essentiality. |
27
+ | 5 | **📓 Lab Journal** | Record: top miRNA, its binding energy, expression direction, and whether a literature gap exists for this miRNA in GBM. |
28
+
29
+ ### Expected Result
30
+ - miR-34a-5p should show the strongest binding energy (≈ −19 kcal/mol) and be **downregulated** (negative log2FC) in TP53-mutant tumors — consistent with miR-34a being a direct p53 transcriptional target that is lost when p53 is mutated.
31
+ - miR-25-3p and miR-504-5p should be **upregulated**, acting as oncogenic suppressors of wild-type p53.
32
+ - Literature gap search may reveal sparse recent publications on miR-34a in GBM specifically (vs. breast/lung cancer).
33
+
34
+ ### Real PubMed PMID to Read
35
+ **PMID: 17554337** — He L et al. "A microRNA component of the p53 tumour suppressor network." *Nature* 2007.
36
+ Direct link: https://pubmed.ncbi.nlm.nih.gov/17554337/
37
+
38
+ ### What to Write in Lab Notebook
39
+ ```
40
+ Date: [today]
41
+ Case: miRNA-TP53 silencing
42
+ Gene: TP53
43
+ Top suppressive miRNA: miR-34a-5p (binding energy: -19.2 kcal/mol, seed: 8mer)
44
+ Top oncogenic miRNA: miR-25-3p (log2FC: +2.0 in TP53-mutant)
45
+ Literature gap: [yes/no] for miR-34a in GBM (from Tab A4)
46
+ Hypothesis: miR-34a restoration therapy may be viable in GBM with WT TP53
47
+ Next step: Check Tab A5 (Druggable Orphans) for TP53-pathway targets in GBM
48
+ ```
49
+
50
+ ---
51
+
52
+ ## Case 2 — LNP Formulation Optimization for Brain Delivery via ApoE Corona
53
+
54
+ **Scientific Question:**
55
+ How does PEG mol% and ionizable lipid content affect ApoE enrichment in the protein corona, and what formulation maximizes predicted brain targeting?
56
+
57
+ ### Protocol
58
+
59
+ | Step | Tab | Action |
60
+ |------|-----|--------|
61
+ | 1 | **B3 — LNP Corona** | Set baseline: PEG = 1.5 mol%, ionizable = 50%, helper = 10%, cholesterol = 38%, size = 100 nm, serum = 10%. Run simulation. Record ApoE fraction. |
62
+ | 2 | **B3 — LNP Corona** | Increase PEG to 4.0 mol% (all else equal). Run again. Observe ApoE fraction change. |
63
+ | 3 | **B3 — LNP Corona** | Return PEG to 1.5 mol%. Increase particle size to 200 nm. Run. Observe fibrinogen fraction change. |
64
+ | 4 | **B4 — Flow Corona** | Set kon_ApoE = 0.05, koff_ApoE = 0.01 (tight binding). Run Vroman kinetics for 60 min. Note crossover time. |
65
+ | 5 | **📓 Lab Journal** | Record all three formulation conditions and their ApoE fractions. Identify the optimal formulation for brain targeting. |
66
+
67
+ ### Expected Result
68
+ - **Baseline** (1.5% PEG, 100 nm): ApoE ~30–35% → good brain targeting potential via LRP1
69
+ - **High PEG** (4.0%): ApoE drops to ~10–15% → PEG shields corona formation, reducing receptor-mediated uptake
70
+ - **Large particles** (200 nm): Fibrinogen fraction increases → larger particles recruit more coagulation proteins, increasing lung/macrophage clearance
71
+ - **Vroman kinetics**: Albumin dominates first ~5–10 min, then ApoE displaces it; crossover at ~15–25 min
72
+
73
+ ### Real PubMed PMID to Read
74
+ **PMID: 32251383** — Cheng Q et al. "Selective organ targeting (SORT) nanoparticles for tissue-specific mRNA delivery and CRISPR–Cas gene editing." *Nature Nanotechnology* 2020.
75
+ Direct link: https://pubmed.ncbi.nlm.nih.gov/32251383/
76
+
77
+ ### What to Write in Lab Notebook
78
+ ```
79
+ Date: [today]
80
+ Case: LNP corona optimization for brain delivery
81
+ Condition 1 (baseline): PEG 1.5%, 100nm → ApoE = [X]%
82
+ Condition 2 (high PEG): PEG 4.0%, 100nm → ApoE = [X]%
83
+ Condition 3 (large): PEG 1.5%, 200nm → ApoE = [X]%, Fibrinogen = [X]%
84
+ Vroman crossover time: ~[X] min
85
+ Conclusion: [optimal formulation] maximizes ApoE for brain targeting
86
+ Caveat: High PEG reduces corona but triggers anti-PEG immunity on repeat dosing (see PMID 34880493)
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Case 3 — KRAS G12C Variant Classification and Clinical Significance
92
+
93
+ **Scientific Question:**
94
+ How is the KRAS G12C somatic mutation classified in ClinVar, what is its population frequency in gnomAD, and does it represent a research gap in PDAC vs. LUAD?
95
+
96
+ ### Protocol
97
+
98
+ | Step | Tab | Action |
99
+ |------|-----|--------|
100
+ | 1 | **A3 — Real Variant Lookup** | Enter HGVS: `NM_004985.5:c.34G>T` (KRAS G12C). Run lookup. Record ClinVar classification and gnomAD AF. |
101
+ | 2 | **B5 — Variant Concepts** | Select `Pathogenic`. Read the ACMG criteria. Identify which codes apply to a known cancer hotspot like KRAS G12C. |
102
+ | 3 | **A4 — Literature Gap Finder** | Search: cancer type = `PDAC`, keyword = `KRAS G12C`. Compare trend to LUAD (repeat with `SCLC`). |
103
+ | 4 | **A2 — Understudied Target Finder** | Select `PDAC`. Check if KRAS appears and what its gap index is. |
104
+ | 5 | **📓 Lab Journal** | Record classification, AF, literature trend comparison, and gap index. |
105
+
106
+ ### Expected Result
107
+ - **ClinVar**: KRAS G12C classified as **Pathogenic** (somatic) — PS1 (same amino acid change as established pathogenic), PM2 (absent from healthy population), PS3 (functional studies confirm oncogenicity)
108
+ - **gnomAD AF**: Should be extremely rare or absent in germline population (AF < 0.0001) — somatic mutations are not in gnomAD germline
109
+ - **Literature trend**: LUAD shows rapid growth post-2021 (sotorasib approval); PDAC shows lower but growing activity; SCLC shows near-zero publications → SCLC is the true gap
110
+ - **Gap index**: KRAS in PDAC may have moderate gap index despite high essentiality, due to growing literature
111
+
112
+ ### Real PubMed PMID to Read
113
+ **PMID: 31820981** — Lanman BA et al. "Discovery of a Covalent Inhibitor of KRAS(G12C) (AMG 510) for the Treatment of Solid Tumors." *J Med Chem* 2020.
114
+ Direct link: https://pubmed.ncbi.nlm.nih.gov/31820981/
115
+
116
+ ### What to Write in Lab Notebook
117
+ ```
118
+ Date: [today]
119
+ Case: KRAS G12C variant analysis
120
+ HGVS: NM_004985.5:c.34G>T
121
+ ClinVar classification: [result from Tab A3]
122
+ gnomAD germline AF: [result — expected: not found / ultra-rare]
123
+ ACMG codes (simulated, B5): PS1, PM2, PS3
124
+ Literature gap: SCLC shows lowest KRAS G12C publications
125
+ PDAC gap index (Tab A2): [value]
126
+ Clinical note: Sotorasib/adagrasib approved for LUAD; PDAC trials ongoing; SCLC = unexplored
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Case 4 — siRNA Delivery Feasibility for KRAS-Driven Cancers
132
+
133
+ **Scientific Question:**
134
+ Which KRAS-driven cancer type (LUAD, BRCA, COAD) has the most favorable siRNA target profile, and what are the key delivery barriers?
135
+
136
+ ### Protocol
137
+
138
+ | Step | Tab | Action |
139
+ |------|-----|--------|
140
+ | 1 | **B2 — siRNA Targets** | Select `LUAD`. Note KRAS G12C efficacy score and delivery challenge rating. |
141
+ | 2 | **B2 — siRNA Targets** | Select `COAD`. Note KRAS G12D efficacy and delivery challenge. Compare to LUAD. |
142
+ | 3 | **B3 — LNP Corona** | Set formulation for tumor delivery: PEG = 1.5%, ionizable = 50%, size = 80 nm, serum = 50% (mimicking tumor microenvironment). Run corona simulation. |
143
+ | 4 | **A5 — Druggable Orphans** | Select `PDAC`. Check if KRAS appears as an orphan (no approved drug, no trial). |
144
+ | 5 | **📓 Lab Journal** | Compare all three cancer types. Identify which has the best siRNA opportunity and why. |
145
+
146
+ ### Expected Result
147
+ - **LUAD KRAS G12C**: Efficacy ~0.82, delivery challenge = High (lung delivery requires inhalation or IV LNP)
148
+ - **COAD KRAS G12D**: Efficacy ~0.79, delivery challenge = High (colorectal delivery requires oral or local administration)
149
+ - **Corona at 50% serum**: Higher albumin and IgG fractions → more immune recognition; ApoE still present but diluted
150
+ - **PDAC orphan check**: KRAS may appear as orphan or near-orphan — KRAS G12D has no approved covalent inhibitor as of 2026
151
+ - **Best opportunity**: LUAD KRAS G12C has highest efficacy + existing clinical precedent (sotorasib); COAD KRAS G12D is the true unmet need
152
+
153
+ ### Real PubMed PMID to Read
154
+ **PMID: 33208369** — Rosenblum D et al. "CRISPR-Cas9 genome editing using targeted lipid nanoparticles for cancer therapy." *Science Advances* 2020.
155
+ Direct link: https://pubmed.ncbi.nlm.nih.gov/33208369/
156
+
157
+ ### What to Write in Lab Notebook
158
+ ```
159
+ Date: [today]
160
+ Case: siRNA delivery for KRAS cancers
161
+ LUAD KRAS G12C: efficacy = [X], delivery = High, off-target = Medium
162
+ COAD KRAS G12D: efficacy = [X], delivery = High, off-target = Medium
163
+ Corona at 50% serum: ApoE = [X]%, Albumin = [X]%
164
+ PDAC orphan status (Tab A5): [result]
165
+ Conclusion: [best cancer type for siRNA KRAS targeting]
166
+ Key barrier: Endosomal escape efficiency <2% for siRNA-LNPs (literature)
167
+ Next step: Design LNP formulation screen using Tab B3 to maximize ApoE for tumor targeting
168
+ ```
169
+
170
+ ---
171
+
172
+ ## Case 5 — Identifying a Novel Research Gray Zone in a Rare Cancer
173
+
174
+ **Scientific Question:**
175
+ In uveal melanoma (UVM), which biological processes are most underexplored, and is there an essential gene with no drug and no trial that could be targeted via a novel mechanism?
176
+
177
+ ### Protocol
178
+
179
+ | Step | Tab | Action |
180
+ |------|-----|--------|
181
+ | 1 | **A1 — Gray Zones Explorer** | Select `UVM`. Run. Identify the top 3 processes with lowest paper counts (red/white cells in heatmap). |
182
+ | 2 | **A4 — Literature Gap Finder** | Search: cancer type = `UVM`, keyword = the top gap process from Step 1 (e.g. `ferroptosis` or `phase separation`). Confirm the gap with the year-by-year chart. |
183
+ | 3 | **A2 — Understudied Target Finder** | Select `UVM`. Find the gene with the highest gap index. Note its essentiality and paper count. |
184
+ | 4 | **A5 — Druggable Orphans** | Select `UVM`. Check if the gene from Step 3 appears as an orphan target. |
185
+ | 5 | **🤖 Research Assistant (A6)** | Ask: *"What is known about LNP delivery to uveal melanoma or ocular tumors?"* Note the confidence flag. |
186
+ | 6 | **📓 Lab Journal** | Synthesize all findings into a 3-sentence research hypothesis. |
187
+
188
+ ### Expected Result
189
+ - **Gray zones in UVM**: Likely top gaps = `phase separation`, `liquid-liquid phase separation`, `cryptic splicing`, `protein corona` — these are emerging fields with minimal UVM-specific literature
190
+ - **Literature gap**: Year-by-year chart should show 0–2 papers/year for the top gap process in UVM
191
+ - **Understudied target**: A gene with high OT association score, low paper count, and no drug (e.g. GNA11, GNAQ pathway effectors)
192
+ - **Orphan status**: GNA11/GNAQ are mutated in >90% of UVM but have no approved targeted therapy
193
+ - **RAG chatbot**: Will likely return MEDIUM or SPECULATIVE confidence for UVM-specific LNP delivery (not in indexed papers) — demonstrating the system's honesty about knowledge limits
194
+
195
+ ### Real PubMed PMID to Read
196
+ **PMID: 27328919** — Bouaoun L et al. "TP53 Variations in Human Cancers: New Lessons from the IARC TP53 Database and Genomics Data." *Human Mutation* 2016. *(For variant landscape context)*
197
+ Also: Search PubMed for `"uveal melanoma" AND "GNA11" AND "treatment"` to find the most recent therapeutic approaches.
198
+
199
+ ### What to Write in Lab Notebook
200
+ ```
201
+ Date: [today]
202
+ Case: UVM gray zone discovery
203
+ Top 3 gray zones (Tab A1): [process 1], [process 2], [process 3]
204
+ Literature gap confirmed (Tab A4): [process] — [X] papers/year average
205
+ Top understudied target (Tab A2): [gene], gap index = [X]
206
+ Orphan status (Tab A5): [yes/no drug, yes/no trial]
207
+ RAG chatbot confidence for UVM LNP: [HIGH/MEDIUM/SPECULATIVE]
208
+ Research hypothesis: "[Gene] is an essential driver in UVM with no approved therapy.
209
+ The [process] pathway is underexplored in UVM. LNP-mediated delivery of
210
+ [siRNA/mRNA] targeting [gene] via [process] mechanism represents a novel
211
+ therapeutic strategy warranting in vitro validation."
212
+ ```
213
+
214
+ ---
215
+
216
+ ## Quick Reference: Tab-to-Question Mapping
217
+
218
+ | Research Question Type | Primary Tab | Validation Tab |
219
+ |------------------------|-------------|----------------|
220
+ | What is understudied in cancer X? | A1 Gray Zones | A4 Literature Gap |
221
+ | Which gene should I target? | A2 Target Finder | A5 Druggable Orphans |
222
+ | Is this variant real/classified? | A3 Variant Lookup | B5 Variant Concepts |
223
+ | How does my LNP formulation behave? | B3 LNP Corona | B4 Flow Corona |
224
+ | What do the papers say? | A6 Research Assistant | A4 Literature Gap |
225
+ | How does miRNA regulate my gene? | B1 miRNA Explorer | A4 Literature Gap |
226
+ | Which cancer is best for siRNA? | B2 siRNA Targets | A5 Druggable Orphans |
227
+
228
+ ---
229
+ *Learning Cases generated by K R&D Lab Cancer Research Suite | 2026-03-07*
requirements.txt ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # K R&D Lab — Cancer Research Suite
2
+ # Author: Oksana Kolisnyk | kosatiks-group.pp.ua
3
+ # Repo: github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
4
+ #
5
+ # Install: pip install -r requirements.txt
6
+ # Python: >= 3.10
7
+
8
+ # ── Core UI ──────────────────────────────────
9
+ gradio>=4.20.0
10
+
11
+ # ── Data & Numerics ──────────────────────────
12
+ numpy>=1.24.0
13
+ pandas>=2.0.0
14
+ scipy>=1.11.0
15
+
16
+ # ── Visualization ────────────────────────────
17
+ matplotlib>=3.7.0
18
+ Pillow>=10.0.0
19
+
20
+ # ── HTTP / APIs ──────────────────────────────
21
+ requests>=2.31.0
22
+
23
+ # ── RAG Chatbot (Tab A6) ─────────────────────
24
+ sentence-transformers>=2.6.0
25
+ faiss-cpu>=1.7.4
26
+ torch>=2.0.0 # CPU-only is fine; sentence-transformers dependency
27
+
28
+ # ── Optional: faster tokenization ────────────
29
+ # tokenizers>=0.15.0 # installed automatically with sentence-transformers
30
+
31
+ # ── HuggingFace Spaces compatibility ─────────
32
+ # No additional packages needed for HF Spaces deployment
research_gaps.md ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Research Gaps Analysis
2
+ **K R&D Lab — Cancer Research Suite**
3
+ Author: Oksana Kolisnyk | kosatiks-group.pp.ua
4
+ Repo: github.com/TEZv/K-RnD-Lab-PHYLO-03_2026
5
+ Generated: 2026-03-07
6
+
7
+ ---
8
+
9
+ ## 10 Underexplored Research Directions
10
+
11
+ ### Domain Coverage
12
+ - **LNP drug delivery** (brain/GBM focus): Directions 1–4
13
+ - **Cancer liquid biopsy biomarkers**: Directions 5–7
14
+ - **Protein corona in disease context**: Directions 8–10
15
+
16
+ ---
17
+
18
+ | # | Direction | Why Underexplored | Data That Exists | Experiment Design | Cost Estimate (USD) |
19
+ |---|-----------|-------------------|-----------------|-------------------|---------------------|
20
+ | 1 | **ApoE isoform-specific LNP corona engineering for GBM** — Exploiting ApoE2/E3/E4 differential LDLR/LRP1 binding to tune BBB transcytosis efficiency of ionizable LNPs | ApoE isoform effects on LNP uptake are studied in liver but almost never in brain endothelium or GBM models. Most BBB-LNP studies use pooled human serum ignoring isoform heterogeneity. | ApoE isoform LDLR binding affinities (structural data); LNP-ApoE corona proteomics (liver); LRP1 expression atlas in brain endothelium (HPA); GBM patient ApoE genotyping (TCGA) | (1) Formulate 3 ionizable LNP variants (MC3, DLin-KC2, Lipid 5); (2) Incubate with ApoE2/E3/E4-spiked plasma; (3) Quantify corona by LC-MS/MS; (4) Test BBB transcytosis in hCMEC/D3 monolayer; (5) Validate in orthotopic GBM mouse model stratified by ApoE genotype | $85,000–$140,000 |
21
+ | 2 | **Focused ultrasound (FUS) + LNP synergy for DIPG delivery** — Using low-intensity FUS to transiently open the BBB at the pons specifically for LNP-mRNA delivery in diffuse intrinsic pontine glioma | DIPG is almost universally fatal with no effective systemic therapy. FUS-BBB opening is validated in GBM but the pons presents unique anatomical and safety challenges. LNP-FUS combination is essentially unstudied in DIPG. | FUS BBB-opening safety data (GBM trials); DIPG transcriptome (CBTTC); LNP-mRNA efficacy in GBM models; Pons anatomy MRI atlases | (1) Establish DIPG patient-derived xenograft (PDX) in pons; (2) Optimize FUS parameters for pontine BBB opening (MRI-guided); (3) Deliver LNP-mRNA (IL-12 or H3K27M-targeting) post-FUS; (4) Measure delivery efficiency by luciferase reporter; (5) Assess safety by MRI + histology | $180,000–$260,000 |
22
+ | 3 | **Intranasal LNP delivery bypassing BBB for GBM — olfactory-trigeminal pathway optimization** | Intranasal delivery to brain is conceptually established but LNP formulation parameters for olfactory epithelium uptake vs. systemic absorption are poorly defined. No systematic formulation screen exists for GBM-relevant payloads. | Intranasal delivery pharmacokinetics (small molecules); Olfactory epithelium transcriptomics; LNP size-uptake relationships (liver); GBM mouse models | (1) Screen 12 LNP formulations varying size (50–200 nm), charge, PEG density; (2) Intranasal dosing in C57BL/6 mice; (3) Quantify brain vs. lung vs. liver distribution by fluorescence imaging; (4) Test in GL261 orthotopic GBM; (5) Measure tumor mRNA expression | $55,000–$90,000 |
23
+ | 4 | **LNP-mediated delivery of circular RNA (circRNA) for sustained GBM immunotherapy** | circRNA is more stable than linear mRNA (no 5'/3' ends for exonuclease degradation) and can drive prolonged protein expression. LNP formulation for circRNA is almost entirely unstudied — most circRNA delivery uses electroporation or viral vectors. | circRNA production protocols (in vitro); LNP-mRNA delivery benchmarks; GBM immunotherapy targets (IL-12, STING agonists); circRNA stability data | (1) Synthesize circRNA encoding IL-12 or anti-PD-L1 nanobody; (2) Formulate in ionizable LNPs (compare MC3 vs. Lipid 5); (3) Compare expression duration vs. linear mRNA-LNP in vitro; (4) Test in GBM organoids; (5) In vivo efficacy in GL261 model | $120,000–$200,000 |
24
+ | 5 | **cfRNA splicing isoform signatures as GBM liquid biopsy** — Tumor-specific alternative splicing events detectable in plasma cfRNA as GBM biomarkers | GBM sheds minimal ctDNA due to BBB. cfRNA from GBM-specific splicing (EGFRvIII, PTPRZ1-MET fusion) is theoretically detectable but no validated plasma cfRNA panel exists for GBM. Most liquid biopsy research focuses on solid tumors with high ctDNA shedding. | GBM splicing atlas (TCGA RNA-seq); EGFRvIII detection methods; cfRNA isolation protocols; Healthy donor cfRNA baseline (GTEx) | (1) Identify top 20 GBM-specific splicing events from TCGA; (2) Design RT-qPCR assays for plasma cfRNA; (3) Collect plasma from 30 GBM patients + 30 healthy controls; (4) Validate with ddPCR; (5) Correlate with tumor burden by MRI | $95,000–$150,000 |
25
+ | 6 | **Extracellular vesicle (EV) surface proteomics as pan-cancer early detection** — Using EV surface protein signatures (not cargo) as cancer-type-specific biomarkers | EV cargo (miRNA, cfDNA) is well-studied. EV surface proteomics by proximity labeling or aptamer arrays is technically feasible but rarely applied to early-stage cancer detection. Surface proteins are more stable and accessible than EV cargo. | EV proteomics databases (EVpedia, Vesiclepedia); Cancer-specific surface markers (HPA); EV isolation benchmarks; SomaScan aptamer platform data | (1) Isolate EVs from plasma of 50 early-stage cancer patients (5 types) + 50 controls by SEC; (2) Profile surface proteome by proximity labeling (BioID2) + LC-MS/MS; (3) Identify cancer-type-specific surface signatures; (4) Validate top 10 markers by aptamer array; (5) Build ML classifier | $200,000–$320,000 |
26
+ | 7 | **Clonal hematopoiesis (CHIP) interference correction in ctDNA liquid biopsy** — Developing computational methods to distinguish tumor-derived variants from CHIP-derived variants in cfDNA | CHIP affects >10% of adults >65 and generates somatic variants (DNMT3A, TET2, ASXL1) that contaminate ctDNA signals. No validated correction algorithm exists for routine clinical use, causing false-positive cancer detections. | CHIP variant databases (gnomAD somatic); ctDNA variant callers (GATK, Mutect2); Paired tumor-normal WGS datasets (TCGA); CHIP prevalence data (UK Biobank) | (1) Collect paired cfDNA + WBC DNA from 100 cancer patients; (2) Call variants in both fractions; (3) Identify CHIP-specific variant patterns (VAF, trinucleotide context); (4) Train random forest classifier to distinguish CHIP vs. tumor variants; (5) Validate in independent cohort | $130,000–$210,000 |
27
+ | 8 | **Disease-specific protein corona fingerprinting for cancer diagnosis** — Using the unique corona formed on standardized nanoparticle probes incubated in patient plasma as a cancer biomarker | The corona formed on a nanoparticle probe reflects the plasma proteome in a concentrated, amplified form. Different cancers produce distinct corona fingerprints. This "corona biopsy" concept has <10 publications and no clinical validation. | Plasma proteomics in cancer (CPTAC); Nanoparticle corona proteomics methods; LC-MS/MS cancer biomarker studies; Healthy donor plasma proteome (HPA) | (1) Incubate 5 standardized NP probes (varying charge/size) in plasma from 20 GBM + 20 PDAC + 20 healthy donors; (2) Elute and quantify corona by LC-MS/MS; (3) Identify cancer-type-specific corona signatures; (4) Build PCA/SVM classifier; (5) Validate in blinded cohort | $160,000–$250,000 |
28
+ | 9 | **Complement activation by LNPs in immunocompromised cancer patients** — Characterizing how chemotherapy-induced immunosuppression alters complement-mediated LNP clearance | Complement C3 deposition on LNPs triggers opsonization and rapid clearance. Cancer patients on chemotherapy have altered complement levels. LNP pharmacokinetics in immunocompromised patients is almost entirely unstudied despite being the primary clinical population. | Complement proteomics in cancer patients; LNP complement activation assays; Chemotherapy immunosuppression data; LNP PK in healthy volunteers | (1) Collect plasma from 30 cancer patients (pre/post chemotherapy) + 15 healthy controls; (2) Incubate LNPs in each plasma sample; (3) Quantify C3b/iC3b deposition by ELISA; (4) Measure LNP uptake by macrophages in complement-depleted vs. replete conditions; (5) Correlate with patient complement levels | $75,000–$120,000 |
29
+ | 10 | **Corona-mediated immunogenicity of LNP-mRNA in repeat-dosing cancer vaccine regimens** — Understanding how the evolving protein corona changes LNP immunogenicity across multiple vaccine doses | Cancer vaccines require multiple doses. Anti-PEG antibodies alter the corona on subsequent doses, potentially changing immunogenicity. The interplay between corona evolution, anti-PEG immunity, and vaccine efficacy is completely unstudied in multi-dose regimens. | Anti-PEG antibody prevalence data; LNP corona proteomics (single dose); mRNA vaccine immunogenicity data (COVID-19); Accelerated blood clearance (ABC) phenomenon literature | (1) Immunize mice with LNP-mRNA (3 doses, 3-week intervals); (2) Collect plasma after each dose; (3) Measure anti-PEG IgM/IgG by ELISA; (4) Incubate LNPs in post-dose plasma and profile corona by LC-MS/MS; (5) Correlate corona changes with T-cell and antibody responses | $90,000–$145,000 |
30
+
31
+ ---
32
+
33
+ ## Key Cross-Cutting Themes
34
+
35
+ 1. **ApoE biology** connects LNP brain targeting (Dir. 1, 2) with corona-mediated organ selectivity (Dir. 9)
36
+ 2. **Stability advantage** of circRNA (Dir. 4) and EV surface proteins (Dir. 6) over conventional analytes is underexploited
37
+ 3. **Patient heterogeneity** (ApoE genotype, CHIP status, immune status) is systematically ignored in LNP and liquid biopsy studies
38
+ 4. **Corona as diagnostic tool** (Dir. 8) inverts the usual framing — instead of preventing corona, using it as a signal
39
+
40
+ ## Recommended Priority Order (impact × feasibility)
41
+
42
+ | Priority | Direction | Rationale |
43
+ |----------|-----------|-----------|
44
+ | 1 | Dir. 3 (Intranasal LNP) | Low cost, high feasibility, unmet need in GBM |
45
+ | 2 | Dir. 7 (CHIP correction) | Computational, leverages existing datasets |
46
+ | 3 | Dir. 5 (cfRNA splicing GBM) | Addresses unique GBM liquid biopsy gap |
47
+ | 4 | Dir. 8 (Corona fingerprinting) | Novel concept, moderate cost |
48
+ | 5 | Dir. 1 (ApoE isoform LNP) | High impact if validated |
49
+
50
+ ---
51
+ *Analysis generated by K R&D Lab Cancer Research Suite | 2026-03-07*