OpenMed PPTX 幻灯片与演讲者备注脱敏实战:文本提取、偏移投影与写入还原
2026/9/18 6:28:55 网站建设 项目流程

OpenMed PPTX 幻灯片与演讲者备注脱敏实战:文本提取、偏移投影与写入还原

【免费下载链接】openmedLocal-first healthcare AI: clinical NER & HIPAA PII de-identification that runs 100% on-device. 2,200+ medical models, 21 languages, Apple MLX + Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed

OpenMed 通过共享的多模态文档契约(ExtractedDocument+SourceSpan),可以从 PowerPoint 幻灯片形状、表格单元格与演讲者备注中提取归一化文本流及 run 级来源信息(provenance),再将 NER 检测结果投影回原始 run 并写出脱敏副本,全程不在审计元数据中落盘明文 PHI。读完本文,你将掌握extract_pptx的偏移语义、map_text_spans_to_pptx_runs/write_redacted_pptx的跨 run 写回机制,以及redact_document调度器的端到端用法。

前置条件:安装 multimodal 扩展

PPTX 处理依赖python-pptx,属于 OpenMed 的可选 multimodal 依赖。OpenMed 刻意将这类重型解析库做惰性导入,import openmed.multimodal本身保持轻量(见 base.py 中对pdfplumber / python-docx / python-pptx / Pillow等依赖的延迟加载策略),只有在真正运行 PPTX 处理器时才会尝试导入pptx,缺失时抛出带安装提示的MissingDependencyError

先安装 multimodal extra:

uv pip install ".[multimodal]"

multimodal extra 中与 PPTX 相关的依赖声明位于 pyproject.toml:python-pptx>=1.0(另有python-docx>=1.1pdfplumber>=0.11openpyxlPillowpydicom等配套解析库)。若已通过其他方式安装过python-pptx,处理器同样可以工作——安装 extra 只是最省心的方式。

共享契约:归一化文本流与 run 级来源

在深入 API 之前,先理解 OpenMed 多模态子系统的统一契约。每个格式的 ingester(PDF/DOCX/HTML/PPTX/OCR/图像……)都返回一个 ExtractedDocument:

  • text:按固定规则拼接出的归一化文本字符串;
  • spans:一组SourceSpan,每个 span 把text中的一段字符区间(start/endend为开区间)映射回源文档中的具体位置;
  • metadata:文档级元信息(如幻灯片数、每页偏移、run 统计)。

SourceSpanpage字段对 PPTX 而言即零基幻灯片索引;metadata携带每块文本的详细定位信息。这套"单一归一化字符串 + 字符偏移到源位置的反查表"设计,让下游脱敏只需在一个字符串上做区间运算,同时仍能把任意偏移精确映射回源文件。

提取文本与偏移:extract_pptx

核心入口是 extract_pptx:

from openmed.multimodal import extract_pptx document = extract_pptx("clinical-case.pptx") print(document.text) for source in document.spans: print( source.page, source.metadata["part"], source.metadata["slide_start"], source.metadata["slide_end"], )

归一化规则与 span 语义

从 pptx.py 的_append_text_frame实现可以看到精确规则:

  • 段落之间以换行符\n分隔(_BLOCK_SEPARATOR),因此document.text是跨幻灯片、跨形状拼接出的单一字符串;
  • 每个非空 PowerPoint run 生成一个SourceSpan,run 的文本原样追加;空 run 被跳过(但仍占用document_run_index计数,保证与源 run 一一对应);
  • span 的page为当前幻灯片索引,metadata中既有文档级全局偏移(slide_start/slide_end该幻灯片内部的字符偏移),也有定位键:part"slide""notes")、block_type"shape"/"table_cell"/"speaker_notes")、block_indexparagraph_indexrun_indexdocument_run_index,表格单元格还会带上row_indexcell_index,嵌套形状会带点分路径shape_path

覆盖的文本来源

_iter_slide_text_frames(pptx.py)按如下顺序枚举每张幻灯片的文本承载:

  1. 幻灯片形状的文本框架(has_text_frame),包括分组形状——_iter_shapes会递归展开嵌套shapes(pptx.py);
  2. 表格单元格(has_table的形状,逐行逐单元格提取cell.text_frame);
  3. 演讲者备注(slide.has_notes_slide时的notes_slide.notes_text_framepart="notes")。

文档级元数据

extract_pptx返回的document.metadata包含:

字段含义
format固定为"pptx"
slide_count演示文稿幻灯片总数
slide_offsets每张幻灯片的{slide_index, start, end, length}包括空幻灯片(空幻灯片 start/end 取当前游标位置、length 为 0)
paragraph_count非空段落总数
text_run_count含文本的 run 总数
document_run_count全部 run 总数(含空 run)

slide_offsets的存在意味着下游可以只凭偏移在幻灯片维度切片文本,例如按页定位某段检测文本属于哪张幻灯片。

投影检测结果并写入脱敏副本

准备检测实体

先用document.text上的偏移构造实体。注意:必须使用document.text的偏移(而非原始文件的偏移),因为document.text是归一化拼接后的字符串:

from openmed.multimodal import ( map_text_spans_to_pptx_runs, write_redacted_pptx, ) name = "Jane Doe" start = document.text.index(name) entities = [ { "start": start, "end": start + len(name), "label": "PERSON", } ] provenance = map_text_spans_to_pptx_runs(document, entities) write_redacted_pptx( "clinical-case.pptx", "clinical-case.redacted.pptx", entities, )

write_redacted_pptx内部会依次执行extract_pptxmap_text_spans_to_pptx_runs→ 写回(pptx.py),所以它接受的是同一套归一化文本偏移。

实体输入的灵活形态

map_text_spans_to_pptx_runs/write_redacted_pptxspans参数非常宽容(见 pptx.py 的_iter_entity_inputs/_coerce_entity):

  • 字典:{"start": …, "end": …, "label": …, "confidence": …, "replacement": …}label也可用entity_type/entity_group,置信度可用score,替换文本可用redacted_text);
  • 二元素/三元组序列:(start, end)(start, end, label)
  • entities/pii_entities属性的检测器结果对象;
  • 任何带start/end属性的对象。

这些设计让同一个函数可以无缝对接 OpenMed 自己的 NER 输出、其他库的 span 对象或手写字典。

跨 run 写回与默认替换

默认替换文本为基于标签的掩码,如[PERSON]。生成规则见_mask_for_label(pptx.py):将标签大写、非字母数字字符替换为下划线后包进方括号,标签为空时退化为[PHI]。你也可以通过replacement=参数统一覆盖,或为单个实体指定replacement字段。

一个检测跨度可能横跨多个带样式的 run(例如"Jane ""Doe"是不同 run)。_write_pptx_redactions(pptx.py)的处理策略是:把替换文本插入第一个被覆盖的 run,其余被覆盖 run 中仅删除对应区间文本——这样既完成脱敏,又最大限度保留原有样式结构。重叠的实体区间会被_non_overlapping_redactions按"先到先得"去重,保证写回时区间不冲突。

返回的 provenance:PHI 安全

map_text_spans_to_pptx_runs返回PptxRedaction记录元组,每个记录包含(pptx.py 与 pptx.py):

  • start/end:归一化文本中的偏移区间;
  • labelconfidence:实体标签与置信度(如提供);
  • replacement:实际写入的替换文本;
  • run_rangesPptxRunRange列表,每个元素含document_run_index、run 内局部偏移run_start/run_end、以及含part/slide_index/slide_start/slide_end/block_type等的来源定位元数据;
  • metadata.text_sha256:被移除明文文本的 SHA-256 摘要(而非明文本身);source_span_count覆盖的 run 数;slide_indices涉及幻灯片索引集合。

关键设计点:provenance 携带偏移、标签、置信度、来源位置和被删文本的 SHA-256 摘要,但绝不包含明文 PHI,因此审计日志与溯源元数据本身不会泄露患者信息。

使用多模态调度器:redact_document

openmed.multimodal被导入时,.pptx处理器通过 register_handler(".pptx", _pptx_handler) 注册进统一调度器(注册表定义在 base.py)。此后可以用与 PDF/DOCX/图像一致的方式处理 PPTX:

from openmed.multimodal import redact_document result = redact_document( "clinical-case.pptx", models={"detector": detector}, policy={"output_path": "clinical-case.redacted.pptx"}, lang="en", )

检测器解析

models参数可以是:

  • 一个可调用对象detector(text, lang=...)
  • 字典,OpenMed 会依次查找detector/extract_pii/analyze_text/predict_entities键;
  • 任意对象,会尝试detect/extract_pii/analyze_text/predict_entities/predict方法。

解析逻辑见_resolve_detector(pptx.py)。检测器被调用时优先传lang=关键字,若抛出TypeError则退化为仅传文本。测试中使用的检测器形态为def detector(text, *, lang=None)(见 test_pptx_redact.py)。

policy 选项

policy支持:

  • output_path(别名redacted_path/destination_path):写出脱敏副本的路径;未提供时,调度器只提取文本并返回投影后的脱敏 provenance,不写任何文件
  • replacement:全局替换文本,覆盖所有实体的默认[LABEL]掩码。

调度器返回的ExtractedDocument.metadata会附加detected_span_countpptx_redactions(每个PptxRedaction的 PHI 安全字典形态,见to_dict)、以及redacted_pptx_path(写出时)等字段。测试 test_pptx_redact.py 验证了注册与写出链路:断言".pptx" in base._HANDLERSredacted_pptx_path正确、且 redaction 记录中不包含"Alice Smith"明文。

端到端示例:一张幻灯片、三种来源同时脱敏

参考 test_pptx_redact.py 构造的合成演示文稿(无真实患者数据),一个典型场景是同一页 PPT 中:文本框里是Patient Jane Doe(三个 run)、表格里是MRN A123、演讲者备注里是Call Dr. Alice Smith,第二页还有Follow-up for Bob Stone

from openmed.multimodal import extract_pptx, write_redacted_pptx document = extract_pptx("clinical-case.pptx") entities = [] for token, label in [("Jane Doe", "PERSON"), ("A123", "ID_NUM"), ("Alice Smith", "PERSON")]: start = document.text.index(token) entities.append({"start": start, "end": start + len(token), "label": label}) out = write_redacted_pptx("clinical-case.pptx", "clinical-case.redacted.pptx", entities)

脱敏结果(与测试断言一致,见 test_pptx_redact.py):

  • 幻灯片形状:Patient [PERSON]
  • 表格单元格:MRN [ID_NUM]
  • 演讲者备注:Call Dr. [PERSON]
  • 未命中的第二页Follow-up for Bob Stone原样保留;
  • 全文档中不再出现Jane DoeA123Alice Smith明文。

该测试同时验证了偏移反查:document.location_at(document.text.index("Jane"))能定位到block_type == "shape"的 span,A123能定位到table_cell(带row_index/cell_index),Alice能定位到part == "notes"speaker_notesspan,且每页slide_offsets精确覆盖各自文本区间(test_pptx_redact.py)。跨 run 场景中,Jane Doe覆盖 2 个 run,两个run_rangerun_start/run_end均为[0, 4],替换文本只落在第一个覆盖 run 上(test_pptx_redact.py)。

范围与限制

  • 支持:幻灯片形状文本、分组形状内文本、表格单元格、演讲者备注。
  • 不检查嵌入图片:图片中的 PHI 需要使用 OpenMed 的图像/OCR 脱敏管线(openmed/multimodal/image.pyocr.py)。
  • 写回保真度:写回保留演示文稿结构与未受影响 run 的格式,但替换后的精确版面布局不做保证。
  • 不在本适配器范围内:SmartArt、图表、OLE 对象、批注、母版与版式模板文本。这些内容中的敏感信息需要另行评估处理方案。

进一步阅读

  • 源码实现:openmed/multimodal/pptx.py(提取/投影/写回全链路)、openmed/multimodal/base.py(ExtractedDocument/SourceSpan/redact_document契约)、openmed/multimodal/init.py(公开 API 与 handler 注册入口)
  • 测试验证:tests/unit/multimodal/test_pptx_redact.py
  • 能力总览:docs/feature-map.md("Documents and metadata" 一节列出 PPTX slide/table/speaker-notes redaction 及对应模块)
  • 版本背景:PPTX 处理随 2.2 版本的"cross-format offset projection、XLSX/PPTX/ODT handling"能力引入,参见 docs/migration/2.1-to-2.2.md 与 docs/release/v2.2.0.md
  • 依赖与安装:multimodalextra 声明见 pyproject.toml,python-pptx为 MIT 许可(见 docs/security/license-inventory.md)

【免费下载链接】openmedLocal-first healthcare AI: clinical NER & HIPAA PII de-identification that runs 100% on-device. 2,200+ medical models, 21 languages, Apple MLX + Python, no cloud, no patient data leaving your network. Apache-2.0项目地址: https://gitcode.com/GitHub_Trending/ope/openmed

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询