Reduce, annotate, and interpret MultiQC spatial-transcriptomics reports with a local LLM (via Ollama). The tool is built around MultiQC's report structure but also accepts any JSON with section-keyed data — MultiQC-specific handling (sample sheet, spatial-neighbors/co-occurrence merging) kicks in automatically when those sections are present, and other data passes through as-is.
Interpretation runs entirely on your own machine — the model and inference are local, and nothing is sent to any external service.
There are two ways to run it:
- Nextflow (recommended) — runs in a container with Ollama and Python deps already baked in; no local setup beyond Nextflow itself and a container engine.
- Directly with Python — useful for local development/debugging; needs a local Python environment and a locally running Ollama.
nextflow run main.nf --input data/multiqc_data.jsonTo steer the model with your own instruction, add --prompt:
nextflow run main.nf --input data/multiqc_data.json \
--prompt "Summarize immune infiltration and flag any tumor-immune interactions."By default this uses the docker profile (see nextflow.config), which pulls
ghcr.io/fertiglab/llmize:latest and boots Ollama inside the container — you
don't need Ollama or the Python dependencies installed on your host for this path.
nextflow run main.nf \
-profile igs \
--input data/multiqc_data.json \
--slurm_account <your-account> \
-w /usr/local/scratch/$USER/work \
-resumeThe Nextflow module uses an Ollama model cache directory via OLLAMA_MODELS.
- By default, the workflow uses a task-local cache at
$PWD/ollama/models(inside the Nextflow work directory). - To reuse models across runs (recommended on clusters), pass
--ollama_models_dir /path/to/persistent/modelsso the container can bind-mount that directory. - On the first run with an empty cache, the workflow auto-pulls the model; subsequent runs reuse the cached model when using a persistent
--ollama_models_dir.
nextflow run main.nf \
-profile igs \
--input data/multiqc_data.json \
--slurm_account <your-account> \
--ollama_models_dir /path/to/persistent/models \
-w /usr/local/scratch/$USER/work \
-resume-profile native runs llmize.py directly on the host instead of in a
container, so it needs the same local setup as "Run directly with Python" below
(Ollama installed and running, Python dependencies installed).
- Ollama (runs locally). Install it from https://ollama.com/download
(or
brew install ollamaon macOS). For a headless/CLI setup, start it once withollama serve. Then download a model once (this single step needs internet):ollama pull gemma4
cd llmize
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install -r requirements.txtConfirm everything is in place — Python version, the ollama client, the
local Ollama service running, at least one pulled model, and the descriptor
schema:
python3 check_env.py
# or, equivalently:
python3 llmize.py --checkIt prints a clear ✓/⚠/✗ report and exits non-zero if a required check fails.
python3 llmize.py --input data/multiqc_data.json --model gemma4Common flags (see python3 llmize.py --help for the full list):
python3 llmize.py --input data/multiqc_data.json \
--prompt "Summarize immune infiltration and flag any tumor-immune interactions." \
--review --output my_interpretation.mdNote that llmize.py's own flags use hyphens and differ slightly from the
Nextflow parameter names below (e.g. --whole-report/--no-synthesis instead
of --whole_report/--synthesis false).
The GitHub Actions workflow (.github/workflows/test.yml) runs on every pull request
to main, across Python 3.9 / 3.11 / 3.12. Because CI runners have no Ollama server,
it installs dependencies, byte-compiles all modules, runs the unit test suite
(python -m unittest discover tests), and runs check_env.py informationally
(non-blocking, since there's no local Ollama service in CI).
Parameters are passed on the Nextflow command line as --<param> <value>. Booleans
are set explicitly, e.g. --think false or --review true.
| Parameter | Default | Description |
|---|---|---|
--input |
— (required) | Path to the MultiQC *_data.json report, or any JSON with section-keyed data. |
--descriptor |
bundled schema | Descriptor schema JSON; override to use your own (see below). |
--model |
gemma4 |
Ollama model name. |
--outdir |
results |
Directory for the output interpretation. |
--prompt |
(none) | Extra instruction appended to the model prompt. |
--num_ctx |
32768 |
Context window size. |
--temperature |
model default | Sampling temperature (0 = deterministic). |
--top_p |
model default | Nucleus-sampling threshold. |
--top_k |
model default | Top-k sampling. |
--seed |
model default | RNG seed for reproducible output. |
--num_predict |
model default | Maximum number of tokens to generate. |
--think |
true |
Model thinking mode; --think false disables it (faster). |
--whole_report |
false |
Interpret the whole report in one call instead of section-by-section. |
--synthesis |
true |
Produce the final executive-summary pass; --synthesis false skips it. |
--review |
false |
Self-review pass flagging gene/cell-type names absent from the report. |
--review_passes |
2 |
Maximum review passes (used with --review true). |
Execution/infrastructure parameters (--container, --ollama_models_dir, profiles)
are covered under Run with Nextflow above. These are the Nextflow parameter
names (see nextflow.config); when running llmize.py directly, use --help to
see its own flag names.
- QC report — your MultiQC
*_data.json(or any section-keyed JSON). Put it anywhere and point--inputat it; the examples keep reports indata/. - Descriptor schema — the default ships at
ingest/descriptor_schema.jsonand is used automatically. To describe your own report sections, copy that file, edit the entries, and pass it with--descriptor /path/to/your_schema.json. - Output — the interpretation
.mdis written toresults/(or wherever--outdirpoints).