260 lines
13 KiB
Markdown
260 lines
13 KiB
Markdown
# 患者首页 PDF 本地处理工作流
|
||
|
||
这个目录用于批量处理“患者首页 PDF”,把每份 PDF 抽取成结构化记录,并输出到 `数据处理结果区/`。
|
||
|
||
## 目录约定
|
||
|
||
- `待处理-患者首页PDF/`:放入等待处理的 PDF,文件名建议保留首页病案号或住院号。
|
||
- `数据处理工作区/`:存放处理脚本和后续工作流工具。
|
||
- `数据处理结果区/`:脚本输出 CSV、JSONL、单份 JSON、抽取文本、PDF 图片对照页和复核清单。
|
||
- `数据可视化网页端/`:Docker 化复核网页端,包含概览、复核、抽查、抽查一览、设置;设置内统一管理用户与权限、数据库状态和目录信息。
|
||
- `已处理-患者首页PDF/`:人工确认后,可把已处理 PDF 移到这里归档。
|
||
|
||
## 工作区文件
|
||
|
||
- `数据处理工作区/01_配置规则/01_科室分类规则.json`:子科室到大科室的分类规则。
|
||
- `数据处理工作区/02_解析入库/02_患者首页PDF解析与入库.py`:解析 PDF,生成 CSV/JSON,并可写入 PostgreSQL。
|
||
- `数据处理工作区/03_人工复核/03_人工复核导出与回写.py`:从 PostgreSQL 导出人工复核表,并把人工修正结果回写。
|
||
- `数据处理工作区/04_质量体检/04_字段核验与数据库体检.py`:检查字段注释、关键字段空值和疑似错位记录。
|
||
- `数据处理工作区/05_备用读取/05_备用PDF转Markdown_Mineru.py`:备用 PDF 转 Markdown 工具,用于扫描件或 `pdftotext` 读取异常时兜底。
|
||
- `数据处理工作区/06_图片对照核验/06_PDF转图片与对照核验.py`:把 PDF 转为图片,生成图片-字段对照 HTML 和缺项核验索引。
|
||
- `数据处理工作区/07_Kimi视觉兜底/07_Kimi图片识别辅助.py`:可选的 Kimi 视觉识别兜底,仅在文本/Markdown 解析仍不稳定时人工触发。
|
||
|
||
## 环境文件
|
||
|
||
本地 `.env` 保存 PostgreSQL 连接信息和网页端目录映射,已被 `.gitignore` 忽略,不会提交到 Gitea。网页端模板见:
|
||
|
||
```text
|
||
数据可视化网页端/.env.example
|
||
```
|
||
|
||
`.env` 也可配置 `MOONSHOT_API_KEY` 和 `KIMI_MODEL`。涉及患者信息的图片不会自动上传,Kimi 视觉步骤只在人工运行 `07_Kimi图片识别辅助.py` 时调用。
|
||
|
||
## 快速运行
|
||
|
||
在当前项目根目录执行:
|
||
|
||
```bash
|
||
python3 数据处理工作区/02_解析入库/02_患者首页PDF解析与入库.py
|
||
```
|
||
|
||
默认 `--text-source auto`:先用 `pdftotext`,如果抽取文本过短或缺少首页关键标记,再调用 Mineru 转 Markdown。
|
||
|
||
强制使用 Mineru:
|
||
|
||
```bash
|
||
python3 数据处理工作区/02_解析入库/02_患者首页PDF解析与入库.py \
|
||
--text-source mineru \
|
||
--mineru-url "http://MINERU_HOST:4000/extract"
|
||
```
|
||
|
||
单独运行 PDF 转 Markdown:
|
||
|
||
```bash
|
||
python3 数据处理工作区/05_备用读取/05_备用PDF转Markdown_Mineru.py \
|
||
-s 待处理-患者首页PDF \
|
||
-t 数据处理结果区/06_Mineru_MD \
|
||
-u "http://MINERU_HOST:4000/extract"
|
||
```
|
||
|
||
正式流程建议同时写入 PostgreSQL:
|
||
|
||
```bash
|
||
export PGPASSWORD='请填写数据库密码'
|
||
python3 数据处理工作区/02_解析入库/02_患者首页PDF解析与入库.py \
|
||
--write-postgres \
|
||
--pg-host DB_HOST \
|
||
--pg-port 5432 \
|
||
--pg-database DB_NAME \
|
||
--pg-user DB_USER \
|
||
--pg-table Patient_FrontPages
|
||
unset PGPASSWORD
|
||
```
|
||
|
||
也可以指定输入和输出目录:
|
||
|
||
```bash
|
||
python3 数据处理工作区/02_解析入库/02_患者首页PDF解析与入库.py \
|
||
--input-dir 待处理-患者首页PDF \
|
||
--output-dir 数据处理结果区
|
||
```
|
||
|
||
生成 PDF 图片对照页:
|
||
|
||
```bash
|
||
python3 数据处理工作区/06_图片对照核验/06_PDF转图片与对照核验.py --force
|
||
```
|
||
|
||
该步骤会读取 `02_单份JSON/` 的结构化结果,把每份 PDF 转为 PNG,并生成:
|
||
|
||
- `数据处理结果区/06_PDF图片对照/图片/`:每份 PDF 一个图片目录。
|
||
- `数据处理结果区/06_PDF图片对照/患者首页_PDF图片对照.html`:浏览器打开后可左侧看原图、右侧看结构化字段和缺项提示。
|
||
- `数据处理结果区/06_PDF图片对照/患者首页_PDF图片对照索引.csv`:按 PDF 汇总页数、复核状态、核心缺项、建议核对缺项。
|
||
|
||
启动可视化网页端:
|
||
|
||
```bash
|
||
docker compose -f 数据可视化网页端/docker-compose.yml up -d --build
|
||
```
|
||
|
||
打开:
|
||
|
||
```text
|
||
http://localhost:8501
|
||
```
|
||
|
||
首次进入会显示登录界面;默认管理员为 `admin`,默认密码为 `change-me`。设置页创建的本地用户会同步作为登录账号,并按权限控制各页面。
|
||
|
||
网页端会显示数据库连接情况、记录数、需复核数、PDF 数量;人工修改右侧字段并点击“复核并保存”后,会同步更新 PostgreSQL,并把 `manual_corrected` 标记为 `true`。
|
||
|
||
网页端说明:
|
||
|
||
- PDF 以 `inline` 方式在页面内打开,不再作为附件触发保存;浏览器内核无法彻底禁止用户保存已展示内容。
|
||
- “复核并保存”后,复核状态由后端自动标记为 `reviewed`,复核状态和质控状态只读显示在 PDF 下方。
|
||
- 诊断、手术、费用等 JSON 字段在右侧以表格方式编辑,保存时再写回 JSONB。
|
||
- 手术操作按编码、日期、级别、名称、术者、I助、II助、切口愈合等级、麻醉方式、麻醉医师拆分展示。
|
||
|
||
可选 Kimi 视觉兜底:
|
||
|
||
```bash
|
||
python3 数据处理工作区/07_Kimi视觉兜底/07_Kimi图片识别辅助.py \
|
||
--case ZY010001672803_ori \
|
||
--page page-001.png
|
||
```
|
||
|
||
输出位于 `数据处理结果区/07_Kimi视觉识别/`,默认不直接覆盖 PostgreSQL,需要人工确认后再回写。
|
||
|
||
## 人工复核流程
|
||
|
||
从 PostgreSQL 导出待复核表:
|
||
|
||
```bash
|
||
export PGPASSWORD='请填写数据库密码'
|
||
python3 数据处理工作区/03_人工复核/03_人工复核导出与回写.py export \
|
||
--pg-host DB_HOST \
|
||
--pg-port 5432 \
|
||
--pg-database DB_NAME \
|
||
--pg-user DB_USER \
|
||
--pg-table Patient_FrontPages
|
||
unset PGPASSWORD
|
||
```
|
||
|
||
人工在 `数据处理结果区/04_复核与人工校正/患者首页_人工复核表.csv` 中填写:
|
||
|
||
- `manual_review_notes`:人工复核说明。
|
||
- `corrected_medical_record_no`:修正后的病案号。
|
||
- `corrected_patient_name`:修正后的姓名。
|
||
- `corrected_major_department`:修正后的大科室。
|
||
- `corrected_primary_diagnosis`、`corrected_primary_diagnosis_code`:修正后的主要诊断。
|
||
- `corrected_total_cost`、`corrected_self_pay_amount`:修正后的费用。
|
||
- `mark_review_status`:建议填 `reviewed`;确实仍有问题可填 `needs_review`。
|
||
|
||
回写 PostgreSQL:
|
||
|
||
```bash
|
||
export PGPASSWORD='请填写数据库密码'
|
||
python3 数据处理工作区/03_人工复核/03_人工复核导出与回写.py import \
|
||
--pg-host DB_HOST \
|
||
--pg-port 5432 \
|
||
--pg-database DB_NAME \
|
||
--pg-user DB_USER \
|
||
--pg-table Patient_FrontPages
|
||
unset PGPASSWORD
|
||
```
|
||
|
||
回写后建议做数据库体检:
|
||
|
||
```bash
|
||
export PGPASSWORD='请填写数据库密码'
|
||
python3 数据处理工作区/04_质量体检/04_字段核验与数据库体检.py \
|
||
--pg-host DB_HOST \
|
||
--pg-port 5432 \
|
||
--pg-database DB_NAME \
|
||
--pg-user DB_USER \
|
||
--pg-table Patient_FrontPages
|
||
unset PGPASSWORD
|
||
```
|
||
|
||
体检会生成:
|
||
|
||
- `数据处理结果区/05_质量体检/患者首页_数据库体检报告.txt`
|
||
- `数据处理结果区/05_质量体检/患者首页_字段空值统计.csv`
|
||
- `数据处理结果区/05_质量体检/患者首页_疑似异常记录.csv`
|
||
|
||
## 输出文件
|
||
|
||
运行后会生成:
|
||
|
||
- `数据处理结果区/01_结构化结果/患者首页_结构化结果.csv`:适合 Excel/WPS 查看的一行一病例总表。
|
||
- `数据处理结果区/01_结构化结果/患者首页_结构化结果.jsonl`:每行一个完整 JSON,适合后续程序继续处理。
|
||
- `数据处理结果区/02_单份JSON/*.json`:每份 PDF 一个完整 JSON,保留嵌套诊断、手术、费用明细和原始文本。
|
||
- `数据处理结果区/03_提取文本/*.txt`:`pdftotext` 抽出的原始文本,用于人工核查。
|
||
- `数据处理结果区/04_复核与人工校正/患者首页_复核清单.csv`:脚本认为需要人工复核的病例。
|
||
- `数据处理结果区/04_复核与人工校正/患者首页_处理失败.csv`:只有处理失败时才会生成。
|
||
- `数据处理结果区/06_PDF图片对照/患者首页_PDF图片对照.html`:PDF 图片与结构化字段的对照复核页。
|
||
- `数据处理结果区/06_PDF图片对照/患者首页_PDF图片对照索引.csv`:图片对照与字段缺项索引。
|
||
|
||
## PostgreSQL 表结构
|
||
|
||
`--write-postgres` 会写入 `public."Patient_FrontPages"` 宽表,不再使用 `payload` 总 JSON 字段,也不写入 `parsed_at/created_at/updated_at`。
|
||
|
||
入库时会同步写入表注释和字段注释,便于在数据库客户端中查看每列含义。
|
||
|
||
网页端会按需把人工复核和抽查记录写入主表 JSONB 列:`review_logs` 记录人工保存时间、修改字段和备注;`audit_logs` 记录抽查来源、结论和备注。历史辅助表 `"Patient_FrontPages_review_logs"`、`"Patient_FrontPages_audit_logs"` 会自动迁移并删除,数据库最终只保留 `"Patient_FrontPages"` 一张业务表。
|
||
|
||
患者号/住院号 `inpatient_no` 是首页与患者列表联动唯一键,也是本程序唯一强制校验条件:不能为空。程序不校验编号格式,同一非空 `inpatient_no` 只保留一条首页记录;迁移时会删除历史重复住院号并保留最新记录,后续重复入库或网页写入会按 `inpatient_no` 覆盖旧首页。若 PDF 文件名和首页病案号可推导,程序仍会自动生成类似 `ZY020001447443` 的默认住院号,后续格式问题交由患者目录核验网页端处理。
|
||
|
||
病案号和首页病案号都按 10 位文本保存,保留前导 0。若 PDF 首页病案号缺前导 0,但文件名可还原,例如 `01447443` -> `0001447443`,脚本会自动修正,并写入:
|
||
|
||
- `inpatient_no`
|
||
- `front_page_medical_record_no`
|
||
- `major_department`
|
||
- `text_extraction_method`
|
||
- `mineru_markdown_dir`
|
||
- `review_status`
|
||
- `review_notes`
|
||
- `auto_corrections`
|
||
- `manual_corrected`
|
||
|
||
`Patient_Lists` 会同步增加 `has_front_page`、`front_page_id`、`front_page_source_file`:凡是患者号非空的首页记录,都会通过 PostgreSQL 触发器自动和 `Patient_Lists.inpatient_no` 关联;如果患者列表没有对应患者号,会由首页表自动补建一条列表记录并标记 `has_front_page = true`,同时写入主要诊断、入院时间和出院时间。空患者号记录会在迁移和入库时被删除,PGSQL 会阻止再次写入空患者号。当首页记录删除,或 `inpatient_no` 改为其他患者号时,触发器会把旧患者号对应的 `has_front_page` 置回 `false` 并清空首页引用。若同一患者号的姓名不一致,以首页表中的非空姓名覆盖 `Patient_Lists.patient_name`,保证患者号、姓名对齐;已有列表记录的诊断和入出院时间不被首页联动覆盖。
|
||
|
||
## 环境要求
|
||
|
||
脚本使用 Python 标准库,不需要安装 pandas/pdfplumber。
|
||
|
||
系统需要有 `pdftotext` 和 `pdftoppm` 命令。Linux 上通常都来自 `poppler-utils`:
|
||
|
||
```bash
|
||
sudo apt-get install poppler-utils
|
||
```
|
||
|
||
`05_备用PDF转Markdown_Mineru.py` 需要 `requests`;只在单独使用 Mineru 客户端时安装即可:
|
||
|
||
```bash
|
||
python3 -m pip install requests
|
||
```
|
||
|
||
Docker 网页端依赖已写入 `数据可视化网页端/Dockerfile`,不再单独维护 `requirements.txt`。
|
||
|
||
## 当前解析范围
|
||
|
||
脚本会抽取:
|
||
|
||
- 基本信息:住院号、病案号、首页病案号、姓名、性别、出生日期、年龄、身份证号、付费方式等。
|
||
- 入出院信息:入院/出院时间、科别、病房、实际住院天数、门急诊诊断。
|
||
- 科室分类:根据 `数据处理工作区/01_配置规则/01_科室分类规则.json` 生成 CSV 的 `大科室` 和 PostgreSQL 的 `major_department`。
|
||
- 诊断信息:`discharge_diagnoses` 出院诊断 JSONB 数组,包含主要诊断、其他诊断、疾病编码、入院病情。
|
||
- 手术操作:编码、日期、名称、原始行内容。
|
||
- 首页质控信息:病理、药物过敏、尸检、血型/Rh、医师、护士、编码员、病案质量、质控日期、离院方式、再住院计划等。
|
||
- 费用信息:总费用、自付金额、各费用明细;若 PDF 首页未填写费用,不强制判为失败。
|
||
|
||
## 建议审核
|
||
|
||
每次运行后先看:
|
||
|
||
```bash
|
||
sed -n '1,20p' 数据处理结果区/04_复核与人工校正/患者首页_复核清单.csv
|
||
```
|
||
|
||
随后打开 `数据处理结果区/06_PDF图片对照/患者首页_PDF图片对照.html`,用 PDF 图片逐项对照病案号、姓名、入出院信息、诊断、手术、质控和费用。遇到新医院、新模板、扫描件或字段错位时,把 PDF、对应 TXT、图片对照索引中的缺项提示留在目录中,再让 Codex 继续补规则。
|