biocabinet 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. biocabinet-0.1.0/LICENSE +21 -0
  2. biocabinet-0.1.0/MANIFEST.in +54 -0
  3. biocabinet-0.1.0/PKG-INFO +386 -0
  4. biocabinet-0.1.0/README.md +320 -0
  5. biocabinet-0.1.0/biocabinet.egg-info/PKG-INFO +386 -0
  6. biocabinet-0.1.0/biocabinet.egg-info/SOURCES.txt +69 -0
  7. biocabinet-0.1.0/biocabinet.egg-info/dependency_links.txt +1 -0
  8. biocabinet-0.1.0/biocabinet.egg-info/entry_points.txt +2 -0
  9. biocabinet-0.1.0/biocabinet.egg-info/requires.txt +51 -0
  10. biocabinet-0.1.0/biocabinet.egg-info/top_level.txt +1 -0
  11. biocabinet-0.1.0/pyproject.toml +118 -0
  12. biocabinet-0.1.0/requirements-dev.txt +5 -0
  13. biocabinet-0.1.0/requirements-llm.txt +5 -0
  14. biocabinet-0.1.0/requirements.txt +42 -0
  15. biocabinet-0.1.0/scripts/__init__.py +1 -0
  16. biocabinet-0.1.0/scripts/bulk_rnaseq/__init__.py +1 -0
  17. biocabinet-0.1.0/scripts/bulk_rnaseq/config.py +341 -0
  18. biocabinet-0.1.0/scripts/bulk_rnaseq/graph.py +119 -0
  19. biocabinet-0.1.0/scripts/bulk_rnaseq/graph_nodes.py +683 -0
  20. biocabinet-0.1.0/scripts/bulk_rnaseq/graph_state.py +74 -0
  21. biocabinet-0.1.0/scripts/bulk_rnaseq/make_test_fastq.py +95 -0
  22. biocabinet-0.1.0/scripts/bulk_rnaseq/nodes.py +1070 -0
  23. biocabinet-0.1.0/scripts/bulk_rnaseq/run_preprocessing.py +167 -0
  24. biocabinet-0.1.0/scripts/common/__init__.py +1 -0
  25. biocabinet-0.1.0/scripts/common/data_detect.py +253 -0
  26. biocabinet-0.1.0/scripts/common/node_result.py +13 -0
  27. biocabinet-0.1.0/scripts/enrichment/__init__.py +1 -0
  28. biocabinet-0.1.0/scripts/enrichment/config.py +173 -0
  29. biocabinet-0.1.0/scripts/enrichment/gnn_data.py +312 -0
  30. biocabinet-0.1.0/scripts/enrichment/gnn_model.py +148 -0
  31. biocabinet-0.1.0/scripts/enrichment/gnn_test.py +262 -0
  32. biocabinet-0.1.0/scripts/enrichment/gnn_train.py +442 -0
  33. biocabinet-0.1.0/scripts/enrichment/graph.py +101 -0
  34. biocabinet-0.1.0/scripts/enrichment/graph_nodes.py +257 -0
  35. biocabinet-0.1.0/scripts/enrichment/graph_state.py +46 -0
  36. biocabinet-0.1.0/scripts/enrichment/inference.py +272 -0
  37. biocabinet-0.1.0/scripts/enrichment/merge_pathway_embeddings.py +487 -0
  38. biocabinet-0.1.0/scripts/enrichment/nodes.py +254 -0
  39. biocabinet-0.1.0/scripts/enrichment/pathway_embed.py +652 -0
  40. biocabinet-0.1.0/scripts/enrichment/playfile.py +6 -0
  41. biocabinet-0.1.0/scripts/enrichment/precompute_esm.py +240 -0
  42. biocabinet-0.1.0/scripts/enrichment/reactome_embed.py +292 -0
  43. biocabinet-0.1.0/scripts/enrichment/test_chain_smoke.py +315 -0
  44. biocabinet-0.1.0/scripts/enrichment/utils.py +199 -0
  45. biocabinet-0.1.0/scripts/enrichment/wikipathways_embed.py +207 -0
  46. biocabinet-0.1.0/scripts/orchestrator.py +580 -0
  47. biocabinet-0.1.0/scripts/rag/__init__.py +6 -0
  48. biocabinet-0.1.0/scripts/rag/answerer.py +450 -0
  49. biocabinet-0.1.0/scripts/rag/artifact_reader.py +426 -0
  50. biocabinet-0.1.0/scripts/rag/augment.py +282 -0
  51. biocabinet-0.1.0/scripts/rag/build_index.py +328 -0
  52. biocabinet-0.1.0/scripts/rag/graph.py +192 -0
  53. biocabinet-0.1.0/scripts/rag/graph_nodes.py +297 -0
  54. biocabinet-0.1.0/scripts/rag/graph_state.py +40 -0
  55. biocabinet-0.1.0/scripts/rag/pipeline_context.py +406 -0
  56. biocabinet-0.1.0/scripts/rag/retriever.py +278 -0
  57. biocabinet-0.1.0/scripts/rag/tools.py +262 -0
  58. biocabinet-0.1.0/scripts/render_graphs.py +68 -0
  59. biocabinet-0.1.0/scripts/scrna/__init__.py +1 -0
  60. biocabinet-0.1.0/scripts/scrna/config.py +171 -0
  61. biocabinet-0.1.0/scripts/scrna/graph.py +289 -0
  62. biocabinet-0.1.0/scripts/scrna/graph_nodes.py +347 -0
  63. biocabinet-0.1.0/scripts/scrna/graph_state.py +31 -0
  64. biocabinet-0.1.0/scripts/scrna/nodes.py +1083 -0
  65. biocabinet-0.1.0/scripts/spatial/__init__.py +1 -0
  66. biocabinet-0.1.0/scripts/spatial/config.py +118 -0
  67. biocabinet-0.1.0/scripts/spatial/graph.py +45 -0
  68. biocabinet-0.1.0/scripts/spatial/graph_nodes.py +240 -0
  69. biocabinet-0.1.0/scripts/spatial/nodes.py +602 -0
  70. biocabinet-0.1.0/setup.cfg +4 -0
  71. biocabinet-0.1.0/tests/test_imports.py +32 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ishita Jain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,54 @@
1
+ # Files to include in the source distribution (sdist)
2
+ include LICENSE
3
+ include README.md
4
+ include pyproject.toml
5
+ include requirements*.txt
6
+
7
+ # Include all Python source under scripts/
8
+ recursive-include scripts *.py py.typed
9
+
10
+ # ── Exclude everything that is NOT source code ──────────────────────────────
11
+
12
+ # Runtime pipeline output directories (scRNA step dirs written to project root)
13
+ prune 00_load
14
+ prune 01_qc
15
+ prune 02_filter
16
+ prune 02_trimmed
17
+ prune 03_normalize
18
+ prune 03_bam
19
+ prune 04_pca
20
+ prune 04_counts
21
+ prune 05_cluster
22
+ prune 05_normalized
23
+ prune 06_markers
24
+ prune 07_trajectory
25
+ prune 09_benchmark
26
+
27
+ # Pipeline run artifacts
28
+ exclude pipeline_runs.sqlite
29
+ exclude pipeline_runs.sqlite-shm
30
+ exclude pipeline_runs.sqlite-wal
31
+ exclude preprocessing_run.json
32
+ exclude app.log
33
+ exclude *.log
34
+ prune runs
35
+
36
+ # Pre-trained model weights downloaded at runtime (not shipped in the wheel)
37
+ prune biobert_v1.1_pubmed_pytorch_model
38
+ exclude *.ckpt
39
+
40
+ # Data directory (binary files — too large; see data/README.md for download)
41
+ prune data
42
+
43
+ # Presentation / docs
44
+ prune docs
45
+
46
+ # Development environment
47
+ prune .venv
48
+ prune .venv-dev
49
+ exclude biocabinet.egg-info
50
+
51
+ # Test outputs / caches
52
+ prune __pycache__
53
+ prune .pytest_cache
54
+ prune .mypy_cache
@@ -0,0 +1,386 @@
1
+ Metadata-Version: 2.4
2
+ Name: biocabinet
3
+ Version: 0.1.0
4
+ Summary: Agentic multi-modal transcriptomics pipeline powered by LangGraph
5
+ License-Expression: MIT
6
+ Project-URL: Homepage, https://github.com/ishitajain9717/biocabinet
7
+ Project-URL: Source, https://github.com/ishitajain9717/biocabinet
8
+ Project-URL: Bug Tracker, https://github.com/ishitajain9717/biocabinet/issues
9
+ Keywords: rna-seq,bioinformatics,langgraph,llm,agent,differential-expression,single-cell,spatial-transcriptomics,gnn,rag,pathway-enrichment
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Operating System :: OS Independent
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: langgraph>=1.1.9
23
+ Requires-Dist: langgraph-checkpoint-sqlite>=3.0
24
+ Requires-Dist: langchain-core>=0.1.0
25
+ Requires-Dist: numpy>=2.0
26
+ Requires-Dist: scipy>=1.13
27
+ Requires-Dist: pandas>=2.0
28
+ Requires-Dist: torch>=2.0
29
+ Requires-Dist: transformers>=4.40
30
+ Requires-Dist: pydeseq2>=0.4
31
+ Requires-Dist: scanpy>=1.10
32
+ Requires-Dist: mygene>=3.2
33
+ Requires-Dist: python-dotenv>=1.0.0
34
+ Requires-Dist: langsmith>=0.1
35
+ Requires-Dist: requests>=2.31
36
+ Requires-Dist: tenacity>=8.2
37
+ Provides-Extra: llm-openai
38
+ Requires-Dist: langchain-openai>=0.1; extra == "llm-openai"
39
+ Provides-Extra: llm-ollama
40
+ Requires-Dist: langchain-ollama>=0.1; extra == "llm-ollama"
41
+ Provides-Extra: llm
42
+ Requires-Dist: langchain-openai>=0.1; extra == "llm"
43
+ Requires-Dist: langchain-ollama>=0.1; extra == "llm"
44
+ Provides-Extra: gnn
45
+ Requires-Dist: torch-geometric>=2.5; extra == "gnn"
46
+ Requires-Dist: fair-esm>=2.0.0; extra == "gnn"
47
+ Provides-Extra: spatial
48
+ Requires-Dist: squidpy>=1.6; extra == "spatial"
49
+ Requires-Dist: harmonypy>=0.0.10; extra == "spatial"
50
+ Provides-Extra: trajectory
51
+ Requires-Dist: palantir>=1.3; extra == "trajectory"
52
+ Provides-Extra: full
53
+ Requires-Dist: langchain-openai>=0.1; extra == "full"
54
+ Requires-Dist: langchain-ollama>=0.1; extra == "full"
55
+ Requires-Dist: torch-geometric>=2.5; extra == "full"
56
+ Requires-Dist: fair-esm>=2.0.0; extra == "full"
57
+ Requires-Dist: squidpy>=1.6; extra == "full"
58
+ Requires-Dist: harmonypy>=0.0.10; extra == "full"
59
+ Requires-Dist: palantir>=1.3; extra == "full"
60
+ Provides-Extra: dev
61
+ Requires-Dist: pytest>=8.0; extra == "dev"
62
+ Requires-Dist: build>=1.0; extra == "dev"
63
+ Requires-Dist: twine>=5.0; extra == "dev"
64
+ Requires-Dist: jupyter>=1.0; extra == "dev"
65
+ Dynamic: license-file
66
+
67
+ # Biocabinet
68
+
69
+ [![PyPI version](https://img.shields.io/pypi/v/biocabinet.svg)](https://pypi.org/project/biocabinet/)
70
+ [![Python](https://img.shields.io/pypi/pyversions/biocabinet.svg)](https://pypi.org/project/biocabinet/)
71
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
72
+ [![Status: Alpha](https://img.shields.io/badge/status-alpha-orange.svg)](https://github.com/ishitajain9717/biocabinet)
73
+
74
+ An agentic transcriptomics analysis platform built on [LangGraph](https://github.com/langchain-ai/langgraph).
75
+ It orchestrates FastQC → trimming → alignment → quantification → normalisation → differential expression → GNN-based PPI enrichment, with an optional RAG layer that grounds LLM summaries in KEGG and Reactome pathway knowledge.
76
+
77
+ The pipeline is **agentic at the decision points, not just the prose**: an LLM (with deterministic guardrails) decides whether a sample passes FastQC, what Trimmomatic steps to apply, what experiment type an input directory contains, and — in the spatial pipeline — whether suspicious clusters are a real cell type or an imaging batch effect. Every LLM decision is validated against hard metrics and falls back to rule-based logic if the model is unavailable or unreliable.
78
+
79
+ ---
80
+
81
+ ## Architecture
82
+
83
+ ```
84
+ Orchestrator (LangGraph)
85
+
86
+ ├── Bulk RNA-seq sub-pipeline
87
+ │ ├── FastQC → Trimmomatic → STAR → featureCounts
88
+ │ ├── Normalisation (TPM / FPKM / RPKM)
89
+ │ ├── Differential Expression (PyDESeq2)
90
+ │ └── Summarise ← RAG-augmented (Phase 4a)
91
+
92
+ ├── scRNA-seq sub-pipeline
93
+ │ ├── Load (h5ad / 10x / pbmc3k)
94
+ │ ├── QC → Filter → Normalise → PCA
95
+ │ ├── Cluster (Leiden / UMAP)
96
+ │ └── Marker genes → Summarise ← RAG-augmented
97
+
98
+ ├── Spatial (imaging) sub-pipeline (in development — Vizgen/MERSCOPE)
99
+ │ ├── Load (squidpy Vizgen cell tables)
100
+ │ ├── QC (blank-FDR, per-cell counts/volume, FOV outliers)
101
+ │ ├── Cluster (PCA → Leiden)
102
+ │ └── FOV-bias check ← agentic (metrics + LLM + Harmony correct/re-cluster loop)
103
+
104
+ ├── Enrichment sub-pipeline (auto-chained after bulk)
105
+ │ ├── Load PPI graph (STRING / SHS27k)
106
+ │ ├── GNN training (GIN, BFS split)
107
+ │ ├── Evaluation (test1/2/3 buckets)
108
+ │ └── Inference → Summarise ← RAG-augmented
109
+
110
+ └── RAG Q&A session (Phase 4b — interactive, after final report)
111
+ └── Retriever → LLM synthesis → Citations
112
+ ```
113
+
114
+ Graph diagrams (Mermaid + PNG) live in `docs/`.
115
+
116
+ ---
117
+
118
+ ## Installation
119
+
120
+ ```bash
121
+ git clone https://github.com/ishitajain9717/biocabinet.git
122
+ cd biocabinet
123
+ python -m venv .venv && source .venv/bin/activate
124
+
125
+ # Option A: editable install (recommended — registers the `rnaseq-agent` CLI)
126
+ pip install -e ".[llm]"
127
+
128
+ # Option B: plain requirements files
129
+ pip install -r requirements.txt -r requirements-llm.txt
130
+ ```
131
+
132
+ ### Python dependencies (all modalities)
133
+
134
+ Installed via `pip install -e ".[llm]"` from `pyproject.toml`. These are **imported in code** — no separate binary on `PATH`.
135
+
136
+ | Package | Used by | Role |
137
+ |---|---|---|
138
+ | `langgraph`, `langchain-core` | Orchestrator, all graphs | Agent workflow + state |
139
+ | `pandas`, `numpy`, `scipy` | Bulk, scRNA, enrichment | Tables and numerics |
140
+ | `pydeseq2` | Bulk | Differential expression (DESeq2) |
141
+ | `scanpy` | scRNA, Spatial | Load h5ad/10x, QC, normalize, PCA, cluster, markers |
142
+ | `squidpy` | Spatial | Read MERSCOPE/Vizgen cell tables into AnnData |
143
+ | `harmonypy` | Spatial | FOV batch correction in the bias-check loop |
144
+ | `python-dotenv` | All | Auto-load LLM config from `.env` |
145
+ | `torch`, `torch-geometric` | Enrichment | GNN training and inference |
146
+ | `transformers` | Enrichment, RAG | BioBERT pathway text embeddings |
147
+ | `fair-esm` | Enrichment | ESM-2 protein sequence embeddings |
148
+ | `mygene` | Bulk (DEG → enrichment) | ENSG → ENSP mapping |
149
+ | `requests`, `tenacity` | Enrichment (pathway build) | KEGG / Reactome / WikiPathways APIs |
150
+ | `langchain-openai`, `langchain-ollama` | Summarise, RAG (optional) | LLM summaries and Q&A |
151
+
152
+ scRNA clustering (Leiden / UMAP) runs inside Scanpy. If Leiden fails at runtime, install graph backends:
153
+
154
+ ```bash
155
+ pip install leidenalg python-igraph
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Requirements by modality
161
+
162
+ ### Bulk RNA-seq
163
+
164
+ **Workflow:** FASTQ → FastQC → **agentic QC gate** → **agentic trim gate** (LLM picks Trimmomatic steps from the FastQC report) → STAR → featureCounts → TPM/FPKM/RPKM → PyDESeq2 → summarise (+ RAG).
165
+
166
+ The QC gate lets the agent **drop a failing sample and continue** with the rest of the batch rather than aborting the run; the trim gate generates sample-specific Trimmomatic arguments, validated against the FastQC metrics before execution.
167
+
168
+ | Type | Requirement | Notes |
169
+ |---|---|---|
170
+ | **CLI on `PATH`** | [FastQC](https://www.bioinformatics.babraham.ac.uk/projects/fastqc/) | QC | `brew install fastqc` |
171
+ | | [STAR](https://github.com/alexdobin/STAR) | Alignment | `brew install star` |
172
+ | | [featureCounts](https://subread.sourceforge.net/) (Subread) | Gene counts | `brew install subread` |
173
+ | | [Trimmomatic](http://www.usadellab.org/cms/?page=trimmomatic) | Adapter/quality trim | JAR + `java`; steps chosen by the agentic trim gate |
174
+ | | `java` | Runs Trimmomatic | Required only if trimming is enabled |
175
+ | **Python (`pip`)** | `pydeseq2`, `pandas`, `mygene` | DEG + pair export for enrichment | In `pyproject.toml` |
176
+ | **Reference data** | STAR genome index + GTF | Not in git | See [`data/README.md`](data/README.md) — GENCODE GRCh38 + `STAR --runMode genomeGenerate` |
177
+ | **Input** | Paired FASTQ + sample sheet | | Conditions for DESeq2 (≥2 per group) |
178
+ | **Optional** | LLM env vars | RAG-augmented summary | See [LLM configuration](#llm-configuration) |
179
+
180
+ ---
181
+
182
+ ### scRNA-seq
183
+
184
+ **Workflow:** Load (h5ad / 10x / pbmc3k) → QC metrics → filter → normalize → HVG → PCA → neighbors → Leiden → UMAP → marker genes → summarise (+ RAG).
185
+
186
+ | Type | Requirement | Notes |
187
+ |---|---|---|
188
+ | **CLI on `PATH`** | *(none)* | Entire pipeline is Scanpy in Python |
189
+ | **Python (`pip`)** | `scanpy`, `numpy`, `scipy`, `pandas` | Core analysis | In `pyproject.toml` |
190
+ | | `leidenalg`, `python-igraph` | Leiden clustering | Often needed; install if clustering errors |
191
+ | **Input** | `.h5ad`, 10x folder, or `pbmc3k` | | Set in `ScrnaConfig` / interactive prompts |
192
+ | **Optional** | `data/pbmc3k_raw.h5ad` | Cached demo data | Download via Scanpy; see `data/README.md` |
193
+ | **Optional** | LLM + RAG index | Marker-gene pathway context in summary | Build RAG index once; see RAG section |
194
+
195
+ ---
196
+
197
+ ### Spatial transcriptomics (imaging-based)
198
+
199
+ **Status:** in active development. The v1 scope targets **imaging-based** platforms — **MERSCOPE / Vizgen** — starting from the post-segmentation cell tables (segmentation is the user's responsibility). The node-level building blocks are implemented and tested; final assembly into the orchestrated LangGraph (`scripts/spatial/graph.py`) is still in progress, so the orchestrator currently routes spatial inputs to a stub.
200
+
201
+ **Planned workflow:** Load (squidpy Vizgen reader) → QC (blank-FDR, per-cell counts/genes/volume, FOV outliers) → normalize → cluster (PCA → Leiden) → **FOV-bias check** → annotation (CeLLama-style, reimplemented in Python) → summarise (+ RAG).
202
+
203
+ | Type | Requirement | Notes |
204
+ |---|---|---|
205
+ | **CLI on `PATH`** | *(none)* | Entire pipeline is Python |
206
+ | **Python (`pip`)** | `squidpy`, `scanpy`, `harmonypy` | Read tables, QC/cluster, batch correction | In `pyproject.toml` |
207
+ | | `leidenalg`, `python-igraph` | Leiden clustering | Install if clustering errors |
208
+ | **Input** | `*_cell_by_gene.csv` + `*_cell_metadata.csv` | MERSCOPE per-region exports | Auto-detected in the input dir |
209
+ | **Optional** | LLM env vars | Agentic FOV-bias adjudication | Deterministic rule fallback without LLM |
210
+
211
+ **The FOV-bias check** is the spatial pipeline's flagship agentic step. Imaging-based data is captured tile-by-tile (each tile = a *field of view*, FOV), and per-FOV imaging differences can split one real cell type into several clusters. The node:
212
+
213
+ 1. Computes deterministic evidence — **iLISI** (do expression-neighbors mix across FOVs?), **Cramér's V** (is cluster identity explained by FOV?), and the **fraction of cells in FOV-pure clusters**.
214
+ 2. Hands that evidence to an LLM, which returns `BATCH_EFFECT` / `BIOLOGY` / `UNCERTAIN` plus an action — with **guardrails** that override the model in both directions (never silently keep an obvious artifact, never over-correct clean biology) and a rule-based fallback.
215
+ 3. If a batch effect is confirmed, runs **Harmony** correction on the FOV label, re-clusters, and **re-verifies** that the split actually collapsed before accepting the result.
216
+
217
+ ---
218
+
219
+ ### Enrichment (GNN-PPI)
220
+
221
+ **Workflow:** Load PPI graph + ESM-2 + pathway embeddings → train GIN (BFS split) → bucketed eval → inference on DEG pairs. Auto-chained after a successful bulk run from the orchestrator.
222
+
223
+ | Type | Requirement | Notes |
224
+ |---|---|---|
225
+ | **CLI on `PATH`** | *(none)* | Training and inference are PyTorch |
226
+ | **Python (`pip`)** | `torch`, `torch-geometric`, `transformers`, `fair-esm` | Model + embeddings | In `pyproject.toml` |
227
+ | **Reference data** | `data/ppi_SHS27k.tsv`, `data/esm2_embeddings_SHS27k.pt`, `data/pathway/06_pathway_embeddings_combined.pt` | SHS27k benchmark | See `data/README.md` |
228
+ | **Upstream** | Bulk DEG `deg_pairs.tsv` | Optional | Orchestrator passes path when bulk DEG ran |
229
+ | **Optional** | GPU (`device=cuda` / `mps`) | Faster training | Default config uses `auto` |
230
+
231
+ Pathway embedding build (one-time, before merge):
232
+
233
+ ```bash
234
+ python -m scripts.enrichment.pathway_embed
235
+ python -m scripts.enrichment.reactome_embed
236
+ python -m scripts.enrichment.wikipathways_embed
237
+ python -m scripts.enrichment.merge_pathway_embeddings
238
+ python -m scripts.enrichment.precompute_esm
239
+ ```
240
+
241
+ ---
242
+
243
+ ### RAG (pathway Q&A)
244
+
245
+ **Workflow:** Build index once → retriever (BioBERT cosine search) → answerer (LLM + citations) → augment pipeline summaries (4a) → optional interactive chat after orchestrator (4b).
246
+
247
+ | Type | Requirement | Notes |
248
+ |---|---|---|
249
+ | **CLI on `PATH`** | *(none)* | Search and embed in Python |
250
+ | **Python (`pip`)** | `transformers`, `torch` | BioBERT at index build and query time | In `pyproject.toml` |
251
+ | | `langchain-openai` or `langchain-ollama` | Prose answers | Optional; deterministic fallback without LLM |
252
+ | **Reference data** | KEGG + Reactome text under `data/pathway/` | Source for `build_index` | Built by enrichment pathway scripts |
253
+ | **Generated** | `data/rag/docs.jsonl`, `embeddings.npy`, `gene_to_doc_ids.json` | Local library | Not committed; run `build_index` |
254
+
255
+ ```bash
256
+ python -m scripts.rag.build_index # once, after pathway data exists
257
+ python -m scripts.rag.retriever "cell cycle CDK4" # smoke-test retrieval
258
+ python -m scripts.rag.graph # interactive Q&A
259
+ ```
260
+
261
+ Bulk runs can set **pathway interests** at config time (e.g. `cell cycle, apoptosis`); matching DEGs are always included in RAG gene selection before the top-60% rule.
262
+
263
+ ---
264
+
265
+ ### Orchestrator
266
+
267
+ | Type | Requirement | Notes |
268
+ |---|---|---|
269
+ | **Python (`pip`)** | All of the above for chosen modality | Lazy-imports child graphs |
270
+ | **Persistence** | `pipeline_runs.sqlite` | LangGraph `SqliteSaver`; created on first run |
271
+ | **LLM** | `OLLAMA_MODEL` or `OPENAI_API_KEY` | Final report + RAG chat; optional |
272
+
273
+ The orchestrator **auto-detects the modality** from the input path (FASTQ/sample-sheet → bulk, 10x/h5ad → scRNA, Vizgen CSVs or spatial-coordinate h5ad → spatial) via `scripts/common/data_detect.py`, shows the evidence, and asks for confirmation rather than presenting a blind menu. A confirmed `bulk_rnaseq` run chains bulk → enrichment (if bulk succeeds) → final report → optional RAG Q&A; `scrna` runs scRNA only, then report and optional RAG.
274
+
275
+ ---
276
+
277
+ ## Data setup
278
+
279
+ See [`data/README.md`](data/README.md) for instructions on downloading the required reference files, PPI graph, and pre-computed embeddings.
280
+
281
+ ---
282
+
283
+ ## Running
284
+
285
+ ### Full orchestrated pipeline
286
+
287
+ ```bash
288
+ python -m scripts.orchestrator
289
+ # resume a previous run
290
+ python -m scripts.orchestrator --thread-id orchestrator_20260520_094200
291
+ ```
292
+
293
+ ### Individual sub-pipelines
294
+
295
+ ```bash
296
+ # Bulk RNA-seq
297
+ python -m scripts.bulk_rnaseq.graph
298
+
299
+ # scRNA-seq
300
+ python -m scripts.scrna.graph
301
+
302
+ # Enrichment (GNN-PPI)
303
+ python -m scripts.enrichment.graph
304
+
305
+ # Build RAG index (run once)
306
+ python -m scripts.rag.build_index
307
+
308
+ # Interactive RAG Q&A
309
+ python -m scripts.rag.graph
310
+ ```
311
+
312
+ ---
313
+
314
+ ## LLM configuration
315
+
316
+ The pipeline uses an LLM for plain-English summaries and RAG-grounded answers.
317
+ Configure via environment variables — no API keys in code:
318
+
319
+ ```bash
320
+ # Option A: local Ollama (free, offline)
321
+ export OLLAMA_MODEL=llama3
322
+
323
+ # Option B: OpenAI
324
+ export OPENAI_API_KEY=sk-...
325
+ export OPENAI_MODEL=gpt-4o-mini # optional, default is gpt-4o-mini
326
+ ```
327
+
328
+ These can also be placed in a `.env` file at the repo root — it is auto-loaded via `python-dotenv`. If neither provider is set, all summarise nodes **and every agentic gate** (FastQC, trimming, data-type detection, FOV-bias) fall back to deterministic rule-based logic.
329
+
330
+ ---
331
+
332
+ ## Project layout
333
+
334
+ ```
335
+ scripts/
336
+ ├── orchestrator.py top-level LangGraph orchestrator
337
+ ├── bulk_rnaseq/ bulk RNA-seq sub-pipeline
338
+ │ ├── config.py PreprocessingConfig dataclass + CLI prompts
339
+ │ ├── nodes.py core bioinformatics functions
340
+ │ ├── graph_nodes.py LangGraph wrapper nodes
341
+ │ ├── graph_state.py PipelineState TypedDict
342
+ │ └── graph.py graph builder
343
+ ├── scrna/ scRNA-seq sub-pipeline (same structure)
344
+ ├── spatial/ spatial (imaging / Vizgen) sub-pipeline — in development
345
+ │ ├── config.py SpatialConfig (Vizgen CSVs + QC thresholds)
346
+ │ ├── nodes.py load_vizgen, spatial_qc, clustering, fov_bias_check
347
+ │ ├── graph_nodes.py LLM FOV-bias adjudication + guardrails
348
+ │ └── graph.py graph builder (assembly in progress)
349
+ ├── enrichment/ GNN-PPI enrichment sub-pipeline
350
+ │ ├── pathway_embed.py KEGG pathway embeddings (BioBERT)
351
+ │ ├── reactome_embed.py Reactome pathway embeddings
352
+ │ ├── wikipathways_embed.py WikiPathways embeddings
353
+ │ ├── merge_pathway_embeddings.py multi-source merge + dedup
354
+ │ ├── precompute_esm.py ESM-2 protein sequence embeddings
355
+ │ ├── gnn_data.py PPI graph + feature assembly
356
+ │ ├── gnn_model.py GIN model definition
357
+ │ ├── gnn_train.py training loop (BFS split)
358
+ │ ├── gnn_test.py bucketed evaluation (test1/2/3)
359
+ │ └── inference.py predict interactions for novel pairs
360
+ ├── rag/ RAG layer
361
+ │ ├── build_index.py Phase 1 — build pathway document library
362
+ │ ├── retriever.py Phase 2 — cosine similarity search
363
+ │ ├── answerer.py Phase 3 — LLM synthesis with citations
364
+ │ ├── augment.py Phase 4a — auto-augment pipeline summaries
365
+ │ ├── graph_state.py Phase 4b — RagChatState
366
+ │ ├── artifact_reader.py scan a run dir for STAR/featureCounts/FastQC/DEG/GNN artifacts
367
+ │ ├── graph_nodes.py Phase 4b — chat loop nodes (+ LLM data-type inference)
368
+ │ └── graph.py Phase 4b — interactive Q&A graph
369
+ └── common/
370
+ ├── node_result.py NodeResult dataclass (shared across pipelines)
371
+ └── data_detect.py auto-detect modality (bulk / scRNA / spatial) from a path
372
+ ```
373
+
374
+ ---
375
+
376
+ ## Checkpointing and resumption
377
+
378
+ All pipeline state is persisted to `pipeline_runs.sqlite` via LangGraph's `SqliteSaver`.
379
+ If a run is interrupted, resume it by passing the printed `--thread-id`.
380
+ Child pipelines (bulk, enrichment) share the same checkpointer as the orchestrator, so partial child runs are also resumable.
381
+
382
+ ---
383
+
384
+ ## License
385
+
386
+ MIT