Agent Skillsmaziyarpanahi/openmed › ingesting-clinical-documents

ingesting-clinical-documents

GitHub

将扫描传真、图像及CSV/CDA等临床文档转换为清洗后的文本,支持本地OCR与结构化提取。作为预处理阶段,为后续去标识化和NER提供标准化输入,确保数据不出设备。

skills/ingesting-clinical-documents/SKILL.md maziyarpanahi/openmed

Trigger Scenarios

用户有扫描的临床笔记需要OCR识别 处理CSV/TSV患者导出数据的列感知解析 将C-CDA XML扁平化为文本 构建 feeding 去标识化或实体抽取的前置摄入流程 询问关于Tesseract/PaddleOCR引擎或多模态摄入细节

Install

npx skills add maziyarpanahi/openmed --skill ingesting-clinical-documents -g -y
More Options

Use without installing

npx skills use maziyarpanahi/openmed@ingesting-clinical-documents

指定 Agent (Claude Code)

npx skills add maziyarpanahi/openmed --skill ingesting-clinical-documents -a claude-code -g -y

安装 repo 全部 skill

npx skills add maziyarpanahi/openmed --all -g -y

预览 repo 内 skill

npx skills add maziyarpanahi/openmed --list

SKILL.md

Frontmatter
{
    "name": "ingesting-clinical-documents",
    "license": "Apache-2.0",
    "metadata": {
        "pairs": "before",
        "project": "OpenMed",
        "version": "1.0",
        "category": "imaging-ocr"
    },
    "description": "Turn scanned faxes, images, and CSV\/CDA exports into clean text ready for OpenMed de-identification and NER, fully on-device. Use when the user has clinical documents (image scans, photographed\/faxed notes, tabular CSV\/TSV exports, C-CDA XML) and needs OCR or structured intake before openmed.deidentify and openmed.analyze_text, asks about openmed.multimodal, OCR engines (Tesseract \/ PaddleOCR), tabular redaction, or layout and reading order. Covers the verified ocr() and redact_document() entry points and the ExtractedDocument contract. Pairs before deidentifying-clinical-text and extracting-clinical-entities."
}

Ingesting Clinical Documents

Clinical text often arrives as scanned faxes, photographed notes, CSV exports, or C-CDA XML — not plain text. openmed.multimodal converts these into a normalized ExtractedDocument (clean text + character-offset → source-location spans) so you can run de-identification and NER. It runs on-device: OCR backends are local, no document leaves the machine.

When to use

  • You have images / scanned faxes of clinical notes and need text out (OCR).
  • You have CSV/TSV patient exports that need column-aware handling.
  • You have C-CDA XML to flatten into text.
  • You are building the intake stage that feeds openmed.deidentify and openmed.analyze_text.

This is the first stage. After intake, hand off to deidentifying-clinical-text then extracting-clinical-entities.

What is supported today

redact_document dispatches by file extension. Live handlers:

Input Extensions Path
Images / scans .png .jpg .jpeg .tif .tiff .bmp .gif .webp OCR (ocr() / image handler)
Tables .csv .tsv column-aware tabular redaction
C-CDA .xml (detected as CDA) stdlib CDA adapter

PDF and DOCX have no live handler yetredact_document("x.pdf") raises UnsupportedDocumentError. Convert PDFs to page images first (or to text with your own tool) and feed the images through OCR. See references/multimodal-ingest.md for the full contract, engines, and the tabular pipeline.

Install

pip install "openmed[multimodal]"      # document intake contract + image deps
pip install "openmed[ocr-paddle]"      # add the PaddleOCR engine
# Tesseract engine also needs the system binary, e.g.:  brew install tesseract

Quick start: OCR an image, then de-identify

The clean two-step intake path. ocr() lives in the submodule (it is intentionally not re-exported from openmed.multimodal):

from openmed.multimodal.ocr import ocr
import openmed

# 1) OCR a scanned/faxed note -> OcrResult -> ExtractedDocument -> plain text
result = ocr("fax_page.png", engine=None)   # None = auto-select an installed engine
doc    = result.to_document()                # ExtractedDocument
text   = doc.text                            # clean text for downstream OpenMed

# 2) De-identify, then run NER (privacy-first order)
deid = openmed.deidentify(text, method="mask", policy="hipaa_safe_harbor")
ner  = openmed.analyze_text(deid.deidentified_text, output_format="dict")

for ent in ner.entities:
    print(ent.label, ent.text, ent.confidence)

engine may be None (auto-select), "tesseract", "paddleocr", or an OcrEngine instance. OcrResult exposes .text and per-word boxes via .words (each OcrWord has text, bbox, confidence, page).

One-step intake + redaction with redact_document

For images, CSV/TSV, and CDA, redact_document performs intake and de-identification in a single, format-aware call, returning an already-redacted ExtractedDocument:

from openmed.multimodal import redact_document

# Image scan: OCR + redact in one call
doc = redact_document("fax_page.png")
print(doc.text)        # redacted text
print(doc.spans[:3])   # SourceSpan offsets -> page / bbox in the original scan

# CSV export: per-column classification (direct id / quasi-id / safe) + redaction
table_doc = redact_document("patients.csv")
print(table_doc.text)

Use redact_document when you want OpenMed to own intake and redaction (especially for tables, where redaction is column-scoped, not free-text NER). Use the ocr()to_document()deidentify path when you want to control the de-identification method, policy, or mapping yourself.

Tabular CSV/TSV redaction

CSV columns get classified before any cell is touched, so a free-text NER pass is not run blindly over structured data:

from openmed.multimodal import read_table, redact_table

view = read_table("patients.csv")            # TableView with column decisions
for col in view.columns:
    print(col.name, "->", col.assigned_class, col.action, col.canonical_label)

redacted = redact_table("patients.csv", keep_year=True)
print(redacted.text)            # redacted CSV
for entry in redacted.manifest: # PHI-SAFE audit: counts/actions per column, no raw values
    print(entry)

redact_table(...) returns a RedactedTable with .text, .headers, .rows, .columns, and a PHI-safe .manifest (no raw cell values). See references/multimodal-ingest.md for column classes and actions.

Preserve layout / reading order and map back to the source

Every ExtractedDocument keeps character offset → source location. After detecting PHI on doc.text, project a span's offset back to its page and bounding box:

from openmed.multimodal.ocr import ocr
import openmed

doc  = ocr("fax_page.png").to_document()
deid = openmed.deidentify(doc.text, method="mask")

for ent in deid.pii_entities:
    loc = doc.location_at(ent.start)   # SourceSpan or None
    if loc is not None:
        print(ent.label, "page", loc.page, "bbox", loc.bbox)

This lets you redact pixels on the original scan, not just the extracted text.

Hand-off to / from OpenMed

  • To deidentifying-clinical-text: pass doc.text to openmed.deidentify(...) with a policy profile; this is the required next stage for PHI.
  • To extracting-clinical-entities: run openmed.analyze_text on the redacted text, not raw OCR output.
  • From file conversion (out-of-process): for PDFs/DOCX, render to page images with your own tool, then OCR those images through this skill.

Edge cases & gotchas

  • ocr() is imported from the submodule: from openmed.multimodal.ocr import ocr. It is deliberately not re-exported from openmed.multimodal.
  • No PDF/DOCX handler yet: redact_document raises UnsupportedDocumentError for them. Rasterize to images first.
  • OCR needs a backend: install [ocr-paddle] for PaddleOCR, or the system Tesseract binary for pytesseract. Missing backends raise MissingDependencyError with an install hint.
  • OCR is noisy: misreads lower downstream recall. Prefer higher-DPI scans; inspect OcrWord.confidence to flag low-quality pages.
  • Tables are not free text: redact_table redacts per column classification — don't run whole-table NER and expect structured columns to be handled correctly.
  • No raw PHI in artifacts: the table manifest and any logs record counts/actions/labels, never raw values. Keep OCR intermediates on-device and out of logs.
  • Local-first: OCR engines run locally; do not send scans to a cloud OCR API in a PHI workflow.

Standards & references

Version History

  • f213557 Current 2026-07-23 00:45

Same Skill Collection

skills/building-with-openmed/SKILL.md
skills/loading-openmed-models/SKILL.md
skills/annotating-variants/SKILL.md
skills/assembling-fhir-bundles/SKILL.md
skills/auditing-deid-leakage/SKILL.md
skills/auditing-deidentification-runs/SKILL.md
skills/auditing-part11-trails/SKILL.md
skills/auditing-safe-harbor-checklist/SKILL.md
skills/auditing-subgroup-fairness/SKILL.md
skills/authoring-model-cards/SKILL.md
skills/batch-processing-clinical-text/SKILL.md
skills/benchmarking-clinical-ner/SKILL.md
skills/bridging-presidio-and-spacy/SKILL.md
skills/building-gold-corpus/SKILL.md
skills/building-patient-timelines/SKILL.md
skills/checking-hipaa-compliance/SKILL.md
skills/choosing-openmed-models/SKILL.md
skills/coding-hcc-risk-adjustment/SKILL.md
skills/coding-icd10/SKILL.md
skills/computing-ecqms/SKILL.md
skills/configuring-privacy-policies/SKILL.md
skills/defining-cohort-phenotypes/SKILL.md
skills/deidentifying-clinical-text/SKILL.md
skills/deidentifying-multilingual-text/SKILL.md
skills/deploying-openmed-mcp/SKILL.md
skills/detecting-pv-signals/SKILL.md
skills/enforcing-nophi-logging/SKILL.md
skills/etl-to-omop-cdm/SKILL.md
skills/evaluating-with-leakage-gates/SKILL.md
skills/exporting-bulk-fhir/SKILL.md
skills/exporting-to-fhir/SKILL.md
skills/extracting-clinical-entities/SKILL.md
skills/extracting-dicom-metadata/SKILL.md
skills/extracting-lab-tables/SKILL.md
skills/extracting-pii-entities/SKILL.md
skills/extracting-sdoh/SKILL.md
skills/fetching-fhir-resources/SKILL.md
skills/gating-deid-leakage/SKILL.md
skills/generating-synthea-data/SKILL.md
skills/generating-synthetic-surrogates/SKILL.md
skills/linking-umls-concepts/SKILL.md
skills/mapping-loinc/SKILL.md
skills/mapping-to-snomed/SKILL.md
skills/mining-pubmed-literature/SKILL.md
skills/normalizing-rxnorm/SKILL.md
skills/parsing-ccda-documents/SKILL.md
skills/parsing-hl7v2-messages/SKILL.md
skills/parsing-lab-values/SKILL.md
skills/parsing-trial-eligibility/SKILL.md

Metadata

Files
0
Version
f213557
Hash
f3db6a26
Indexed
2026-07-23 00:45

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-29 23:31
浙ICP备14020137号-1 $Carte des visiteurs$