openmed README

The project's README from github.com/maziyarpanahi/openmed. As one markdown file: README.md.

OpenMed README banner with the cat mascot, lowercase wordmark, Open Cross, and the text Open-source healthcare AI, 340M+ downloads, and 10M+ installs

Your Data. Your Model. Your Hardware.

Turn clinical text into structured, de-identified insight on hardware you control.
OpenMed's core local runtime performs extraction and de-identification after required model artifacts are available. Model downloads, remote-provider adapters, telemetry-enabled paths, and user-configured integrations may use a network; review each model and dataset's terms.

PyPI package · Python 3.10+ · Model catalog · Research paper · Apache-2.0 SDK source

OpenMedKit · Apple Silicon / MLX · Android / ONNX Runtime Mobile · Browser / Transformers.js · Documentation

2,266 manifest entries  ·  33 model-backed PII languages  ·  Apache-2.0 SDK

English · 简体中文 · Español · Français · Deutsch · Italiano · Português · Nederlands · العربية · हिन्दी · తెలుగు · 日本語 · Türkçe · فارسی · Kiswahili


See it in action

This iPhone example uses OpenMed's local runtime after the required model artifacts are available:

OpenMed Scan on iPhone · on-device PII de-identification and clinical extraction via OpenMedKit
On iPhone via OpenMedKit: scan a clinical note, de-identify it, and extract clinical signals with Apple MLX processing locally in this configuration.

OpenMed redacting PII from a clinical discharge document in real time
Real-time PII de-identification: in this configured local workflow, the Nemotron Privacy Filter redacts names, addresses, IDs, and billing data from a synthetic clinical discharge packet. (All values shown are synthetic.)

30-second example

from openmed import analyze_text

result = analyze_text(
    "Patient started on imatinib for chronic myeloid leukemia.",
    model_name="disease_detection_superclinical",
)

for entity in result.entities:
    print(f"{entity.label:<12} {entity.text:<28} {entity.confidence:.2f}")
# DISEASE      chronic myeloid leukemia     0.98
# DRUG         imatinib                     0.95

A clinical NER model using the local runtime after its required artifacts are available.


Building with an agent?

Start with the consumer agent-usage guide, or load the curated llms.txt documentation index. For callable local interfaces, use the MCP server, the typed tool registry, or the command-line interface. Ready-made cross-tool procedures live in the repository skills catalog.


Why OpenMed?

Deployment consideration OpenMed SDK boundary
Core runtime Processes locally after required artifacts are available
Optional network paths Downloads, remote adapters, telemetry-enabled paths, and user integrations may use a network
Validation Deployment owners validate model and dataset terms, privacy behavior, and clinical fitness
Interfaces Python, Swift, Android, browser, and service surfaces where supported

On-device on Apple: Swift, MLX & iOS

On supported Apple hardware, OpenMed can use MLX and OpenMedKit for local processing after required artifacts are available. Model acquisition and any user-configured remote integrations remain separate network boundaries.

// Add OpenMedKit to your app
dependencies: [
    .package(url: "https://github.com/maziyarpanahi/openmed.git", from: "2.3.0"),
]

Expected result: Swift Package Manager resolves OpenMedKit and makes import OpenMedKit available to your app target.

Guides: MLX backend · OpenMedKit (Swift) · CoreML export

MLX vs CPU latency on Apple Silicon: 24 to 33 times faster
MLX on Apple Silicon: 24–33× faster than CPU PyTorch for the Privacy Filter: median latency per inference step, lower is better.

On-device on Android — Kotlin & ONNX Runtime Mobile

OpenMedKit also ships as a native Android/Kotlin library for local document intake, OCR handoff, PII redaction, and token-classification inference through ONNX Runtime Mobile. Mobile model repositories include stable tensor names, dynamic sequence axes, tokenizer files, labels, and Android-ready fp32, fp16, INT8, and optional .ort outputs.

Add the scoped JitPack repository in settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven {
            url = uri("https://jitpack.io")
            content { includeGroup("com.github.maziyarpanahi") }
        }
    }
}

Then use the immutable OpenMed v2.3.0 release:

dependencies {
    implementation("com.github.maziyarpanahi:openmed:v2.3.0")
}

See the Android installation guide for local builds and publishing details.

val model = OpenMedKit.fromDirectory(modelDir)
val entities = model.analyzeText("Patient Alice Nguyen was seen in cardiology.")

Guides: Android ONNX export · Android span parity · OpenMedKit Android

The same ONNX model on Python CPU

from openmed import OnnxModel

model = OnnxModel.from_pretrained(
    "OpenMed/OpenMed-PII-ClinicalE5-Small-33M-v1-onnx-android"
)
entities = model("Patient Alice Nguyen was seen in cardiology.")

The same ONNX model in the browser

npm install openmed @huggingface/transformers
import { loadOnnxModel } from "openmed";

const model = await loadOnnxModel(
  "OpenMed/OpenMed-PII-ClinicalE5-Small-33M-v1-onnx-android",
);
const entities = await model("Patient Alice Nguyen was seen in cardiology.");

How it works

flowchart LR
    A["Clinical text"] --> B["OpenMed<br/>(local-first)"]
    B --> C["Medical entities"]
    B --> D["PII detected"]
    B --> E["De-identified text"]
    style B fill:#0D6E6E,stroke:#0A5656,stroke-width:2px,color:#ffffff
    style C fill:#D6EBEB,stroke:#0D6E6E,color:#0E1116
    style D fill:#F7DCD8,stroke:#C5453A,color:#0E1116
    style E fill:#F5E27A,stroke:#A9A088,color:#0E1116

Rendered result: a local clinical-text pipeline that returns medical entities, PII findings, and de-identified text without sending data to a cloud API.


Agent Skills — build with OpenMed from your coding agent

The skills/ catalog ships portable Agent Skills for on-device de-identification, clinical NER, FHIR export, evaluation, and the healthcare workflows around them. The same SKILL.md folders work in Claude Code, OpenAI Codex, OpenCode, and compatible agents; the installer uses each client's skills directory plus the cross-client ~/.agents/skills convention.

git clone https://github.com/maziyarpanahi/openmed && cd openmed
./install-skills.sh          # installs for Claude Code, Codex, OpenCode, and ~/.agents/skills

Then ask your agent for the pipeline using synthetic placeholders:

Build a local OpenMed pipeline that de-identifies a synthetic discharge note and extracts medication entities.

It loads the right skills and produces an on-device pipeline (openmed.deidentify(...) → openmed.analyze_text(...)). After the one-time model download, run that pipeline locally on real notes; do not paste real PHI into a cloud-hosted agent prompt. See the skills catalog and 30-second example.


Quick start

# Core + Hugging Face runtime (Linux, macOS, Windows; CPU or CUDA)
pip install --upgrade "openmed[hf]"

# Add the REST service
pip install --upgrade "openmed[hf,service]"

# Apple Silicon acceleration (MLX)
pip install --upgrade "openmed[mlx]"

Expected result:

Successfully installed openmed-...

Python API

from openmed import analyze_text

result = analyze_text(
  "Patient received 75mg "
  "clopidogrel for NSTEMI.",
  model_name=
  "pharma_detection_superclinical",
)
print([(e.label, e.text) for e in result.entities])

Example output:

[('DRUG', 'clopidogrel'), ('CONDITION', 'NSTEMI')]

REST service

uvicorn openmed.service.app:app \
  --host 0.0.0.0 --port 8080

Example output:

INFO:     Uvicorn running on http://0.0.0.0:8080
GET /health -> 200 OK

GET /health POST /analyze POST /pii/extract POST /pii/deidentify

Batch

from openmed import BatchProcessor

p = BatchProcessor(
  model_name=
  "disease_detection_superclinical",
  group_entities=True,
)
results = p.process_texts([...])
print(len(results), sum(len(r.entities) for r in results))
print([(e.label, e.text) for e in results[0].entities[:1]])

Example output:

3 7
[('DISEASE', 'leukemia')]

Browser / WebGPU

Package ONNX token-classification exports for in-browser inference through Transformers.js:

python -m openmed.onnx.convert \
  --model dslim/bert-base-NER \
  --output dist/example-onnx \
  --include-transformersjs

Example output:

Exported Transformers.js bundle to dist/example-onnx
import { pipeline } from "@huggingface/transformers";

const detector = await pipeline(
  "token-classification",
  "/models/openmed-pii/transformersjs",
  { device: "webgpu" },
);
const entities = await detector("Patient Casey Example called 212-555-0198.");
console.log(entities.slice(0, 2));

Example output:

[
  { entity: "NAME", word: "Casey Example", score: 0.99 },
  { entity: "PHONE", word: "212-555-0198", score: 0.98 },
]

Transformers.js export guide

Offline / air-gapped? Point model_name (or model_id) at a local directory and OpenMed loads it without contacting the Hugging Face Hub:

from openmed import OpenMedConfig, analyze_text

result = analyze_text(
    "Patient presents with chronic myeloid leukemia and Type 2 diabetes.",
    model_id="./models/OpenMed-NER-DiseaseDetect-SuperClinical-434M",
    config=OpenMedConfig(device="cpu"),
)
for entity in result.entities:
    print(f"{entity.label:<12} {entity.text:<28} {entity.confidence:.2f}")

Example output:

DISEASE      chronic myeloid leukemia     0.98
DISEASE      Type 2 diabetes              0.96

Because model_id points to a local directory, this example does not contact the Hugging Face Hub or any external model provider.


Models

A curated registry of specialized medical NER models; browse the full catalog.

Model Specialization Entity types Size
disease_detection_superclinical Disease & conditions DISEASE, CONDITION, DIAGNOSIS 434M
pharma_detection_superclinical Drugs & medications DRUG, MEDICATION, TREATMENT 434M
pii_superclinical_large PII & de-identification NAME, DATE, SSN, PHONE, EMAIL, ADDRESS 434M
anatomy_detection_electramed Anatomy & body parts ANATOMY, ORGAN, BODY_PART 109M
gene_detection_genecorpus Genes & proteins GENE, PROTEIN 109M

Privacy: PII detection & de-identification

from openmed import extract_pii, deidentify

text = "Patient: John Doe, DOB: 01/15/1970, SSN: 123-45-6789"

# Extract PII with smart merging (prevents tokenization fragmentation)
result = extract_pii(text, model_name="pii_superclinical_large", use_smart_merging=True)
print([(e.label, e.text) for e in result.entities])

# De-identify with the method you need
print(deidentify(text, method="mask").deidentified_text)
print(deidentify(text, method="replace").deidentified_text)
print(deidentify(text, method="hash").deidentified_text)
print(deidentify(text, method="shift_dates", date_shift_days=180).deidentified_text)

Example output:

[('NAME', 'John Doe'), ('DATE', '01/15/1970'), ('SSN', '123-45-6789')]
Patient: [NAME], DOB: [DATE], SSN: [SSN]
Patient: Emily Chen, DOB: 03/22/1985, SSN: 456-78-9012
Patient: 6b8f...c4a1, DOB: 48b1...91de, SSN: 3f13...e912
Patient: John Doe, DOB: 07/14/1970, SSN: 123-45-6789
Batch PII processing throughput: up to 3.3x on CPU and 2.2x on MLX
Batch processing: up to 3.3× higher throughput on CPU and 2.2× on MLX vs. one document at a time.

Complete PII notebook · Smart merging · Anonymization quickstart

Privacy Filter family: three model families on the OpenAI Privacy Filter architecture

Same model code (gpt-oss-style sparse-MoE transformer with local attention, sink tokens, RoPE+YaRN, tiktoken o200k_base), different training data. All route through the same extract_pii() / deidentify() API; only model_name= changes. openai/privacy-filter is a Hugging Face model identifier for local weights; using it here does not call the OpenAI API.

Variant PyTorch (CPU + CUDA) MLX (Apple Silicon) MLX 8-bit
OpenAI Privacy Filter openai/privacy-filter OpenMed/privacy-filter-mlx …-mlx-8bit
Nemotron-PII fine-tune OpenMed/privacy-filter-nemotron …-nemotron-mlx …-nemotron-mlx-8bit
OpenMed Multilingual OpenMed/privacy-filter-multilingual …-multilingual-mlx …-multilingual-mlx-8bit
from openmed import extract_pii

text = "Patient Sarah Connor (DOB: 03/15/1985) at MRN 4471882."

variants = {
    "baseline": extract_pii(text, model_name="openai/privacy-filter"),
    "nemotron": extract_pii(text, model_name="OpenMed/privacy-filter-nemotron"),
    "mlx": extract_pii(text, model_name="OpenMed/privacy-filter-mlx"),
}
print([(e.label, e.text) for e in variants["baseline"].entities])

Example output:

[('NAME', 'Sarah Connor'), ('DATE', '03/15/1985'), ('ID', '4471882')]

On non-Apple-Silicon hosts, MLX model names are automatically substituted with the matching PyTorch checkpoint (with a one-time warning): reuse one model name where a matching backend artifact is available. See Privacy Filter architecture & backend routing.


Multilingual PII (36 supported routes; 33 model-backed)

Extraction and de-identification support 36 supported PII language codes: am, ar, as, bn, cs, da, de, el, en, es, fa, fr, he, hi, id, it, ja, ko, mr, nl, no, or, pt, ro, ru, sv, sw, ta, te, th, tr, uk, vi, xh, zh, and zu, with the registry-backed PII model catalog in total. Russian routing currently uses a documented multilingual default-model placeholder. Bengali, Chinese, and Tamil have dedicated registry entries. An optional, user-configured Indic NER family accepts four additional routes (gu, kn, ml, and pa) and can also serve Assamese, Bengali, Hindi, Marathi, Odia, Tamil, and Telugu. Set OPENMED_INDIC_NER_MODEL; OpenMed never bundles or automatically selects those optional weights. OpenMed also includes validator-backed national-ID coverage for addit

openmed (maziyarpanahi/openmed)

Searching Database…

5.7K ·GitHub
Что это такое?OpenMed — это SDK для здравоохранения, работающий локально: клинический NER и обезличивание PHI согласно HIPAA на вашем собственном железе, с более чем 2 200 медицинскими моделями и рантаймами для Python, MLX, Android и браузера.
Это библиотека, под которую я пишу код, или готовое приложение?Это SDK, а не приложение с кнопками: Python-пакет, Swift-библиотека OpenMedKit для платформ Apple, Kotlin-библиотека для Android, браузерный рантайм на базе Transformers.js, плюс REST-сервис, MCP-сервер и CLI.
Как его запустить?Установите Python-пакет командой 'pip install openmed' — на Apple Silicon используйте дополнение [mlx]. Swift-приложения подключают OpenMedKit через Swift Package Manager; на Android её берут из JitPack. Файлы моделей скачиваются один раз при первом использовании.
Это заработает на моём ноутбуке или нужно специальное железо?Ядро на Python работает на обычном CPU или CUDA; на Apple Silicon доступен бэкенд MLX с откатом на CoreML, на Android используется ONNX Runtime Mobile, а в браузере — WebGPU. Возможности зависят от конкретного файла модели.
Если я строю продукт на этом SDK, соответствие HIPAA обеспечивается само собой?Нет. Конфигурация, соответствующая Safe Harbor, может охватывать все 18 категорий идентификаторов, но в README прямо сказано, что требуется экспертная проверка развёртывания, и один SDK соответствие не обеспечивает.
А если место развёртывания полностью изолировано от интернета?Да — укажите modelname или modelid на локальную папку, и OpenMed загрузит модель, не обращаясь к Hugging Face Hub или каким-либо внешним провайдерам.
Могут ли мои клинические данные покинуть компьютер?Основной рантайм выполняет извлечение и обезличивание локально, как только загружены нужные файлы моделей. В сеть выходят только опциональные сценарии: загрузки, удалённые адаптеры, пути с включённой телеметрией и настроенные пользователем интеграции.
SDK бесплатный — а что с самими моделями?Исходный код SDK — под Apache-2.0, но условия использования моделей и датасетов различаются — README рекомендует владельцам развёртывания проверять каждую модель, лицензию и датасет под свой сценарий.
Что медицинские NER-модели реально находят в заметке?Отобранный каталог содержит 2 266 записей: детекторы болезней/состояний/диагнозов, лекарств и препаратов, анатомии, генов и белков, а также модели для персональных данных (PII) — размеры от 109 до 434 миллионов параметров.
Какие языки поддерживает обезличивание персональных данных?Поддерживается 36 языковых кодов для PII, из них 33 — с реальными моделями: английский, немецкий, русский, китайский, японский, арабский, хинди, суахили и другие. Для бенгальского, китайского и тамильского есть отдельные записи в реестре, а необязательное семейство Indic NER добавляет ещё четыре направления.
Насколько бэкенд MLX быстрее на Apple Silicon?Для моделей Privacy Filter MLX на Apple Silicon в 24–33 раза быстрее, чем PyTorch на CPU. Пакетная обработка даёт прирост пропускной способности до 3,3x на CPU и 2,2x на MLX по сравнению с обработкой по одному документу.
Могу ли я собирать пайплайны из Claude Code или другого кодинг-агента?Да. В каталоге навыков есть переносимые Agent Skills для обезличивания на устройстве, клинического NER, экспорта в FHIR и оценки качества — одни и те же папки SKILL.md работают в Claude Code, OpenAI Codex, OpenCode и совместимых агентах.
Size
100.5 MB
Stars
5.7K
Age
1y
Commits · 90 Days