- name
- snv-judge
- description
- Predict the pathogenicity of a human missense SNV (single nucleotide variant) using SNV-judge v5.2. Returns a calibrated probability (0โ1), ACMG 5-tier classification (P/LP/VUS/LB/B), per-feature SHAP contributions, and optionally a full LLM-generated clinical interpretation report (Chinese/English/summary). Use this skill whenever a user asks to classify, score, interpret, or generate a clinical report for a genetic variant.
# SNV-judge v5.2 โ Variant Pathogenicity Prediction
## Overview
SNV-judge is a stacking ensemble (XGBoost + LightGBM + Isotonic calibration) trained on 2,000 ClinVar variants across 547 genes. It uses 8 features fetched from free public APIs (Ensembl VEP, gnomAD) plus optional AI scores (Evo2, Genos).
**No API keys required for basic prediction.** Evo2 and Genos scores are imputed from training medians when unavailable (AUROC impact: 0.9985 โ 0.9892).
---
## Decision Tree: Which function to call
```
User request
โโโ Single variant (chrom/pos/ref/alt OR gene + protein change)
โ โโโ predict_variant() โ then print_shap_summary()
โ
โโโ Multiple variants at once
โ โโโ loop predict_variant() โ collect results into a table
โ
โโโ VCF file provided
โ โโโ predict_vcf() โ saves CSV automatically
โ
โโโ User wants to know WHY a variant scored high/low
โ โโโ predict_variant() โ print_shap_summary() โ explain top drivers
โ
โโโ User provides gene name + amino acid change (e.g. "TP53 R175H")
โ โโโ resolve_protein_variant() โ then predict_variant()
โ
โโโ User wants ClinVar ground truth alongside prediction
โ โโโ predict_variant() + fetch_clinvar_classification()
โ
โโโ User wants a clinical report / interpretation document
โโโ Has LLM API key?
โ โโโ Yes โ predict_variant() โ generate_clinical_report()
โ โ choose template: "chinese" | "english" | "summary"
โ โโโ No โ predict_variant() โ print_shap_summary()
โ tell user to provide an OpenAI-compatible API key to enable reports
โโโ User wants to stream report in real-time (e.g. Streamlit)
โโโ generate_clinical_report(..., stream=True) โ iterate chunks
```
---
## Setup (run once per session)
```python
import sys
sys.path.insert(0, '.') # run from SNV-judge repo root
from skill.scripts.predict import (
load_model_artifacts,
predict_variant,
resolve_protein_variant,
predict_vcf,
fetch_clinvar_classification,
generate_clinical_report,
print_result,
print_shap_summary,
)
# Load model โ do this ONCE and reuse artifacts for all predictions
artifacts = load_model_artifacts(".")
```
**If `load_model_artifacts` fails:** see [Troubleshooting](./references/troubleshooting.md#model-issues).
---
## Core Functions
### 1. Predict a single variant
```python
result = predict_variant(
chrom="17", # chromosome, no "chr" prefix, GRCh38
pos=7675088, # 1-based position
ref="C", # reference allele
alt="T", # alternate allele
artifacts=artifacts,
genos_url=None, # optional: local ngrok URL for Genos embedding
)
# Quick summary
print_shap_summary(result)
# Full formatted output
print_result(result)
```
**Key result fields:**
| Field | Type | Description |
|---|---|---|
| `cal_prob` | float | Calibrated P(pathogenic), 0โ1 |
| `acmg_class` | str | `Pathogenic` / `Likely Pathogenic` / `VUS` / `Likely Benign` / `Benign` |
| `acmg_confidence` | str | `High` / `Moderate` / `Low` |
| `shap_values` | list[float] | Per-feature SHAP contributions (log-odds) |
| `feature_labels` | list[str] | Feature names matching shap_values |
| `feature_vec` | list[float] | Actual feature values used |
| `top_shap_feature` | str | Feature with largest absolute SHAP |
| `genos_source` | str | `API` / `embedding` / `median_imputed` |
| `vep_scores` | dict | Gene, transcript, HGVSp, consequence from VEP |
### 2. Predict from gene + protein change
```python
# User says "TP53 R175H" โ resolve to genomic coordinates first
coords = resolve_protein_variant("TP53", "R175H")
# coords = {"chrom": "17", "pos": 7675088, "ref": "C", "alt": "T", ...}
result = predict_variant(
coords["chrom"], coords["pos"], coords["ref"], coords["alt"],
artifacts=artifacts,
)
print_shap_summary(result)
```
### 3. Batch predict from VCF file
```python
results = predict_vcf(
vcf_path="variants.vcf", # .vcf or .vcf.gz, GRCh38
artifacts=artifacts,
output_csv="results.csv", # auto-saved
batch_size=50, # VEP batch size, max 200
)
# results is a list of dicts, same structure as predict_variant()
```
### 4. Generate clinical report (LLM)
```python
# Requires any OpenAI-compatible API key
report = generate_clinical_report(
result, # from predict_variant()
api_key="sk-xxx",
base_url="https://api.moonshot.cn/v1", # or DashScope / OpenAI / DeepSeek
model="moonshot-v1-32k", # or "qwen-plus", "gpt-4o", etc.
template="chinese", # "chinese" | "english" | "summary"
stream=False, # True โ returns Generator for streaming
)
print(report)
```
**Provider presets** (swap `base_url` + `model` freely):
| Provider | base_url | Example model |
|---|---|---|
| Moonshot / Kimi | `https://api.moonshot.cn/v1` | `moonshot-v1-32k` |
| Alibaba DashScope | `https://dashscope.aliyuncs.com/compatible-mode/v1` | `qwen-plus` |
| OpenAI | `https://api.openai.com/v1` | `gpt-4o` |
| DeepSeek | `https://api.deepseek.com/v1` | `deepseek-chat` |
**Report templates:**
| template | Language | Length | Use when |
|---|---|---|---|
| `"chinese"` | ไธญๆ | ~800 words, 6 sections | Default clinical report |
| `"english"` | English | ~800 words, 6 sections | International / publication |
| `"summary"` | ไธญๆ | 3โ5 sentences | Quick interpretation |
**Report sections** (chinese / english):
1. Variant information (coordinates, gene, HGVSp)
2. Integrated prediction (cal_prob, ACMG class)
3. Multi-dimensional evidence (PP3/BP4 per tool, PM2/BA1 for gnomAD)
4. SHAP feature contributions
5. Clinical significance and recommendations
6. Limitations
**Streaming** (for real-time display):
```python
for chunk in generate_clinical_report(result, api_key="sk-xxx", stream=True):
print(chunk, end="", flush=True)
```
### 5. Fetch ClinVar ground truth
```python
cv = fetch_clinvar_classification("17", 7675088, "C", "T")
print(cv["clinical_significance"]) # e.g. "Pathogenic"
print(cv["review_status"]) # e.g. "reviewed by expert panel"
print(cv["conditions"]) # list of associated diseases
```
---
## Interpreting Results
### ACMG probability thresholds
| cal_prob | Classification | Meaning |
|---|---|---|
| โฅ 0.90 | Pathogenic | Strong computational evidence of pathogenicity |
| 0.70โ0.90 | Likely Pathogenic | Moderate evidence |
| 0.40โ0.70 | VUS | Uncertain โ borderline features |
| 0.20โ0.40 | Likely Benign | Moderate evidence of benignity |
| < 0.20 | Benign | Strong evidence of benignity |
### SHAP interpretation
- **Positive SHAP** โ feature pushes toward pathogenic
- **Negative SHAP** โ feature pushes toward benign
- SHAP values are in **log-odds space** (not probability space)
- `top_shap_feature` is the single most influential feature for this variant
- `genos_source = "median_imputed"` means Genos/Evo2 were unavailable โ marked with `*` in output
### Known limitations
- **MYH7 (cardiomyopathy)**: LOGO-CV AUROC = 0.79 (lowest of 16 tested genes). Gain-of-function mechanism causes intermediate SIFT/PolyPhen scores. Flag predictions on MYH7 variants as lower confidence.
- **Missense only**: Model trained on missense SNVs. Do not use for synonymous, intronic, or frameshift variants โ VEP will warn if consequence is not missense.
- **GRCh38 only**: Coordinates must be hg38. If user provides hg19, tell them to liftover first.
- **Not for clinical use**: Provides computational evidence (PP3/BP4) only. Clinical classification requires functional data, segregation, de novo status, etc.
For full ACMG criteria details: [acmg-criteria.md](./references/acmg-criteria.md)
---
## Example: Complete workflow (predict + SHAP + report)
```python
import sys
sys.path.insert(0, '.')
from skill.scripts.predict import (
load_model_artifacts, resolve_protein_variant, predict_variant,
fetch_clinvar_classification, print_shap_summary, generate_clinical_report,
)
artifacts = load_model_artifacts(".")
# Step 1: resolve protein variant name โ genomic coordinates
coords = resolve_protein_variant("TP53", "R175H")
# Step 2: predict
result = predict_variant(
coords["chrom"], coords["pos"], coords["ref"], coords["alt"],
artifacts=artifacts,
)
# Step 3: ClinVar ground truth
cv = fetch_clinvar_classification(
coords["chrom"], coords["pos"], coords["ref"], coords["alt"],
)
# Step 4: print summary
print(f"P(pathogenic) : {result['cal_prob']:.1%}")
print(f"ACMG class : {result['acmg_class']}")
print(f"ClinVar : {cv['clinical_significance']}")
print_shap_summary(result)
# Step 5: generate clinical report (requires API key)
report = generate_clinical_report(
result,
api_key="sk-xxx", # any OpenAI-compatible key
base_url="https://api.moonshot.cn/v1", # swap for DashScope / OpenAI etc.
model="moonshot-v1-32k",
template="chinese", # or "english" / "summary"
)
print(report)
```
Expected SHAP output:
```
SHAP Feature Contributions
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
AlphaMissense 1.000 SHAP +2.627 โฒ pathogenic
gnomAD log-AF -8.000 SHAP +2.730 โฒ pathogenic
CADD Phred 29.600 SHAP +0.898 โฒ pathogenic
Genos-10B 0.974 SHAP +0.433 โฒ pathogenic
phyloP 2.550 SHAP +0.170 โฒ pathogenic
SIFT (inv) 1.000 SHAP +0.171 โฒ pathogenic
PolyPhen-2 0.998 SHAP +0.137 โฒ pathogenic
Evo2 LLR* -0.074 SHAP -1.281 โผ benign
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Top driver: gnomAD log-AF (SHAP +2.730)
Calibrated P(pathogenic): 100.0%
ACMG class: Pathogenic
```
Expected report structure (chinese template):
```markdown
## ๅๅผ่งฃ่ฏปๆฅๅ
### ไธใๅๅผๅบๆฌไฟกๆฏ
chr17:7675088 C>T | ๅบๅ : TP53 | p.Arg175His
### ไบใ้ๆ้ขๆต็ปๆ
่ด็
ๆฆ็: 100.0% | ACMGๅ็บง: Pathogenic
### ไธใๅค็ปดๅบฆ่ฏๆฎๅๆ
#### 3.1 ็ปๅ
ธๆณจ้ๅทฅๅ
ท่ฏๆฎ๏ผPP3/BP4๏ผ...
#### 3.4 ไบบ็พค้ข็่ฏๆฎ๏ผBA1/PM2๏ผ...
#### 3.5 SHAP็นๅพ่ดก็ฎๅๆ...
### ๅใ็ปผๅๅ็ฑปๅปบ่ฎฎ ...
### ไบใไธดๅบๆไนไธๅปบ่ฎฎ ...
### ๅ
ญใๅฑ้ๆง่ฏดๆ ...
---
*ๆฌๆฅๅ็ฑSNV-judge v5ๆบ่ฝไฝ็ณป็ป่ชๅจ็ๆ๏ผไป
ไพ็ง็ ๅ่๏ผไธๆๆไธดๅบ่ฏๆญไพๆฎใ*
```
---
## Reference Files
- [acmg-criteria.md](./references/acmg-criteria.md) โ ACMG evidence criteria, per-tool thresholds (PP3/BP4/PM2/BA1)
- [troubleshooting.md](./references/troubleshooting.md) โ API errors, model loading failures, VCF parsing issues
View on GitHub