Skip to content

Latest commit

 

History

History
742 lines (541 loc) · 28.4 KB

README.zh-CN.md

File metadata and controls

742 lines (541 loc) · 28.4 KB
OpenMed README 横幅,包含猫咪吉祥物、小写文字标识、Open Cross,以及开源医疗 AI、下载量 3.4 亿+ 和安装量 1000 万+ 文字

你的数据。你的模型。你的硬件。

在你掌控的硬件上,将临床文本转化为结构化、去标识化的洞见。
OpenMed 的核心本地运行时会在所需模型制品就绪后执行抽取和去标识化。模型下载、远程提供商适配器、启用遥测的路径及用户配置的集成可能使用网络;请核查每个模型和数据集的条款。

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 条清单记录  ·  35 种模型支持的 PII 语言  ·  Apache-2.0 SDK

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


现场演示

此 iPhone 示例会在所需模型制品就绪后使用 OpenMed 的本地运行时:

iPhone 上的 OpenMed Scan:通过 OpenMedKit 在设备本地完成 PII 去标识化和临床实体抽取
通过 OpenMedKit 在 iPhone 上运行:在此配置中,由 Apple MLX 在本地扫描临床记录、完成去标识化并抽取临床信号。

OpenMed 实时对一份临床出院记录进行 PII 脱敏
实时 PII 去标识化:在此配置的本地工作流中,Nemotron Privacy Filter 会对合成临床出院记录中的姓名、地址、证件号和账单数据进行脱敏。(图中所有数值均为合成数据。)

30 秒上手示例

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

临床 NER 模型会在所需制品就绪后使用本地运行时。


30 秒运行临床摘要示例

在源码检出目录中运行仅使用 CPU 的合成数据接口演示:

python examples/v30_clinical_brief.py
# 可选:--model mlx,需要在 Apple 芯片设备上预先缓存固定版本的模型。

该示例对内置记录进行去标识化、实体抽取和概念匹配,然后输出带来源引用的摘要、 核验结果和不含原始值的审核包。NER/NLI 提供程序是明确标注的合成测试替身, 不是经过训练的模型,也不代表临床验证。 不接受外部记录输入。 MLX 输出若缺乏证据支持会被拒绝,不会绕过保护检查。 详见摘要指南和演示脚本。


使用智能体构建?

请从面向使用者的智能体指南开始,或加载精选的 llms.txt 文档索引。对于可调用的本地接口, 请使用 MCP 服务器、带类型的 工具注册表或 命令行接口。可直接使用的跨工具流程位于 仓库技能目录。


为什么选择 OpenMed?

部署考量 OpenMed SDK 边界
核心运行时 所需制品就绪后在本地处理
可选网络路径 下载、远程适配器、遥测路径和用户集成可能使用网络
验证 部署方验证模型与数据条款、隐私行为及临床适用性
接口 在受支持的范围内提供 Python、Swift、Android、浏览器和服务接口
  • 精选模型目录:请针对你的用例验证每个模型、许可证和数据集。
  • 与 Safe Harbor 对齐的配置:可面向 18 类标识符;仍需专家开展部署审查,使用 SDK 本身并不能证明符合 HIPAA。
  • 受支持的执行路径:CPU、CUDA、MLX、移动端、服务和浏览器适配器会因环境与制品而异。
  • 部署接口:Python、容器、服务和批处理工作流需要配置与验证。
  • SDK 源代码:基于 Apache-2.0 License 发布;模型和数据集条款各不相同。

在 Apple 设备上本地运行:Swift、MLX 与 iOS

在受支持的 Apple 硬件上,所需制品就绪后,OpenMed 可使用 MLX 和 OpenMedKit 进行本地处理。模型获取和用户配置的远程集成仍是独立的网络边界。

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

预期结果:Swift Package Manager 解析 OpenMedKit,并让你的应用 target 可以使用 import OpenMedKit。

  • MLX 运行时,用于 PII token 分类、Privacy Filter 系列、实验性的 GLiNER 系列 zero-shot 任务,以及通过 Laneformer 进行 Python MLX-LM 文本生成;对支持的 token 分类产物还提供 CoreML 回退路径。
  • 一个模型名,所有平台:在非 Apple 硬件上,MLX 模型名会自动回退到对应的 PyTorch 检查点。
  • Apple Silicon 上的 Python 同样支持:pip install --upgrade "openmed[mlx]"。

指南:MLX 后端 · OpenMedKit (Swift) · CoreML 导出

Apple Silicon 上 MLX 与 CPU 的延迟对比:速度提高 24 到 33 倍
Apple Silicon 上的 MLX 比 CPU PyTorch 快 24–33 倍:Privacy Filter 每次推理步骤的中位延迟,数值越低越好。

在 Android 设备上本地运行:Kotlin 与 ONNX Runtime Mobile

OpenMedKit 也以原生 Android/Kotlin 库的形式提供,用于本地文档导入、OCR 交接、PII 脱敏, 并通过 ONNX Runtime Mobile 进行 token 分类推理。移动端模型仓库包含稳定的 tensor 名称、 动态序列轴、tokenizer 文件、标签,以及可供 Android 使用的 fp32、fp16、INT8 和可选 .ort 输出。

在 settings.gradle.kts 中添加限定范围的 JitPack 仓库:

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

然后使用不可变的 OpenMed v3.0.0 版本:

dependencies {
    implementation("com.github.maziyarpanahi:openmed:v3.0.0")
}

本地构建和发布详情参见 Android 安装指南。

val model = OpenMedKit.fromDirectory(modelDir)
val entities = model.analyzeText("Patient Alice Nguyen was seen in cardiology.")
  • Android ONNX 配置会生成 model.onnx、model_fp16.onnx、 model_int8.onnx、tokenizer 资源、标签和 openmed-onnx.json。
  • ORT Mobile 支持会在安装 ONNX Runtime 转换工具时记录最小构建所需的算子配置。
  • Kotlin 对等测试确保 tokenizer offset、span 边界和 decoder 输出与 Python 运行时保持一致。

指南:Android ONNX 导出 · Android span 对等性 · OpenMedKit Android

在 Python CPU 上使用同一个 ONNX 模型

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.")

在浏览器中使用同一个 ONNX 模型

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.");

工作原理

flowchart LR
    A["临床文本"] --> B["OpenMed<br/>(本地优先)"]
    B --> C["医疗实体"]
    B --> D["检测到的 PII"]
    B --> E["去标识化文本"]
    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
Loading

渲染结果:本地临床文本流水线会返回医疗实体、PII 检测结果和已去标识化文本, 无需将数据发送到云端 API。


Agent Skills — 使用编码智能体构建 OpenMed

skills/ 目录提供可移植的 Agent Skills,覆盖设备本地去标识化、临床 NER、FHIR 导出、评估以及相关医疗工作流。同一套 SKILL.md 文件夹可用于 Claude Code、OpenAI Codex、OpenCode 和兼容的智能体;安装脚本会使用各客户端的 skills 目录,并同时支持跨客户端约定 ~/.agents/skills。

git clone https://github.com/maziyarpanahi/openmed && cd openmed
./install-skills.sh          # 安装到 Claude Code、Codex、OpenCode 和 ~/.agents/skills

然后使用合成占位符让智能体生成流水线:

构建一个本地 OpenMed 流水线,对合成出院记录进行去标识化并抽取药物实体。

它会加载相应 skills,并生成设备本地流水线(openmed.deidentify(...) → openmed.analyze_text(...))。完成一次性模型下载后,请在本地使用该流水线处理真实病历;不要把真实 PHI 粘贴到云端智能体提示词中。参阅 skills 目录与 30 秒示例。


快速开始

# 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]"

预期结果:

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])

示例输出:

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

REST 服务

python -m openmed.service.logging \
  --host 0.0.0.0 --port 8080

示例输出:

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

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

批处理

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]])

示例输出:

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

浏览器 / WebGPU

通过 Transformers.js 打包 ONNX token 分类导出,以便在浏览器中进行推理:

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

示例输出:

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));

示例输出:

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

Transformers.js 导出指南

离线 / 隔离网络? 只需将 model_name(或 model_id)指向本地目录,OpenMed 即会在本地加载,而不会连接 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}")

示例输出:

DISEASE      chronic myeloid leukemia     0.98
DISEASE      Type 2 diabetes              0.96

由于 model_id 指向本地目录,本示例不会连接 Hugging Face Hub 或任何外部模型提供方。


模型

精选的专业医疗 NER 模型注册表,浏览完整目录。

模型 专长 实体类型 大小
disease_detection_superclinical 疾病与病症 DISEASE, CONDITION, DIAGNOSIS 434M
pharma_detection_superclinical 药物与用药 DRUG, MEDICATION, TREATMENT 434M
pii_superclinical_large PII 与去标识化 NAME, DATE, SSN, PHONE, EMAIL, ADDRESS 434M
anatomy_detection_electramed 解剖与身体部位 ANATOMY, ORGAN, BODY_PART 109M
gene_detection_genecorpus 基因与蛋白质 GENE, PROTEIN 109M

隐私:PII 检测与去标识化

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)

示例输出:

[('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
  • 智能实体合并让 01/15/1970 保持完整,而不会被拆分。
  • 策略感知流水线提供 HIPAA/GDPR/研究配置、校准阈值、签名审计报告、脱敏预览,以及最小必要操作选择。
  • 基于 Faker 的混淆,内置自定义临床证件号 provider(CPF、CNPJ、BSN、NIR、Codice Fiscale、NIE、Aadhaar、Steuer-ID、NPI)。
  • HIPAA 边界:与 Safe Harbor 对齐的类别和可配置阈值属于实现辅助;仍需专家开展部署审查,仅使用 SDK 并不能证明合规。
  • 批量与流式 PII 处理:使用 BatchProcessor(operation="extract_pii" | "deidentify", batch_size=16) 或增量流式辅助函数,对大量文档进行抽取或去标识化。
批量 PII 处理吞吐量:CPU 最高提升 3.3 倍,MLX 最高提升 2.2 倍
批量处理:与逐个处理文档相比,CPU 吞吐量最高提升 3.3 倍,MLX 最高提升 2.2 倍。

完整 PII 笔记本 · 智能合并 · 匿名化快速入门

Privacy Filter 系列:基于 OpenAI Privacy Filter 架构的三个模型系列

模型代码相同(gpt-oss 风格的稀疏 MoE Transformer,带局部注意力、sink token、RoPE+YaRN、tiktoken o200k_base 分词),仅训练数据不同。它们都通过同一套 extract_pii() / deidentify() API 调用,只需更改 model_name= 参数。 openai/privacy-filter 是本地权重在 Hugging Face 上的模型标识符; 在此使用它不会调用 OpenAI API。

变体 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])

示例输出:

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

在非 Apple Silicon 主机上,MLX 模型名会自动替换为对应的 PyTorch 检查点(并给出一次性警告),写一个模型名,随处运行。参见 Privacy Filter 架构与后端路由。


多语言 PII(42 条支持的路由;35 条由模型支持)

实体抽取和去标识化支持 40 个 PII 语言代码: am、ar、as、bn、cs、da、de、el、en、es、fa、fr、gu、he、hi、id、it、ja、kn、ko、ml、mr、nl、no、or、pa、pt、ro、ru、sv、sw、ta、te、th、tr、uk、vi、xh、zh 和 zu,共计 已登记的 PII 模型目录。 俄语路由目前使用文档中说明的多语言默认模型占位符。孟加拉语、中文和泰米尔语拥有专用注册表条目。 一个由用户选择并配置的印度语言 NER 系列可服务于阿萨姆语、孟加拉语、古吉拉特语、印地语、卡纳达语、马拉雅拉姆语、马拉地语、奥里亚语、旁遮普语、泰米尔语和泰卢固语。请设置 OPENMED_INDIC_NER_MODEL; OpenMed 不会捆绑或自动选择这些权重。 OpenMed 还为其他仅含证件号的语言区域提供基于 validator 的国家证件号覆盖, 例如拉脱维亚、斯洛伐克、马来西亚、菲律宾和芬兰。

各语言代码的默认 PII 模型、Faker locale 和去标识化前后示例,参见分语言指南。

python -c "from openmed import extract_pii; print([(e.label, e.text) for e in extract_pii('Dr. Pedro Almeida, CPF: 123.456.789-09, email: pedro@hospital.pt', lang='pt').entities])"

示例输出:

[('NAME', 'Pedro Almeida'), ('ID', '123.456.789-09'), ('EMAIL', 'pedro@hospital.pt')]
查看各语言示例(葡萄牙语、荷兰语、印地语、阿拉伯语、日语、土耳其语)
from openmed import extract_pii

portuguese = extract_pii("Paciente: Pedro Almeida, CPF: 123.456.789-09, telefone: +351 912 345 678", lang="pt", use_smart_merging=True)
dutch      = extract_pii("Patiënt: Eva de Vries, BSN: 123456782, telefoon: +31 6 12345678", lang="nl", use_smart_merging=True)
hindi      = extract_pii("रोगी: अनीता शर्मा, फोन: +91 9876543210, पता: नई दिल्ली 110001", lang="hi", use_smart_merging=True)
arabic     = extract_pii("المريضة ليلى حسن، الهاتف +20 10 1234 5678، الرقم القومي 29801011234567.", lang="ar", use_smart_merging=True)
japanese   = extract_pii("患者 佐藤 花子、電話 +81 90 1234 5678、マイナンバー 1234 5678 9012.", lang="ja", use_smart_merging=True)
turkish    = extract_pii("Hasta Ayşe Yılmaz, telefon +90 532 123 45 67, TCKN 10000000146.", lang="tr", use_smart_merging=True)

for r in (portuguese, dutch, hindi, arabic, japanese, turkish):
    print([(e.label, e.text) for e in r.entities])

示例输出:

[('NAME', 'Pedro Almeida'), ('ID', '123.456.789-09'), ('PHONE', '+351 912 345 678')]
[('NAME', 'Eva de Vries'), ('ID', '123456782'), ('PHONE', '+31 6 12345678')]
[('NAME', 'अनीता शर्मा'), ('PHONE', '+91 9876543210'), ('ADDRESS', 'नई दिल्ली 110001')]
[('NAME', 'ليلى حسن'), ('PHONE', '+20 10 1234 5678'), ('ID', '29801011234567')]
[('NAME', '佐藤 花子'), ('PHONE', '+81 90 1234 5678'), ('ID', '1234 5678 9012')]
[('NAME', 'Ayşe Yılmaz'), ('PHONE', '+90 532 123 45 67'), ('ID', '10000000146')]

REST API

一个对 Docker 友好的 FastAPI 服务,具备请求校验、共享流水线预加载,以及统一的错误响应封装。

pip install --upgrade "openmed[hf,service]"
python -m openmed.service.logging --host 0.0.0.0 --port 8080

# or with Docker
docker build -t openmed:local .
docker run --rm -p 8080:8080 -e OPENMED_PROFILE=prod openmed:local

示例输出:

INFO:     Uvicorn running on http://0.0.0.0:8080
curl -X POST http://127.0.0.1:8080/pii/extract \
  -H "Content-Type: application/json" \
  -d '{"text":"Paciente: Maria Garcia, DNI: 12345678Z","lang":"es"}'

简化的响应示例:

{
  "text": "Paciente: Maria Garcia, DNI: 12345678Z",
  "entities": [
    {"text": "Maria Garcia", "label": "NAME", "confidence": 0.99, "start": 10, "end": 22},
    {"text": "12345678Z", "label": "ID", "confidence": 0.98, "start": 29, "end": 38}
  ],
  "model_name": "OpenMed/privacy-filter-multilingual"
}

**模型生命周期和服务控制:**通过 GET /models/loaded、POST /models/unload 和 keep_alive 空闲时限按需释放内存;v1.8 还提供 API key/JWT 身份验证、 不含 PHI 的请求日志、tracing、gRPC、异步任务、webhook、warm pool、动态批处理、 请求合并、速率与并发限制、/livez、/readyz 和可选 metrics:

OPENMED_SERVICE_KEEP_ALIVE=10m python -m openmed.service.logging --host 0.0.0.0 --port 8080
curl -X POST http://127.0.0.1:8080/models/unload -H "Content-Type: application/json" -d '{"all":true}'

示例响应:

{
  "unloaded": true,
  "released": {"models": 1, "tokenizers": 1, "pipelines": 1},
  "active_models": {}
}

参见完整的 REST 服务指南。


文档

完整指南见 openmed.life/docs。

AI 智能体可以加载精选的 llms.txt 索引,或加载内联全文的 llms-full.txt 信息流。每次严格构建 MkDocs 时,两者都会根据当前文档重新生成。

快速入门 文本分析 模型注册表
常见问题 匿名化 批处理
配置档案 REST 服务 MLX 后端
Transformers.js 导出 FHIR 互操作 HL7 v2 去标识化
OpenMed 3.0.0 迁移指南 OpenMed 2.2.0 发行说明 示例
发布通道 生成式模型策略 贡献指南
安全策略 合规状态 扩展插件 SDK
v1 到 v2 迁移 MCP 客户端连接 非洲开发者入门

认识一下我们的吉祥物

OpenMed 吉祥物

OpenMed 的守护者是一只蓬松的波斯猫,化身为小小的阿维森纳(伊本·西那,Avicenna / Ibn Sina),这位伟大的 波斯医师所著的《医典》(Canon of Medicine)在约 600 年间一直是全世界的标准医学教科书。它守护着翻开的 医学知识之书,配色取自波斯绿松石(fīrūza):一位守护你最私密数据的本地优先卫士。



贡献

欢迎贡献:bug 报告、功能请求和 PR 都欢迎。请先阅读贡献指南和行为准则。


安全

发现漏洞?OpenMed 会对 PHI 进行脱敏,因此脱敏绕过或 PHI/PII 泄漏属于安全问题: 请通过私密渠道报告,切勿提交公开 issue。负责任披露政策参见 SECURITY.md, 也可使用私密报告表单。 报告中绝不能包含真实患者数据。


致谢

OpenMed 建立在优秀的开源工作之上:特别感谢 OpenAI(Privacy Filter 架构)、NVIDIA(Nemotron PII 数据集)、Hugging Face(transformers、Transformers.js 及模型生态)、Apple(MLX),以及 Faker 的维护者。

许可证

OpenMed SDK 源代码基于 Apache-2.0 License 发布。第三方资源声明记录在 NOTICE 中。

引用

@misc{panahi2025openmedneropensourcedomainadapted,
      title={OpenMed NER: Open-Source, Domain-Adapted State-of-the-Art Transformers for Biomedical NER Across 12 Public Datasets},
      author={Maziyar Panahi},
      year={2025},
      eprint={2508.01630},
      archivePrefix={arXiv},
      primaryClass={cs.CL},
      url={https://arxiv.org/abs/2508.01630},
}

预期结果:可在论文、海报和衍生文档中引用 OpenMed 的 BibTeX 兼容元数据。


Star 历史

如果 OpenMed 对你有帮助,点个 star 能帮助更多人发现它。

5,400+ GitHub stars · 9 Oct 2026 snapshot


由 OpenMed 团队打造

网站 · 文档 · X / Twitter · LinkedIn