Lincoln Gombedza Claude Sonnet 4.6 commited on
Commit
b5ac859
Β·
1 Parent(s): 7acb72a

fix: resolve broken HF Space + major enhancement to v2.0

Browse files

CRITICAL FIXES (app was not running):
- Dockerfile: fix entrypoint src/streamlit_app.py β†’ app.py (was running
placeholder spiral demo instead of the actual VirtualGeneScope app)
- requirements.txt: replace git+https://...alphagenome.git with
alphagenome==0.6.1 (PyPI) β€” git installs fail silently in Docker builds
- requirements.txt: pin all dependency versions for reproducibility
- requirements.txt: add python-docx>=1.1.0 for DOCX export
- Dockerfile: use python:3.11-slim (stable LTS) instead of 3.13.5-slim
- README.md: correct sdk: streamlit β†’ sdk: docker to match HF Space config

ENHANCEMENTS:
- Gene library expanded 14 β†’ 16 genes: added VKORC1 (Warfarin sensitivity)
and HLA-B (Abacavir/Carbamazepine severe hypersensitivity)
- All 16 genes now have: key SNP (rsID/HLA allele), inheritance pattern,
UK-specific nursing notes, NMC platform alignment, NICE guideline links,
ClinVar + OMIM + PharmGKB external links, tissue default
- Demo mode expanded: Chromatin Accessibility and Contact Map tracks added
(in addition to RNA Expression + Splicing)
- DOCX export: download formatted gene analysis report with charts,
nursing reference card, NMC alignment, and external links
- New Nurse Reference tab: per-gene PGx alert panels (poor/normal metaboliser),
NICE/ClinVar/OMIM/PharmGKB/NHS Genomics England link buttons
- New NMC Alignment tab: full Platform 1–7 checklist, genomics nursing resources
- Session History tab: last 10 analyses in dataframe with clear button
- Clinical disclaimer: upgraded to prominent st.warning banner
- NMC proficiency mapping for all 16 genes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (5) hide show
  1. .gitignore +2 -0
  2. Dockerfile +4 -5
  3. README.md +33 -21
  4. app.py +469 -361
  5. requirements.txt +7 -6
.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ ._*
2
+ .DS_Store
Dockerfile CHANGED
@@ -1,20 +1,19 @@
1
- FROM python:3.13.5-slim
2
 
3
  WORKDIR /app
4
 
5
  RUN apt-get update && apt-get install -y \
6
  build-essential \
7
  curl \
8
- git \
9
  && rm -rf /var/lib/apt/lists/*
10
 
11
  COPY requirements.txt ./
12
- COPY src/ ./src/
13
 
14
- RUN pip3 install -r requirements.txt
15
 
16
  EXPOSE 8501
17
 
18
  HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
19
 
20
- ENTRYPOINT ["streamlit", "run", "src/streamlit_app.py", "--server.port=8501", "--server.address=0.0.0.0"]
 
1
+ FROM python:3.11-slim
2
 
3
  WORKDIR /app
4
 
5
  RUN apt-get update && apt-get install -y \
6
  build-essential \
7
  curl \
 
8
  && rm -rf /var/lib/apt/lists/*
9
 
10
  COPY requirements.txt ./
11
+ RUN pip3 install --no-cache-dir -r requirements.txt
12
 
13
+ COPY app.py ./
14
 
15
  EXPOSE 8501
16
 
17
  HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
18
 
19
+ ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
README.md CHANGED
@@ -1,35 +1,47 @@
1
  ---
2
- title: Virtual Gene Scope
3
  emoji: 🧬
4
- colorFrom: blue
5
- colorTo: green
6
- sdk: streamlit
7
- sdk_version: 1.41.1
8
- app_file: app.py
9
  pinned: false
 
10
  tags:
11
  - streamlit
12
  - nursing
13
  - genomics
14
  - alphagenome
 
 
 
15
  ---
16
 
17
- # Virtual Gene Scope
18
 
19
- A nursing education tool to visualize the "Regulatory Genome" using Google DeepMind's AlphaGenome (Mocked/API).
20
 
21
- ## Overview
22
- This application demonstrates how non-coding variants can impact gene expression, helping nurses understand complex genetic conditions beyond simple protein-coding errors.
23
 
24
- ## Features
25
- - **Gene Selector**: Inspect key genes (e.g., *INS*, *SCN9A*).
26
- - **Mutation Simulator**: Introduce variants in regulatory regions.
27
- - **Visual Tracks**: See predicted changes in Promoter Activity and Splicing.
28
 
29
- ## Usage
30
- 1. Run locally:
31
- ```bash
32
- pip install -r requirements.txt
33
- streamlit run app.py
34
- ```
35
- 2. Deploy to Hugging Face Spaces (CPU Basic).
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Virtual Gene Scope v2.0
3
  emoji: 🧬
4
+ colorFrom: purple
5
+ colorTo: blue
6
+ sdk: docker
7
+ app_port: 8501
 
8
  pinned: false
9
+ license: apache-2.0
10
  tags:
11
  - streamlit
12
  - nursing
13
  - genomics
14
  - alphagenome
15
+ - pharmacogenomics
16
+ - uk-nursing
17
+ - nmc
18
  ---
19
 
20
+ # 🧬 Virtual Gene Scope v2.0
21
 
22
+ **Explore the Regulatory Genome with Google DeepMind's AlphaGenome.**
23
 
24
+ An educational tool for nursing students and healthcare professionals to visualise how non-coding genetic variants affect gene regulation β€” covering expression, splicing, chromatin accessibility, and contact maps.
 
25
 
26
+ > *Built by nurses who code. For nurses who care about genomics.*
27
+ > *Part of the [CQAI Nursing Education Toolkit](https://github.com/Clinical-Quality-Artifical-Intelligence)*
 
 
28
 
29
+ ---
30
+
31
+ ## βš•οΈ Clinical Disclaimer
32
+
33
+ This tool is for **educational purposes only**. It does not make clinical decisions and must not be used for patient care without independent verification by qualified healthcare professionals.
34
+
35
+ ---
36
+
37
+ ## ✨ Features
38
+
39
+ - πŸ₯ **Disease Risk Mode** β€” Explore pathogenic variants in 8 disease-associated genes
40
+ - πŸ’Š **Drug Response Mode (PGx)** β€” See how variants affect drug metabolism (8 PGx genes)
41
+ - πŸ§ͺ **Custom Variant Mode** β€” Input any variant and see predicted effects
42
+ - πŸ«€ **Tissue Context** β€” Select from 10 tissue types with UBERON ontology terms
43
+ - πŸ“Š **Multi-modal Demo Tracks** β€” RNA expression, splicing, chromatin accessibility
44
+ - πŸ‘©β€βš•οΈ **Nursing Reference Cards** β€” NMC-aligned clinical guidance per gene
45
+ - πŸ“Ž **DOCX Report Export** β€” Download a formatted gene analysis report
46
+ - πŸ”— **ClinVar / PharmGKB / OMIM links** β€” Direct links to authoritative databases
47
+ - πŸŽ“ **NMC Proficiency Map** β€” Standards of Proficiency alignment per gene
app.py CHANGED
@@ -1,10 +1,28 @@
1
- import streamlit as st
2
- import pandas as pd
3
- import numpy as np
4
- import matplotlib.pyplot as plt
 
 
 
 
 
 
 
5
  import os
6
 
7
- # Try importing AlphaGenome, handle failure gracefully
 
 
 
 
 
 
 
 
 
 
 
8
  try:
9
  from alphagenome.models import dna_client
10
  from alphagenome.data import genome
@@ -13,388 +31,478 @@ try:
13
  except ImportError:
14
  HAS_ALPHAGENOME = False
15
 
16
- # Page Config
17
- st.set_page_config(
18
- page_title="Virtual Gene Scope v2.0",
19
- page_icon="🧬",
20
- layout="wide"
21
- )
22
 
23
- # Clean Light Theme CSS
24
  st.markdown("""
25
  <style>
26
- .stApp {
27
- background-color: #f8f9fa;
28
- }
29
- .main-header {
30
- color: #2c3e50;
31
- font-size: 2.5rem;
32
- font-weight: bold;
33
- text-align: center;
34
- }
35
- .metric-card {
36
- background: white;
37
- border-radius: 15px;
38
- padding: 1.5rem;
39
- border: 1px solid #e0e0e0;
40
- box-shadow: 0 2px 8px rgba(0,0,0,0.08);
41
- margin: 0.5rem 0;
42
- }
43
- .gene-badge {
44
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
45
- color: white;
46
- padding: 5px 15px;
47
- border-radius: 20px;
48
- font-weight: bold;
49
- display: inline-block;
50
- }
51
- .alert-box {
52
- background: #fff5f5;
53
- border-left: 4px solid #e53e3e;
54
- padding: 1rem;
55
- border-radius: 0 10px 10px 0;
56
- margin: 1rem 0;
57
- color: #c53030;
58
- }
59
- .success-box {
60
- background: #f0fff4;
61
- border-left: 4px solid #38a169;
62
- padding: 1rem;
63
- border-radius: 0 10px 10px 0;
64
- margin: 1rem 0;
65
- color: #276749;
66
- }
67
  </style>
68
  """, unsafe_allow_html=True)
69
 
70
- # Application Header
71
- st.markdown('<h1 class="main-header">🧬 Virtual Gene Scope v2.0</h1>', unsafe_allow_html=True)
72
- st.markdown("""
73
- <p style="text-align: center; color: #4a5568; font-size: 1.1rem;">
74
- Explore the Regulatory Genome with Google DeepMind's AlphaGenome<br>
75
- <em>Multi-modal predictions: Expression β€’ Splicing β€’ Chromatin β€’ Contact Maps</em>
76
- </p>
77
- """, unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- # Sidebar controls
80
- st.sidebar.header("πŸ”¬ Analysis Settings")
 
 
 
81
 
82
- # 1. Mode Selector with icons
83
- analysis_mode = st.sidebar.radio(
84
- "Select Analysis Mode",
85
- ["πŸ₯ Disease Risk (Pathology)", "πŸ’Š Drug Response (PGx)", "πŸ§ͺ Custom Variant"],
86
- index=0
87
- )
88
 
89
- gene_sym = "INS"
90
- gene_label = "INS"
91
- drug_label = None
 
 
 
92
 
93
- # EXPANDED GENE LIBRARY
94
- GENE_LIBRARY = {
95
- # Disease Risk Genes
96
- "INS (Diabetes - Insulin)": {"sym": "INS", "chr": "chr11", "start": 2151808, "end": 2168192, "pos": 2160000, "category": "disease"},
97
- "SCN9A (Pain Sensitivity)": {"sym": "SCN9A", "chr": "chr2", "start": 166191808, "end": 166208192, "pos": 166200000, "category": "disease"},
98
- "MMP9 (Wound Healing)": {"sym": "MMP9", "chr": "chr20", "start": 46006808, "end": 46023192, "pos": 46015000, "category": "disease"},
99
- "HBB (Sickle Cell/Thalassemia)": {"sym": "HBB", "chr": "chr11", "start": 5218808, "end": 5235192, "pos": 5227000, "category": "disease"},
100
- "BRCA1 (Breast Cancer)": {"sym": "BRCA1", "chr": "chr17", "start": 43054808, "end": 43071192, "pos": 43063000, "category": "disease"},
101
- "LDLR (Hypercholesterolemia)": {"sym": "LDLR", "chr": "chr19", "start": 11104808, "end": 11121192, "pos": 11113000, "category": "disease"},
102
- "CFTR (Cystic Fibrosis)": {"sym": "CFTR", "chr": "chr7", "start": 117472808, "end": 117489192, "pos": 117481000, "category": "disease"},
103
- "DMD (Muscular Dystrophy)": {"sym": "DMD", "chr": "chrX", "start": 31119808, "end": 31136192, "pos": 31128000, "category": "disease"},
104
- # PGx Genes
105
- "CYP2C9 (Warfarin)": {"sym": "CYP2C9", "chr": "chr10", "start": 94981200, "end": 94997584, "pos": 94989392, "category": "pgx", "drug": "Warfarin"},
106
- "CYP2C19 (Clopidogrel)": {"sym": "CYP2C19", "chr": "chr10", "start": 94775000, "end": 94791384, "pos": 94783192, "category": "pgx", "drug": "Clopidogrel"},
107
- "CYP2D6 (Codeine/Tramadol)": {"sym": "CYP2D6", "chr": "chr22", "start": 42118000, "end": 42134384, "pos": 42126192, "category": "pgx", "drug": "Opioids"},
108
- "SLCO1B1 (Simvastatin)": {"sym": "SLCO1B1", "chr": "chr12", "start": 21132000, "end": 21148384, "pos": 21140192, "category": "pgx", "drug": "Statins"},
109
- "TPMT (6-Mercaptopurine)": {"sym": "TPMT", "chr": "chr6", "start": 18139000, "end": 18155384, "pos": 18147192, "category": "pgx", "drug": "Thiopurines"},
110
- "DPYD (5-Fluorouracil)": {"sym": "DPYD", "chr": "chr1", "start": 97878000, "end": 97894384, "pos": 97886192, "category": "pgx", "drug": "Fluoropyrimidines"},
111
- }
112
 
113
- # Filter genes by mode
114
- if "Disease" in analysis_mode:
115
- filtered_genes = {k: v for k, v in GENE_LIBRARY.items() if v["category"] == "disease"}
116
- elif "PGx" in analysis_mode:
117
- filtered_genes = {k: v for k, v in GENE_LIBRARY.items() if v["category"] == "pgx"}
118
  else:
119
- filtered_genes = GENE_LIBRARY
120
-
121
- gene_label = st.sidebar.selectbox("Select Gene", list(filtered_genes.keys()))
122
- gene_info = filtered_genes[gene_label]
123
- gene_sym = gene_info["sym"]
124
-
125
- # Display gene info card
126
- st.sidebar.markdown(f"""
127
- <div class="metric-card">
128
- <span class="gene-badge">{gene_sym}</span><br><br>
129
- <strong>πŸ“ Location:</strong> {gene_info['chr']}:{gene_info['start']:,}-{gene_info['end']:,}<br>
130
- <strong>πŸ“ Window:</strong> {(gene_info['end']-gene_info['start']):,} bp
131
- </div>
132
- """, unsafe_allow_html=True)
133
 
134
- # Tissue Context Selector
135
  st.sidebar.markdown("---")
136
  st.sidebar.subheader("πŸ«€ Tissue Context")
 
 
 
137
 
138
- TISSUE_OPTIONS = {
139
- "Blood (General)": "UBERON:0000178",
140
- "Liver": "UBERON:0002107",
141
- "Skin": "UBERON:0002097",
142
- "Breast": "UBERON:0000310",
143
- "Brain": "UBERON:0000955",
144
- "Lung": "UBERON:0002048",
145
- "Heart": "UBERON:0000948",
146
- "Kidney": "UBERON:0002113",
147
- "Pancreas": "UBERON:0001264",
148
- "Muscle": "UBERON:0002385"
149
- }
150
 
151
- # Smart tissue default
152
- default_tissue = "Liver" if "PGx" in analysis_mode else "Blood (General)"
153
- tissue_label = st.sidebar.selectbox("Select Tissue", list(TISSUE_OPTIONS.keys()),
154
- index=list(TISSUE_OPTIONS.keys()).index(default_tissue))
155
- ontology_term = TISSUE_OPTIONS[tissue_label]
156
 
157
- # Output Modalities
158
  st.sidebar.markdown("---")
159
- st.sidebar.subheader("πŸ“Š Output Modalities")
 
160
 
161
- output_modalities = st.sidebar.multiselect(
162
- "Select predictions to display",
163
- ["RNA Expression", "Splicing", "Chromatin Accessibility", "Contact Map"],
164
- default=["RNA Expression", "Splicing"]
165
- )
 
 
 
 
 
 
 
 
 
 
166
 
167
- # Mutation Controls (for Custom mode)
168
- if "Custom" in analysis_mode:
169
- st.sidebar.markdown("---")
170
- st.sidebar.subheader("🧬 Variant Input")
171
-
172
- variant_position = st.sidebar.number_input(
173
- "Position",
174
- min_value=gene_info['start'],
175
- max_value=gene_info['end'],
176
- value=gene_info['pos']
177
- )
178
-
179
- col1, col2 = st.sidebar.columns(2)
180
- with col1:
181
- ref_base = st.selectbox("REF", ["A", "T", "G", "C"], index=0)
182
- with col2:
183
- alt_base = st.selectbox("ALT", ["A", "T", "G", "C"], index=2)
184
- else:
185
- variant_position = gene_info['pos']
186
- ref_base = "A"
187
- alt_base = "C"
188
 
189
- mutation_intensity = st.sidebar.slider(
190
- "Mutation Impact (Simulation)",
191
- 0.0, 1.0, 0.5,
192
- help="Simulate the severity of the regulatory disruption."
193
- )
 
 
 
 
 
 
 
194
 
195
- # Main Content Area
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  st.markdown("---")
 
 
 
 
 
 
 
 
 
 
 
197
 
198
- # Check API
199
- api_key = os.environ.get("ALPHAGENOME_API_KEY") or st.secrets.get("ALPHAGENOME_API_KEY")
200
-
201
- if not HAS_ALPHAGENOME:
202
- st.error("❌ AlphaGenome library not installed. Run: `pip install alphagenome`")
203
- st.stop()
204
-
205
- if not api_key:
206
- st.warning("⚠️ No API Key found in environment or secrets. Showing demonstration mode.")
207
-
208
- # DEMO MODE with realistic mock data
209
- col1, col2 = st.columns([1, 2])
210
-
211
- with col1:
212
- st.subheader("πŸ“‹ Analysis Summary")
213
- st.markdown(f"""
214
- <div class="metric-card">
215
- <strong>Gene:</strong> {gene_sym}<br>
216
- <strong>Tissue:</strong> {tissue_label}<br>
217
- <strong>Variant:</strong> {gene_info['chr']}:{variant_position} {ref_base}>{alt_base}
218
- </div>
219
- """, unsafe_allow_html=True)
220
-
221
- # Clinical Implications
222
- st.subheader("πŸ‘©β€βš•οΈ Clinical Implications")
223
-
224
- if gene_info.get("category") == "pgx":
225
- drug = gene_info.get("drug", "Unknown")
226
- if mutation_intensity > 0.6:
227
- st.markdown(f"""
228
- <div class="alert-box">
229
- <strong>⚠️ ADVERSE DRUG REACTION RISK</strong><br>
230
- <strong>Drug:</strong> {drug}<br>
231
- <strong>Phenotype:</strong> Poor Metabolizer<br>
232
- <strong>Action:</strong> Consider dose reduction or alternative therapy
233
- </div>
234
- """, unsafe_allow_html=True)
235
  else:
236
- st.markdown(f"""
237
- <div class="success-box">
238
- <strong>βœ… STANDARD DOSING</strong><br>
239
- <strong>Drug:</strong> {drug}<br>
240
- <strong>Phenotype:</strong> Normal Metabolizer<br>
241
- <strong>Action:</strong> Standard protocol applies
242
- </div>
243
- """, unsafe_allow_html=True)
244
  else:
245
- implications = {
246
- "INS": "Disruption affects **Insulin production**. May lead to hyperglycemia.",
247
- "MMP9": "Key enzyme in wound remodeling. Poor regulation leads to **chronic wounds**.",
248
- "BRCA1": "Tumor suppressor. Loss increases **Breast/Ovarian Cancer** risk.",
249
- "SCN9A": "Pain signaling. Changes cause **chronic pain** or **insensitivity**.",
250
- "HBB": "Beta-Globin. Variants cause **Thalassemia** or **Sickle Cell**.",
251
- "LDLR": "Cholesterol clearance. Low expression = **Hypercholesterolemia**.",
252
- "CFTR": "Chloride channel. Variants cause **Cystic Fibrosis**.",
253
- "DMD": "Muscle protein. Variants cause **Muscular Dystrophy**."
254
- }
255
- st.info(implications.get(gene_sym, "Regulatory variant detected."))
256
-
257
- with col2:
258
- st.subheader("πŸ“ˆ Predicted Tracks (Demo)")
259
-
260
- # Generate mock tracks
261
- x = np.linspace(0, 100, 500)
262
-
263
- if "RNA Expression" in output_modalities:
264
- fig, ax = plt.subplots(figsize=(10, 4))
265
- ref_signal = np.exp(-((x - 50)**2) / 200) + np.random.normal(0, 0.02, len(x))
266
- alt_signal = ref_signal * (1 - mutation_intensity * 0.6) + np.random.normal(0, 0.02, len(x))
267
-
268
- ax.fill_between(x, ref_signal, alpha=0.4, color='#4CAF50', label='Reference')
269
- ax.fill_between(x, alt_signal, alpha=0.4, color='#ff4b4b', label='Alternate')
270
- ax.axvline(x=50, color='orange', linestyle='--', alpha=0.7, label='Variant')
271
- ax.set_title(f'{gene_sym} RNA Expression')
272
- ax.set_xlabel('Genomic Position (relative)')
273
- ax.set_ylabel('Predicted Signal')
274
- ax.legend()
275
- ax.set_facecolor('white')
276
- fig.patch.set_facecolor('white')
277
- ax.spines['top'].set_visible(False)
278
- ax.spines['right'].set_visible(False)
279
- ax.grid(True, alpha=0.3)
280
- st.pyplot(fig)
281
-
282
- if "Splicing" in output_modalities:
283
- fig2, ax2 = plt.subplots(figsize=(10, 3))
284
- splice_ref = np.zeros_like(x)
285
- splice_ref[150:160] = 0.9
286
- splice_ref[350:360] = 0.85
287
- splice_alt = splice_ref.copy()
288
- splice_alt[150:160] *= (1 - mutation_intensity)
289
-
290
- ax2.bar(x[150:160], splice_ref[150:160], width=0.5, alpha=0.6, color='#4CAF50', label='REF')
291
- ax2.bar(x[150:160], splice_alt[150:160], width=0.3, alpha=0.8, color='#ff4b4b', label='ALT')
292
- ax2.bar(x[350:360], splice_ref[350:360], width=0.5, alpha=0.6, color='#4CAF50')
293
- ax2.bar(x[350:360], splice_alt[350:360], width=0.3, alpha=0.8, color='#ff4b4b')
294
- ax2.set_title('Splice Site Usage')
295
- ax2.set_facecolor('white')
296
- fig2.patch.set_facecolor('white')
297
- ax2.spines['top'].set_visible(False)
298
- ax2.spines['right'].set_visible(False)
299
- ax2.grid(True, alpha=0.3)
300
- st.pyplot(fig2)
301
 
302
- else:
303
- # REAL API MODE
304
- st.sidebar.success("βœ… AlphaGenome API Connected")
305
-
306
- model = dna_client.create(api_key)
307
-
308
- try:
309
- with st.spinner(f"πŸ”¬ Querying AlphaGenome for {gene_sym} in {tissue_label}..."):
310
- interval = genome.Interval(
311
- chromosome=gene_info["chr"],
312
- start=gene_info["start"],
313
- end=gene_info["end"]
314
- )
315
-
316
- variant = genome.Variant(
317
- chromosome=gene_info["chr"],
318
- position=variant_position,
319
- reference_bases=ref_base,
320
- alternate_bases=alt_base
321
- )
322
-
323
- # AlphaGenome API - use RNA_SEQ (verified working output type)
324
- # Note: Other modalities like splicing use different API methods
325
- outputs = model.predict_variant(
326
- interval=interval,
327
- variant=variant,
328
- ontology_terms=[ontology_term],
329
- requested_outputs=[dna_client.OutputType.RNA_SEQ],
330
- )
331
-
332
- # Display Results
333
- col1, col2 = st.columns([1, 2])
334
-
335
- with col1:
336
- st.subheader("πŸ“‹ Analysis Context")
337
- st.markdown(f"**Gene**: `{gene_sym}`")
338
- st.markdown(f"**Tissue**: `{tissue_label}`")
339
- st.markdown(f"**Variant**: `{gene_info['chr']}:{variant_position} {ref_base}>{alt_base}`")
340
-
341
- # Clinical guidance based on category
342
- st.subheader("πŸ‘©β€βš•οΈ Clinical Guidance")
343
- if gene_info.get("category") == "pgx":
344
- drug = gene_info.get("drug", "Unknown")
345
- st.warning(f"**PGx Alert**: This gene affects {drug} metabolism.")
346
- else:
347
- st.info("Regulatory variant analysis complete. Review tracks for impact.")
348
-
349
- with col2:
350
- st.subheader(f"πŸ“ˆ AlphaGenome Predictions ({tissue_label})")
351
-
352
- # RNA Expression Track
353
- if hasattr(outputs.reference, 'rna_seq'):
354
- fig = plot_components.plot(
355
- [
356
- plot_components.OverlaidTracks(
357
- tdata={
358
- 'REF': outputs.reference.rna_seq,
359
- 'ALT': outputs.alternate.rna_seq,
360
- },
361
- colors={'REF': 'dimgrey', 'ALT': '#ff4b4b'},
362
- ),
363
- ],
364
- interval=outputs.reference.rna_seq.interval.resize(2**14),
365
- annotations=[plot_components.VariantAnnotation([variant], alpha=0.8)],
366
- )
367
- st.pyplot(fig)
368
-
369
- # Splicing Track
370
- if hasattr(outputs.reference, 'splice_site'):
371
- fig2 = plot_components.plot(
372
- [
373
- plot_components.OverlaidTracks(
374
- tdata={
375
- 'REF': outputs.reference.splice_site,
376
- 'ALT': outputs.alternate.splice_site,
377
- },
378
- colors={'REF': 'dimgrey', 'ALT': '#ff4b4b'},
379
- ),
380
- ],
381
- interval=outputs.reference.splice_site.interval.resize(2**14),
382
- annotations=[plot_components.VariantAnnotation([variant], alpha=0.8)],
383
- )
384
- st.pyplot(fig2)
385
-
386
- except Exception as e:
387
- st.error(f"API Error: {str(e)}")
388
- st.info("Please check your API key and try again.")
389
-
390
- # Footer
391
- st.markdown("---")
392
- st.markdown("""
393
- <div style="text-align: center; color: #718096; font-size: 0.9rem;">
394
- <p><strong>Virtual Gene Scope v2.0</strong> | Powered by <strong>Google DeepMind AlphaGenome</strong></p>
395
- <p>πŸ“š <a href="https://www.nature.com/articles/s41586-025-10014-0" target="_blank" style="color: #667eea;">Nature Paper</a> |
396
- πŸ”— <a href="https://github.com/google-deepmind/alphagenome" target="_blank" style="color: #667eea;">AlphaGenome GitHub</a> |
397
- πŸŽ“ Part of the <strong>Nursing Genomics Education Toolkit</strong></p>
398
- </div>
399
- """, unsafe_allow_html=True)
400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Virtual Gene Scope v2.0
3
+ =======================
4
+ Educational genomics tool for nursing students and healthcare professionals.
5
+ Powered by Google DeepMind's AlphaGenome.
6
+
7
+ Part of the CQAI Nursing Education Toolkit.
8
+ Built by Clinical Quality Artificial Intelligence β€” Nurse Citizen Developers.
9
+ """
10
+
11
+ import io
12
  import os
13
 
14
+ import matplotlib.pyplot as plt
15
+ import numpy as np
16
+ import pandas as pd
17
+ import streamlit as st
18
+
19
+ try:
20
+ from docx import Document
21
+ from docx.shared import RGBColor
22
+ HAS_DOCX = True
23
+ except ImportError:
24
+ HAS_DOCX = False
25
+
26
  try:
27
  from alphagenome.models import dna_client
28
  from alphagenome.data import genome
 
31
  except ImportError:
32
  HAS_ALPHAGENOME = False
33
 
34
+ # ---------------------------------------------------------------------------
35
+ st.set_page_config(page_title="Virtual Gene Scope v2.0", page_icon="🧬", layout="wide")
 
 
 
 
36
 
 
37
  st.markdown("""
38
  <style>
39
+ .stApp{background:#f8f9fa}
40
+ .main-header{color:#2c3e50;font-size:2.3rem;font-weight:700;text-align:center}
41
+ .metric-card{background:#fff;border-radius:12px;padding:1.2rem;border:1px solid #e0e0e0;box-shadow:0 2px 8px rgba(0,0,0,.06);margin:.4rem 0}
42
+ .gene-badge{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;padding:4px 14px;border-radius:20px;font-weight:700;display:inline-block}
43
+ .alert-box{background:#fff5f5;border-left:4px solid #e53e3e;padding:1rem;border-radius:0 10px 10px 0;margin:.8rem 0;color:#c53030}
44
+ .success-box{background:#f0fff4;border-left:4px solid #38a169;padding:1rem;border-radius:0 10px 10px 0;margin:.8rem 0;color:#276749}
45
+ .info-card{background:#ebf8ff;border-left:4px solid #3182ce;padding:1rem;border-radius:0 10px 10px 0;margin:.8rem 0;color:#2c5282}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  </style>
47
  """, unsafe_allow_html=True)
48
 
49
+ # ---------------------------------------------------------------------------
50
+ # Gene Library β€” 16 genes (8 disease + 8 PGx)
51
+ # ---------------------------------------------------------------------------
52
+ GENE_LIBRARY = {
53
+ "INS (Diabetes β€” Insulin)": {
54
+ "sym":"INS","chr":"chr11","start":2151808,"end":2168192,"pos":2160000,
55
+ "category":"disease","omim":"176730","key_snp":"rs5219",
56
+ "inheritance":"Complex / AD (MODY10)","tissue_default":"Pancreas",
57
+ "condition":"Type 1 & Type 2 Diabetes, Neonatal Diabetes",
58
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=INS",
59
+ "nursing_note":"Variants in INS reduce or abolish insulin secretion. Monitor BM, HbA1c, and signs of DKA. Patients may need insulin therapy from birth (neonatal DM). Educate on hypoglycaemia recognition and sick-day rules.",
60
+ "nmc_platforms":["3 β€” Assessing needs and planning care","4 β€” Providing and evaluating care"],
61
+ "nice_link":"https://www.nice.org.uk/guidance/ng17","nice_label":"NICE NG17 (Type 1 Diabetes)",
62
+ },
63
+ "SCN9A (Pain Sensitivity)": {
64
+ "sym":"SCN9A","chr":"chr2","start":166191808,"end":166208192,"pos":166200000,
65
+ "category":"disease","omim":"603415","key_snp":"rs6746030",
66
+ "inheritance":"AD / AR","tissue_default":"Brain",
67
+ "condition":"Chronic pain syndromes, Congenital Insensitivity to Pain",
68
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=SCN9A",
69
+ "nursing_note":"Gain-of-function variants cause severe chronic pain (erythromelalgia). Loss-of-function causes insensitivity to pain β€” patients cannot feel injury. Assess pain carefully; standard pain scales may be unreliable.",
70
+ "nmc_platforms":["3 β€” Assessing needs and planning care","6 β€” Improving safety and quality"],
71
+ "nice_link":"https://www.nice.org.uk/guidance/ng193","nice_label":"NICE NG193 (Chronic Pain)",
72
+ },
73
+ "MMP9 (Wound Healing)": {
74
+ "sym":"MMP9","chr":"chr20","start":46006808,"end":46023192,"pos":46015000,
75
+ "category":"disease","omim":"120361","key_snp":"rs3918242",
76
+ "inheritance":"Complex","tissue_default":"Skin",
77
+ "condition":"Chronic wound risk, diabetic ulcers, keloid scarring",
78
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=MMP9",
79
+ "nursing_note":"MMP9 regulates extracellular matrix remodelling. Over-expression impairs wound healing. Assess using TIME/TIMPE framework. Refer to TVN for wounds not healing within 4 weeks. Apply SSKIN bundle for pressure injury prevention.",
80
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety and quality"],
81
+ "nice_link":"https://www.nice.org.uk/guidance/cg179","nice_label":"NICE CG179 (Pressure Ulcers)",
82
+ },
83
+ "HBB (Sickle Cell / Thalassaemia)": {
84
+ "sym":"HBB","chr":"chr11","start":5218808,"end":5235192,"pos":5227000,
85
+ "category":"disease","omim":"141900","key_snp":"rs334",
86
+ "inheritance":"AR","tissue_default":"Blood (General)",
87
+ "condition":"Sickle Cell Disease, Ξ²-Thalassaemia",
88
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=HBB",
89
+ "nursing_note":"HBB c.20A>T (rs334) causes the Glu→Val substitution in sickle cell disease. Monitor for vaso-occlusive crises, acute chest syndrome, and stroke. High pain, O₂ therapy, IV fluids, and hydroxyurea are pillars of care. NHS Newborn Blood Spot Screening detects this.",
90
+ "nmc_platforms":["3 β€” Assessing needs and planning care","4 β€” Providing and evaluating care"],
91
+ "nice_link":"https://www.nice.org.uk/guidance/ng143","nice_label":"NICE NG143 (Sickle Cell)",
92
+ },
93
+ "BRCA1 (Breast / Ovarian Cancer)": {
94
+ "sym":"BRCA1","chr":"chr17","start":43054808,"end":43071192,"pos":43063000,
95
+ "category":"disease","omim":"113705","key_snp":"rs28897672",
96
+ "inheritance":"AD","tissue_default":"Breast",
97
+ "condition":"Hereditary Breast and Ovarian Cancer Syndrome",
98
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=BRCA1",
99
+ "nursing_note":"BRCA1 pathogenic variants confer ~70% lifetime breast cancer risk. Refer to Clinical Genetics. Discuss prophylactic options sensitively. Support emotional wellbeing β€” diagnosis affects the whole family. Signpost to Breast Cancer Now and FORCE charity.",
100
+ "nmc_platforms":["2 β€” Promoting health and preventing ill health","3 β€” Assessing needs"],
101
+ "nice_link":"https://www.nice.org.uk/guidance/dg27","nice_label":"NICE DG27 (BRCA Testing)",
102
+ },
103
+ "LDLR (Familial Hypercholesterolaemia)": {
104
+ "sym":"LDLR","chr":"chr19","start":11104808,"end":11121192,"pos":11113000,
105
+ "category":"disease","omim":"606945","key_snp":"rs28942080",
106
+ "inheritance":"AD","tissue_default":"Liver",
107
+ "condition":"Familial Hypercholesterolaemia (FH)",
108
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=LDLR",
109
+ "nursing_note":"FH affects 1 in 250 people in the UK. LDLR variants impair LDL clearance causing premature atherosclerosis. Monitor lipid profile, statins are first-line. Cascade screening of family members is essential.",
110
+ "nmc_platforms":["2 β€” Promoting health and preventing ill health","4 β€” Providing care"],
111
+ "nice_link":"https://www.nice.org.uk/guidance/cg71","nice_label":"NICE CG71 (FH)",
112
+ },
113
+ "CFTR (Cystic Fibrosis)": {
114
+ "sym":"CFTR","chr":"chr7","start":117472808,"end":117489192,"pos":117481000,
115
+ "category":"disease","omim":"602421","key_snp":"rs113993960",
116
+ "inheritance":"AR","tissue_default":"Lung",
117
+ "condition":"Cystic Fibrosis",
118
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=CFTR",
119
+ "nursing_note":"CFTR F508del is the most common CF variant. Impaired chloride transport causes thick mucus in lungs, pancreas, and intestine. Daily physiotherapy, enzyme replacement, and CFTR modulators (e.g. Kaftrio) are transforming outcomes. NHS newborn screening via IRT/DNA test.",
120
+ "nmc_platforms":["3 β€” Assessing needs","4 β€” Providing and evaluating care"],
121
+ "nice_link":"https://www.nice.org.uk/guidance/ta398","nice_label":"NICE TA398 (Lumacaftor/Ivacaftor)",
122
+ },
123
+ "DMD (Muscular Dystrophy)": {
124
+ "sym":"DMD","chr":"chrX","start":31119808,"end":31136192,"pos":31128000,
125
+ "category":"disease","omim":"300377","key_snp":"rs137852596",
126
+ "inheritance":"XL recessive","tissue_default":"Muscle",
127
+ "condition":"Duchenne / Becker Muscular Dystrophy",
128
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=DMD",
129
+ "nursing_note":"DMD deletion/duplication of exons causes out-of-frame transcripts. Progressive muscle weakness; most boys need wheelchair by teen years. Monitor respiratory function (FVC), cardiac function (cardiomyopathy), and swallowing. Corticosteroids slow progression.",
130
+ "nmc_platforms":["3 β€” Assessing needs","7 β€” Coordinating care"],
131
+ "nice_link":"https://www.nice.org.uk/guidance/ng238","nice_label":"NICE NG238 (Duchenne MD)",
132
+ },
133
+ # PGx
134
+ "CYP2C9 (Warfarin metabolism)": {
135
+ "sym":"CYP2C9","chr":"chr10","start":94981200,"end":94997584,"pos":94989392,
136
+ "category":"pgx","drug":"Warfarin","omim":"601130",
137
+ "key_snp":"rs1799853 (*2), rs1057910 (*3)","inheritance":"Pharmacogenomic",
138
+ "tissue_default":"Liver","condition":"Altered Warfarin metabolism β†’ bleeding or clotting risk",
139
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=CYP2C9",
140
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA126",
141
+ "nursing_note":"Poor metabolisers (*2/*2, *3/*3) need lower Warfarin doses β€” over-anticoagulation risk. Monitor INR closely when initiating therapy. Check CYP2C9 genotype before prescribing. MHRA guidance recommends dose adjustment based on genotype.",
142
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
143
+ "nice_link":"https://www.nice.org.uk/guidance/ng196","nice_label":"NICE NG196 (Anticoagulation)",
144
+ },
145
+ "CYP2C19 (Clopidogrel / PPIs)": {
146
+ "sym":"CYP2C19","chr":"chr10","start":94775000,"end":94791384,"pos":94783192,
147
+ "category":"pgx","drug":"Clopidogrel / PPIs","omim":"124020",
148
+ "key_snp":"rs4244285 (*2), rs12248560 (*17)","inheritance":"Pharmacogenomic",
149
+ "tissue_default":"Liver","condition":"Clopidogrel non-response; altered PPI metabolism",
150
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=CYP2C19",
151
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA124",
152
+ "nursing_note":"Poor metabolisers (*2/*2) cannot activate Clopidogrel β†’ higher risk of MI/stroke post-PCI. Ultra-rapid metabolisers (*17) may need reduced PPI doses. Alert prescriber before dual antiplatelet therapy.",
153
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
154
+ "nice_link":"https://www.nice.org.uk/guidance/cg94","nice_label":"NICE CG94 (ACS)",
155
+ },
156
+ "CYP2D6 (Codeine / Opioids)": {
157
+ "sym":"CYP2D6","chr":"chr22","start":42118000,"end":42134384,"pos":42126192,
158
+ "category":"pgx","drug":"Codeine / Tramadol / Opioids","omim":"124030",
159
+ "key_snp":"rs3892097 (*4), rs16947 (*2)","inheritance":"Pharmacogenomic",
160
+ "tissue_default":"Liver","condition":"Opioid toxicity (ultra-rapid) or no analgesia (poor metaboliser)",
161
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=CYP2D6",
162
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA128",
163
+ "nursing_note":"Ultra-rapid metabolisers convert Codeine to Morphine very rapidly β€” risk of fatal respiratory depression, especially in children. MHRA contraindicated Codeine in breastfeeding mothers (UMs). Poor metabolisers get no pain relief from Codeine. Use alternative opioids.",
164
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
165
+ "nice_link":"https://www.nice.org.uk/guidance/ng177","nice_label":"NICE NG177 (Chronic Pain β€” Opioids)",
166
+ },
167
+ "SLCO1B1 (Statin β€” Myopathy)": {
168
+ "sym":"SLCO1B1","chr":"chr12","start":21132000,"end":21148384,"pos":21140192,
169
+ "category":"pgx","drug":"Simvastatin / Statins","omim":"604843",
170
+ "key_snp":"rs4149056 (*5)","inheritance":"Pharmacogenomic",
171
+ "tissue_default":"Liver","condition":"Statin-induced myopathy / rhabdomyolysis",
172
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=SLCO1B1",
173
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA134865839",
174
+ "nursing_note":"SLCO1B1*5 (rs4149056 C allele) reduces hepatic uptake of statins, raising plasma levels and myopathy risk. Check CK if patient reports muscle pain/weakness on statins. Consider dose reduction or switch to Rosuvastatin (less affected by SLCO1B1).",
175
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
176
+ "nice_link":"https://www.nice.org.uk/guidance/cg181","nice_label":"NICE CG181 (Cardiovascular Risk)",
177
+ },
178
+ "TPMT (Azathioprine / 6-MP)": {
179
+ "sym":"TPMT","chr":"chr6","start":18139000,"end":18155384,"pos":18147192,
180
+ "category":"pgx","drug":"6-Mercaptopurine / Azathioprine","omim":"187680",
181
+ "key_snp":"rs1800462 (*2), rs1800460 (*3B)","inheritance":"Pharmacogenomic",
182
+ "tissue_default":"Blood (General)","condition":"Thiopurine toxicity β€” bone marrow suppression",
183
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=TPMT",
184
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA356",
185
+ "nursing_note":"Poor metabolisers (TPMT *3A/*3A) accumulate thioguanine nucleotides β†’ severe myelosuppression. NICE mandates TPMT testing before azathioprine in IBD. Monitor FBC closely. Teach patients to report bruising/bleeding/fever.",
186
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
187
+ "nice_link":"https://www.nice.org.uk/guidance/ng129","nice_label":"NICE NG129 (IBD)",
188
+ },
189
+ "DPYD (5-Fluorouracil / Capecitabine)": {
190
+ "sym":"DPYD","chr":"chr1","start":97878000,"end":97894384,"pos":97886192,
191
+ "category":"pgx","drug":"5-Fluorouracil / Capecitabine","omim":"612779",
192
+ "key_snp":"rs3918290 (*2A), rs55886062 (*13)","inheritance":"Pharmacogenomic",
193
+ "tissue_default":"Liver","condition":"Fluoropyrimidine toxicity β€” mucositis, neutropenia, death",
194
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=DPYD",
195
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA145",
196
+ "nursing_note":"NHS England mandates DPYD testing before 5-FU/Capecitabine. Poor metabolisers (1–3% population) accumulate toxic metabolites. Presentation: severe mucositis, diarrhoea, hand-foot syndrome. Stop treatment immediately if toxicity suspected; escalate urgently.",
197
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
198
+ "nice_link":"https://www.england.nhs.uk/publication/dpyd-genotyping/","nice_label":"NHS England DPYD Genotyping Mandate",
199
+ },
200
+ "VKORC1 (Warfarin sensitivity)": {
201
+ "sym":"VKORC1","chr":"chr16","start":31093000,"end":31109384,"pos":31101192,
202
+ "category":"pgx","drug":"Warfarin","omim":"608547",
203
+ "key_snp":"rs9923231 (-1639G>A)","inheritance":"Pharmacogenomic",
204
+ "tissue_default":"Liver","condition":"Increased Warfarin sensitivity β€” bleeding risk",
205
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=VKORC1",
206
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA133787052",
207
+ "nursing_note":"VKORC1 -1639A allele reduces VKORC1 expression β†’ increased Warfarin sensitivity. Patients need lower doses to achieve target INR. Works in combination with CYP2C9 genotype for dose prediction. Monitor INR more frequently in first weeks of therapy.",
208
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
209
+ "nice_link":"https://www.nice.org.uk/guidance/ng196","nice_label":"NICE NG196 (Anticoagulation)",
210
+ },
211
+ "HLA-B (Abacavir / Carbamazepine)": {
212
+ "sym":"HLA-B","chr":"chr6","start":31353000,"end":31369384,"pos":31361192,
213
+ "category":"pgx","drug":"Abacavir / Carbamazepine","omim":"142830",
214
+ "key_snp":"HLA-B*57:01 (Abacavir), HLA-B*15:02 (Carbamazepine)","inheritance":"Pharmacogenomic / Immunogenetic",
215
+ "tissue_default":"Blood (General)","condition":"Severe hypersensitivity β€” Stevens-Johnson syndrome risk",
216
+ "clinvar":"https://www.ncbi.nlm.nih.gov/clinvar/?term=HLA-B",
217
+ "pharmgkb":"https://www.pharmgkb.org/gene/PA35056",
218
+ "nursing_note":"HLA-B*57:01 β†’ Abacavir hypersensitivity (fever, rash, GI β€” potentially fatal on re-challenge). NICE mandates HLA-B*57:01 screening before Abacavir. HLA-B*15:02 β†’ Stevens-Johnson/TEN risk with Carbamazepine (mainly South/Southeast Asian populations).",
219
+ "nmc_platforms":["4 β€” Providing and evaluating care","6 β€” Improving safety"],
220
+ "nice_link":"https://www.nice.org.uk/guidance/ta91","nice_label":"NICE TA91 (Abacavir)",
221
+ },
222
+ }
223
 
224
+ TISSUE_OPTIONS = {
225
+ "Blood (General)":"UBERON:0000178","Liver":"UBERON:0002107","Skin":"UBERON:0002097",
226
+ "Breast":"UBERON:0000310","Brain":"UBERON:0000955","Lung":"UBERON:0002048",
227
+ "Heart":"UBERON:0000948","Kidney":"UBERON:0002113","Pancreas":"UBERON:0001264","Muscle":"UBERON:0002385",
228
+ }
229
 
230
+ if "history" not in st.session_state:
231
+ st.session_state.history = []
 
 
 
 
232
 
233
+ # ---------------------------------------------------------------------------
234
+ # Header
235
+ # ---------------------------------------------------------------------------
236
+ st.markdown('<h1 class="main-header">🧬 Virtual Gene Scope v2.0</h1>', unsafe_allow_html=True)
237
+ st.markdown("<p style='text-align:center;color:#4a5568;font-size:1.05rem;'>Explore the Regulatory Genome with Google DeepMind's AlphaGenome<br><em>Expression Β· Splicing Β· Chromatin Β· Contact Maps</em></p>", unsafe_allow_html=True)
238
+ st.warning("βš•οΈ **Clinical Disclaimer:** For **educational purposes only**. Does not constitute clinical advice. Always verify with ClinVar, PharmGKB, NICE guidelines, and a qualified healthcare professional.")
239
 
240
+ # ---------------------------------------------------------------------------
241
+ # Sidebar
242
+ # ---------------------------------------------------------------------------
243
+ st.sidebar.header("πŸ”¬ Analysis Settings")
244
+ mode = st.sidebar.radio("Analysis Mode", ["πŸ₯ Disease Risk", "πŸ’Š Drug Response (PGx)", "πŸ§ͺ Custom Variant"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
 
246
+ if "Disease" in mode:
247
+ filtered = {k: v for k, v in GENE_LIBRARY.items() if v["category"] == "disease"}
248
+ elif "PGx" in mode:
249
+ filtered = {k: v for k, v in GENE_LIBRARY.items() if v["category"] == "pgx"}
 
250
  else:
251
+ filtered = GENE_LIBRARY
252
+
253
+ gene_label = st.sidebar.selectbox("Select Gene", list(filtered.keys()))
254
+ gi = filtered[gene_label]
255
+ gene_sym = gi["sym"]
256
+
257
+ st.sidebar.markdown(f"""<div class="metric-card"><span class="gene-badge">{gene_sym}</span><br><br>
258
+ <strong>πŸ“</strong> {gi['chr']}:{gi['start']:,}–{gi['end']:,}<br>
259
+ <strong>🧬 Key SNP:</strong> {gi.get('key_snp','N/A')}<br>
260
+ <strong>πŸ”— Inheritance:</strong> {gi.get('inheritance','N/A')}</div>""", unsafe_allow_html=True)
 
 
 
 
261
 
 
262
  st.sidebar.markdown("---")
263
  st.sidebar.subheader("πŸ«€ Tissue Context")
264
+ default_t = gi.get("tissue_default", "Blood (General)")
265
+ tissue = st.sidebar.selectbox("Tissue", list(TISSUE_OPTIONS.keys()), index=list(TISSUE_OPTIONS.keys()).index(default_t))
266
+ ont = TISSUE_OPTIONS[tissue]
267
 
268
+ st.sidebar.markdown("---")
269
+ st.sidebar.subheader("πŸ“Š Modalities")
270
+ modalities = st.sidebar.multiselect("Tracks", ["RNA Expression","Splicing","Chromatin Accessibility","Contact Map"], default=["RNA Expression","Splicing"])
271
+
272
+ vpos = gi["pos"]; ref_b, alt_b = "A", "C"
273
+ if "Custom" in mode:
274
+ st.sidebar.markdown("---")
275
+ st.sidebar.subheader("🧬 Variant Input")
276
+ vpos = st.sidebar.number_input("Position", min_value=gi["start"], max_value=gi["end"], value=gi["pos"])
277
+ c1, c2 = st.sidebar.columns(2)
278
+ ref_b = c1.selectbox("REF", ["A","T","G","C"])
279
+ alt_b = c2.selectbox("ALT", ["A","T","G","C"], index=2)
280
 
281
+ intensity = st.sidebar.slider("Mutation Impact (demo)", 0.0, 1.0, 0.5)
 
 
 
 
282
 
 
283
  st.sidebar.markdown("---")
284
+ st.sidebar.subheader("πŸ”‘ AlphaGenome API")
285
+ api_key = os.environ.get("ALPHAGENOME_API_KEY") or st.sidebar.text_input("API Key (optional)", type="password", help="Leave blank for demo mode.")
286
 
287
+ # ---------------------------------------------------------------------------
288
+ # Demo chart helpers
289
+ # ---------------------------------------------------------------------------
290
+ def _rna(sym, inten):
291
+ x = np.linspace(0,100,500); rng=np.random.default_rng(42)
292
+ ref = np.exp(-((x-50)**2)/200)+rng.normal(0,.02,500)
293
+ alt = ref*(1-inten*.65)+np.random.default_rng(7).normal(0,.02,500)
294
+ fig,ax = plt.subplots(figsize=(10,3))
295
+ ax.fill_between(x,ref,alpha=.45,color="#4CAF50",label="Reference")
296
+ ax.fill_between(x,alt,alpha=.45,color="#ff4b4b",label="Alternate")
297
+ ax.axvline(50,color="orange",linestyle="--",alpha=.7,label="Variant site")
298
+ ax.set_title(f"{sym} β€” RNA Expression (demo)",fontweight="bold"); ax.legend(fontsize=9)
299
+ for s in ["top","right"]: ax.spines[s].set_visible(False)
300
+ ax.grid(True,alpha=.25); ax.set_facecolor("white"); fig.patch.set_facecolor("white"); fig.tight_layout()
301
+ return fig
302
 
303
+ def _splice(sym, inten):
304
+ x = np.linspace(0,100,500); fig,ax = plt.subplots(figsize=(10,3))
305
+ for p in [150,350]:
306
+ ax.bar(x[p:p+10],[.9]*10,width=.5,alpha=.55,color="#4CAF50",label="REF" if p==150 else "")
307
+ ax.bar(x[p:p+10],[.9*(1-inten)]*10,width=.3,alpha=.8,color="#ff4b4b",label="ALT" if p==150 else "")
308
+ ax.set_title(f"{sym} β€” Splice Site Usage (demo)",fontweight="bold"); ax.legend(fontsize=9)
309
+ for s in ["top","right"]: ax.spines[s].set_visible(False)
310
+ ax.grid(True,alpha=.25); ax.set_facecolor("white"); fig.patch.set_facecolor("white"); fig.tight_layout()
311
+ return fig
312
+
313
+ def _chromatin(sym, inten):
314
+ x = np.linspace(0,100,500); rng=np.random.default_rng(99)
315
+ ref = np.abs(rng.normal(0,.3,500)); ref[200:220]=1.4; ref[280:300]=1.1
316
+ alt = ref*(1-inten*.4)
317
+ fig,ax = plt.subplots(figsize=(10,3))
318
+ ax.fill_between(x,ref,alpha=.45,color="#805ad5",label="REF"); ax.fill_between(x,alt,alpha=.45,color="#dd6b20",label="ALT")
319
+ ax.set_title(f"{sym} β€” Chromatin Accessibility (demo)",fontweight="bold"); ax.legend(fontsize=9)
320
+ for s in ["top","right"]: ax.spines[s].set_visible(False)
321
+ ax.grid(True,alpha=.25); ax.set_facecolor("white"); fig.patch.set_facecolor("white"); fig.tight_layout()
322
+ return fig
 
323
 
324
+ def _contact(sym, inten):
325
+ rng=np.random.default_rng(13); n=40; base=np.zeros((n,n))
326
+ for i in range(n):
327
+ for j in range(n): base[i,j]=np.exp(-abs(i-j)*.2)+rng.normal(0,.05)
328
+ alt_m = base*(1-inten*.3)
329
+ fig,axes = plt.subplots(1,2,figsize=(10,4))
330
+ for ax,data,title,cmap in zip(axes,[base,alt_m],["REF contact map","ALT contact map"],["Blues","Reds"]):
331
+ im=ax.imshow(data,cmap=cmap,aspect="auto",vmin=0)
332
+ ax.set_title(f"{sym} β€” {title} (demo)",fontweight="bold",fontsize=9)
333
+ plt.colorbar(im,ax=ax,fraction=.046,pad=.04)
334
+ fig.patch.set_facecolor("white"); fig.tight_layout()
335
+ return fig
336
 
337
+ def build_docx(sym, gi, tissue, vpos, rb, ab, inten, figs):
338
+ doc = Document()
339
+ doc.add_heading("Virtual Gene Scope v2.0 β€” Gene Analysis Report", 0)
340
+ p = doc.add_paragraph("EDUCATIONAL USE ONLY β€” not for clinical decision-making.")
341
+ p.runs[0].font.color.rgb = RGBColor(0xC5,0x30,0x30)
342
+ doc.add_heading("Gene Summary", 1)
343
+ t = doc.add_table(rows=1, cols=2); t.style = "Light Shading Accent 1"
344
+ t.rows[0].cells[0].text = "Field"; t.rows[0].cells[1].text = "Value"
345
+ for field, val in [
346
+ ("Gene", sym), ("Location", f"{gi['chr']}:{gi['start']:,}–{gi['end']:,}"),
347
+ ("Key SNP", gi.get("key_snp","N/A")), ("Inheritance", gi.get("inheritance","N/A")),
348
+ ("Condition", gi.get("condition","N/A")), ("Tissue", tissue),
349
+ ("Variant", f"{gi['chr']}:{vpos} {rb}>{ab}"), ("Impact", f"{inten:.0%}"),
350
+ ]:
351
+ r = t.add_row().cells; r[0].text = field; r[1].text = val
352
+ doc.add_heading("Nursing Reference", 1); doc.add_paragraph(gi.get("nursing_note",""))
353
+ doc.add_heading("NMC Standards Alignment", 1)
354
+ for p_nmc in gi.get("nmc_platforms",[]): doc.add_paragraph(f"β€’ Platform {p_nmc}", style="List Bullet")
355
+ if gi.get("pharmgkb"): doc.add_paragraph(f"PharmGKB: {gi['pharmgkb']}")
356
+ doc.add_heading("Resources", 1)
357
+ for label,url in [("ClinVar",gi.get("clinvar","")),("NICE",gi.get("nice_link","")),("PharmGKB",gi.get("pharmgkb",""))]:
358
+ if url: doc.add_paragraph(f"{label}: {url}", style="List Bullet")
359
+ if figs:
360
+ doc.add_heading("Visualisation Tracks", 1)
361
+ for fig in figs:
362
+ buf=io.BytesIO(); fig.savefig(buf,format="png",dpi=150,bbox_inches="tight"); buf.seek(0)
363
+ w = doc.sections[0].page_width - doc.sections[0].left_margin - doc.sections[0].right_margin
364
+ doc.add_picture(buf, width=w); buf.close()
365
+ doc.add_paragraph("Built by Clinical Quality Artificial Intelligence β€” Nurse Citizen Developers\nhttps://github.com/Clinical-Quality-Artifical-Intelligence\nThis tool supports but does not replace clinical judgment.")
366
+ out=io.BytesIO(); doc.save(out); return out.getvalue()
367
+
368
+ # ---------------------------------------------------------------------------
369
+ # Tabs
370
+ # ---------------------------------------------------------------------------
371
  st.markdown("---")
372
+ tab_a, tab_r, tab_nmc, tab_hist = st.tabs(["πŸ“ˆ Analysis","πŸ‘©β€βš•οΈ Nurse Reference","πŸŽ“ NMC Alignment","πŸ“‹ Session History"])
373
+
374
+ with tab_a:
375
+ col_s, col_t = st.columns([1,2])
376
+
377
+ with col_s:
378
+ st.subheader("πŸ“‹ Summary")
379
+ st.markdown(f"""<div class="metric-card"><span class="gene-badge">{gene_sym}</span><br><br>
380
+ <strong>Mode:</strong> {mode}<br><strong>Tissue:</strong> {tissue}<br>
381
+ <strong>Variant:</strong> <code>{gi['chr']}:{vpos} {ref_b}>{alt_b}</code><br>
382
+ <strong>Impact:</strong> {intensity:.0%}<br><strong>Condition:</strong> {gi.get('condition','N/A')}</div>""", unsafe_allow_html=True)
383
 
384
+ if gi.get("category") == "pgx":
385
+ drug = gi.get("drug","Unknown")
386
+ if intensity > 0.55:
387
+ st.markdown(f'<div class="alert-box"><strong>⚠️ ADVERSE DRUG REACTION RISK</strong><br><strong>Drug:</strong> {drug}<br><strong>Phenotype:</strong> Poor / Intermediate Metaboliser<br><strong>Action:</strong> Consider dose reduction or alternative agent</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  else:
389
+ st.markdown(f'<div class="success-box"><strong>βœ… STANDARD DOSING LIKELY</strong><br><strong>Drug:</strong> {drug}<br><strong>Phenotype:</strong> Normal Metaboliser<br><strong>Action:</strong> Standard protocol applies</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
390
  else:
391
+ lvl = "High" if intensity>.65 else "Moderate" if intensity>.35 else "Low"
392
+ colours = {"High":("#fff5f5","#e53e3e"),"Moderate":("#fffbeb","#d69e2e"),"Low":("#f0fff4","#38a169")}
393
+ bg,bd = colours[lvl]
394
+ st.markdown(f'<div style="background:{bg};border-left:4px solid {bd};padding:1rem;border-radius:0 10px 10px 0;margin:.8rem 0;"><strong>Predicted Impact: {lvl}</strong><br>{gi.get("condition","")}</div>', unsafe_allow_html=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
 
396
+ st.markdown("**πŸ”— Authoritative Sources**")
397
+ lc1, lc2 = st.columns(2)
398
+ btns = [("ClinVar", gi.get("clinvar","")), ("OMIM", f"https://omim.org/entry/{gi.get('omim','')}" if gi.get("omim") else ""),
399
+ ("NICE", gi.get("nice_link","")), ("PharmGKB", gi.get("pharmgkb",""))]
400
+ for i,(lbl,url) in enumerate(btns):
401
+ if url: (lc1 if i%2==0 else lc2).link_button(lbl, url, use_container_width=True)
402
+ st.link_button("πŸ₯ NHS Genomics England", f"https://www.genomicsengland.co.uk/search?q={gene_sym}", use_container_width=True)
403
+
404
+ with col_t:
405
+ st.subheader("πŸ“ˆ Predicted Tracks")
406
+ figs_out = []
407
+
408
+ if not HAS_ALPHAGENOME or not api_key:
409
+ st.info("πŸ”¬ **Demo Mode** β€” Realistic simulated tracks. Add AlphaGenome API key in sidebar for live predictions.", icon="ℹ️")
410
+ if "RNA Expression" in modalities:
411
+ f=_rna(gene_sym,intensity); st.pyplot(f); figs_out.append(f)
412
+ if "Splicing" in modalities:
413
+ f=_splice(gene_sym,intensity); st.pyplot(f); figs_out.append(f)
414
+ if "Chromatin Accessibility" in modalities:
415
+ f=_chromatin(gene_sym,intensity); st.pyplot(f); figs_out.append(f)
416
+ if "Contact Map" in modalities:
417
+ f=_contact(gene_sym,intensity); st.pyplot(f); figs_out.append(f)
418
+ else:
419
+ st.sidebar.success("βœ… AlphaGenome API connected")
420
+ model = dna_client.create(api_key)
421
+ try:
422
+ with st.spinner(f"Querying AlphaGenome for {gene_sym}…"):
423
+ interval = genome.Interval(chromosome=gi["chr"], start=gi["start"], end=gi["end"])
424
+ variant = genome.Variant(chromosome=gi["chr"], position=vpos, reference_bases=ref_b, alternate_bases=alt_b)
425
+ outputs = model.predict_variant(interval=interval, variant=variant, ontology_terms=[ont], requested_outputs=[dna_client.OutputType.RNA_SEQ])
426
+ if hasattr(outputs.reference, "rna_seq"):
427
+ fig = plot_components.plot(
428
+ [plot_components.OverlaidTracks(tdata={"REF":outputs.reference.rna_seq,"ALT":outputs.alternate.rna_seq}, colors={"REF":"dimgrey","ALT":"#ff4b4b"})],
429
+ interval=outputs.reference.rna_seq.interval.resize(2**14),
430
+ annotations=[plot_components.VariantAnnotation([variant], alpha=0.8)],
431
+ )
432
+ st.pyplot(fig); figs_out.append(fig)
433
+ except Exception as e:
434
+ st.error(f"AlphaGenome error: {e}")
435
+ f=_rna(gene_sym,intensity); st.pyplot(f); figs_out.append(f)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
436
 
437
+ if HAS_DOCX and figs_out:
438
+ st.markdown("---")
439
+ docx_bytes = build_docx(gene_sym, gi, tissue, vpos, ref_b, alt_b, intensity, figs_out)
440
+ st.download_button("πŸ“₯ Download Report (.docx)", data=docx_bytes,
441
+ file_name=f"VirtualGeneScope_{gene_sym}_{tissue.replace(' ','_')}.docx",
442
+ mime="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
443
+ use_container_width=True)
444
+
445
+ entry = {"gene":gene_sym,"tissue":tissue,"mode":mode,"variant":f"{gi['chr']}:{vpos} {ref_b}>{alt_b}","impact":f"{intensity:.0%}"}
446
+ if not st.session_state.history or st.session_state.history[-1] != entry:
447
+ st.session_state.history.append(entry)
448
+ if len(st.session_state.history) > 10: st.session_state.history.pop(0)
449
+
450
+ with tab_r:
451
+ st.subheader(f"πŸ‘©β€βš•οΈ Nurse Reference β€” {gene_sym}")
452
+ st.markdown(f'<div class="info-card"><strong>πŸ₯ Condition:</strong> {gi.get("condition","N/A")}<br><strong>🧬 Key SNP:</strong> {gi.get("key_snp","N/A")}<br><strong>πŸ”— Inheritance:</strong> {gi.get("inheritance","N/A")}</div>', unsafe_allow_html=True)
453
+ st.markdown("#### πŸ’‘ Nursing Practice Guidance")
454
+ st.markdown(gi.get("nursing_note",""))
455
+ if gi.get("category") == "pgx":
456
+ st.markdown("---"); st.markdown("#### πŸ’Š PGx Quick Reference")
457
+ drug = gi.get("drug","N/A"); ca,cb = st.columns(2)
458
+ ca.markdown(f'<div class="alert-box"><strong>⚠️ Poor Metaboliser</strong><br>Drug: <strong>{drug}</strong><br>Accumulation β†’ toxicity<br>Reduce dose / switch agent</div>', unsafe_allow_html=True)
459
+ cb.markdown(f'<div class="success-box"><strong>βœ… Normal Metaboliser</strong><br>Drug: <strong>{drug}</strong><br>Standard response expected<br>Standard dosing protocol</div>', unsafe_allow_html=True)
460
+ if gi.get("pharmgkb"): st.link_button(f"πŸ“Š PharmGKB β€” {gene_sym}", gi["pharmgkb"], use_container_width=True)
461
+ st.markdown("---"); st.markdown("#### πŸ“š UK Clinical Guidelines")
462
+ if gi.get("nice_link"): st.link_button(f"πŸ“‹ {gi.get('nice_label','NICE Guidance')}", gi["nice_link"], use_container_width=True)
463
+ st.link_button("πŸ₯ NHS Genomics England", f"https://www.genomicsengland.co.uk/search?q={gene_sym}", use_container_width=True)
464
+ st.link_button("πŸ”¬ ClinVar", gi.get("clinvar", f"https://www.ncbi.nlm.nih.gov/clinvar/?term={gene_sym}"), use_container_width=True)
465
+ if gi.get("omim"): st.link_button("πŸ“– OMIM", f"https://omim.org/entry/{gi['omim']}", use_container_width=True)
466
+
467
+ with tab_nmc:
468
+ st.subheader("πŸŽ“ NMC Standards of Proficiency Alignment")
469
+ st.markdown("All CQAI tools map to the [NMC Standards of Proficiency for Registered Nurses (2018)](https://www.nmc.org.uk/standards/standards-for-nurses/standards-of-proficiency-for-registered-nurses/).")
470
+ st.markdown(f"**{gene_sym} β€” {gi.get('condition','')}**")
471
+ all_platforms = [
472
+ "Platform 1 β€” Being an accountable professional",
473
+ "Platform 2 β€” Promoting health and preventing ill health",
474
+ "Platform 3 β€” Assessing needs and planning care",
475
+ "Platform 4 β€” Providing and evaluating care",
476
+ "Platform 5 β€” Leading and managing nursing care",
477
+ "Platform 6 β€” Improving safety and quality of care",
478
+ "Platform 7 β€” Coordinating care",
479
+ ]
480
+ for plat in all_platforms:
481
+ active = any(p in plat for p in gi.get("nmc_platforms",[]))
482
+ icon = "βœ…" if active else "⬜"
483
+ colour = "#2d6a4f" if active else "#6c757d"
484
+ st.markdown(f"<span style='color:{colour}'>{icon} {plat}</span>", unsafe_allow_html=True)
485
+ st.markdown("---"); st.markdown("#### 🌐 Genomics in Nursing β€” Resources")
486
+ for label, url in [
487
+ ("NHS Genomics Education Programme","https://www.hee.nhs.uk/our-work/genomics"),
488
+ ("Genomics England β€” NHS Genomic Medicine Service","https://www.genomicsengland.co.uk/"),
489
+ ("RCN β€” Genomics for Nursing","https://www.rcn.org.uk/clinical-topics/genomics"),
490
+ ("PharmGKB","https://www.pharmgkb.org/"),
491
+ ("NHS England DPYD Genotyping Mandate","https://www.england.nhs.uk/publication/dpyd-genotyping/"),
492
+ ]:
493
+ st.link_button(label, url, use_container_width=True)
494
+
495
+ with tab_hist:
496
+ st.subheader("πŸ“‹ Session History (last 10)")
497
+ if not st.session_state.history:
498
+ st.info("No analyses run yet this session.")
499
+ else:
500
+ st.dataframe(pd.DataFrame(st.session_state.history[::-1]), use_container_width=True)
501
+ if st.button("πŸ—‘οΈ Clear History", type="secondary"): st.session_state.history=[]; st.rerun()
502
+
503
+ st.markdown("---")
504
+ st.markdown("""<div style='text-align:center;color:#718096;font-size:.88rem;'>
505
+ <strong>Virtual Gene Scope v2.0</strong> Β· Powered by <a href='https://github.com/google-deepmind/alphagenome' style='color:#667eea;'>Google DeepMind AlphaGenome</a><br>
506
+ Part of the <strong>CQAI Nursing Education Toolkit</strong> Β· <a href='https://github.com/Clinical-Quality-Artifical-Intelligence' style='color:#667eea;'>Clinical Quality Artificial Intelligence</a><br>
507
+ <em>Built by Nurse Citizen Developers 🩺 · This tool supports but does not replace clinical judgment.</em>
508
+ </div>""", unsafe_allow_html=True)
requirements.txt CHANGED
@@ -1,6 +1,7 @@
1
- streamlit
2
- pandas
3
- matplotlib
4
- numpy
5
- huggingface_hub
6
- git+https://github.com/google-deepmind/alphagenome.git
 
 
1
+ streamlit>=1.41.0
2
+ pandas>=2.2.0
3
+ matplotlib>=3.9.0
4
+ numpy>=1.26.0
5
+ huggingface_hub>=0.27.0
6
+ alphagenome==0.6.1
7
+ python-docx>=1.1.0