feat(review): 核对包改成医生读得懂;资料库超声一路只留给 agent 的参数

- ceus:灌注指标改为对病灶去暗区(roi_perf)和紫圈(roi_pan)两组算,roi_all 指标删除;
  D1–D4 仍要 roi_all、roi_perf 两条都过才定位(负责人 2026-10-17:医生要正常区与病灶对比看)
- build/library:tic.json 只出两组 11 个指标与 7 个槽位的视频时间;医生截图挪进
  ultrasound/keyframes/key.png,UltrasoundRoute 去掉 key_image、keyframes 多一个 key
- review:TIC参数.csv 取代 TIC结果.csv;问题清单按原因对照表写成大白话,对照表外的原因报错;
  程序原文进 snapshot/问题清单_原文.csv;说明.pdf 整份重写为合作者口吻
- 文档:结构.md、医生核对包、装配两个库、CEUS定量

任务书 04。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 10:22:15 -04:00
parent 77ee03f9a3
commit 7e7f32a13d
19 changed files with 2111 additions and 634 deletions
+35 -10
View File
@@ -1,6 +1,6 @@
# 医生核对包
医生核对包是一个文件夹,交给临床方的医生,请他们核对我们对交付资料的处理结果。医生不用写代码就能打开:表格是 CSV,文字是 PDF,图和视频原样拷贝。本文写给出包的人:什么时候跑、怎么跑、产物在哪、怎么交出去、报错了怎么办。为什么做、包里每个文件的格式,见 `../任务书/03-医生核对包.md`;它在代码里的位置见 `../explanation/结构.md` 第三、四部分。
医生核对包是一个文件夹,交给临床方的医生,请他们核对我们对交付资料的处理结果。医生不用写代码就能打开:表格是 CSV,文字是 PDF,图和视频原样拷贝。本文写给出包的人:什么时候跑、怎么跑、产物在哪、怎么交出去、报错了怎么办。为什么做、包里每个文件的格式,见 `../任务书/03-医生核对包.md` 和改成医生读得懂的 `../任务书/04-核对包改成医生读得懂.md`(两者不一致处以 04 为准);它在代码里的位置见 `../explanation/结构.md` 第三、四部分。
## 先认识几个词
@@ -15,11 +15,13 @@
- **CEUS 定量运行**:跑一次 `scripts/ceus_quant.py`(`CEUS定量.md`),产物在 `runs/ceus/<CEUS运行号>/`。
- **`failed.csv`**:这次运行里记各病例在第几步失败、失败原因的表。
- **视频号**:每例 CEUS 视频的编号,`U` 加三位病例号(如 `U001`),CEUS 运行的结果目录按它命名。
- **TIC、拟合**:TIC(时间-强度曲线)是病灶区域平均亮度随时间的变化。拟合是用一条光滑的模型曲线(Lognormal,对数正态形状)去贴 TIC。拟合要过一道质量门才算成功;没成功时,关键帧 D1–D4 和灌注指标都取不到。
- **TIC、拟合**:TIC(时间-强度曲线)是一块区域平均亮度随时间的变化。拟合是用一条光滑的模型曲线(Lognormal,对数正态形状)去贴 TIC。拟合要过一道质量门才算成功;病灶曲线没成功时关键帧 B0、D1–D4 取不到,某条曲线没成功时它那一组灌注指标为空。
- **TIC 参数**:从过了质量门的拟合曲线算出的 11 个灌注指标(PE、TTP 等),紫圈(胰腺实质)和病灶去暗区各一组,就是资料库 `tic.json` 里给 AI 专家的那份。
- **紫圈**:临床方在视频上画的紫色圈,圈一块正常胰腺作对照,程序也为它画一条 TIC。
- **关键帧、槽位**:从视频里挑出的 7 个时刻的画面,每个时刻叫一个槽位。B0 是刚开始变亮之前,D1–D4 是从拟合曲线上取的开始变亮、变亮最快、最亮、变暗最快,F1、F2 是推注造影剂后第 20、60 秒。细节见包里的 `说明.pdf`。
- **回放视频**:原视频逐帧叠加程序画的病灶轮廓等线条,医生用它看程序圈得对不对。
- **问题清单**:包里的 `问题清单.csv`,列出程序在每个病例上观察到的现象:某例没进资料库、CEUS 在第几步失败、拟合没完成、关键帧没取到、紫圈曲线不可用。每条都抄自某个已有文件里的值,只写现象,不写原因推测和建议。这是负责人 2026-10-17 定的(任务书 03「不做什么」):包只请医生核对事实,推测会把医生的注意力引向我们的猜测。
- **问题清单**:包里的 `问题清单.csv`,列出程序在每个病例上观察到的现象:某例没进资料库、造影视频处理失败、曲线没能拟合、关键帧没取到、紫圈不可用。每条都抄自某个已有文件里的值,只写现象,不写原因推测和建议(负责人 2026-10-17,任务书 03「不做什么」):包只请医生核对事实,推测会把医生的注意力引向我们的猜测。
- **写成医生能懂的话**:程序记录的原因(检查编号、原因码、英文字段名)经 `src/cadx/review/_problems.py` 里的对照表换成一句大白话,同一个原因引起的几条合成一行(任务书 04)。对照表里没有的原因直接报错停下,不把程序原文给医生;程序原文另存在快照的 `问题清单_原文.csv` 里。
- **三种编号**:格式都是 `YYYYMMDD-HHMMSS-<git 短哈希>`,工作区有未提交改动时末尾加 `-dirty`(`装配两个库.md` 第三节「构建号」)。三者各指一样东西,本文用不同的名字区分:
- **构建号**:一次构建,即 `library/<构建号>/`、`answers/<构建号>/`;
- **CEUS 运行号**:一次 CEUS 定量运行,即 `runs/ceus/<CEUS运行号>/`;
@@ -27,15 +29,16 @@
## 一、什么时候跑
医生每交一版新数据,按顺序做完:
医生每交一版新数据,或者处理规则改了,按顺序做完:
1. CEUS 定量 `scripts/ceus_quant.py`,得到新的 `runs/ceus/<CEUS运行号>/`;
2. 把 `config/build.yaml` 的 `ceus_run` 指向这个目录,跑 `scripts/build.py` 构建两个库,得到新的构建号;
3. 再跑本入口出核对包。
1. **干净工作区**:先确认 `git status` 没有任何改动(包括未跟踪文件),有就先提交或请改动的人处理。工作区不干净时三个运行号末尾都会带 `-dirty`,记下的提交号复现不出这次结果;
2. **ceus_quant**:CEUS 定量 `scripts/ceus_quant.py`,得到新的 `runs/ceus/<CEUS运行号>/`;
3. **build**:把 `config/build.yaml` 的 `ceus_run` 指向这个目录,跑 `scripts/build.py` 构建两个库,得到新的构建号;
4. **review_pack**:再跑本入口出核对包。
核对包只读已经构建好的两个库和那次 CEUS 运行,不碰交付包,也不改两个库。所以交付数据或处理规则变了,要先重新构建,再出包。一次构建可以出多次包,每次一个新的出包号。
没装 CEUS 结果的构建(`build.yaml` 的 `ceus_run` 为 null)也能出包。包里没有关键帧、TIC 曲线、TIC 结果和回放视频,病例总表的 CEUS 各列留空,`说明.pdf` 里写明这次没有 CEUS 结果。
没装 CEUS 结果的构建(`build.yaml` 的 `ceus_run` 为 null)也能出包。病例的 `关键帧/` 里只有医生截图,没有程序取的关键帧、TIC 曲线图、TIC 参数和回放视频,病例总表的 CEUS 各列留空,`说明.pdf` 里写明这一版没有造影视频的处理结果。
## 二、怎么跑
@@ -87,8 +90,27 @@ runs/review_pack/<出包号>/ (output_root 下)
- `snapshot.json`:git 状态、Python 版本、`uv.lock` 哈希、开始时间、配置哈希;
- `review_pack.yaml`:配置原文副本;
- `review.json`:构建号、CEUS 运行号、pandoc 与 soffice 的版本行;
- `问题清单_原文.csv`:问题清单的程序原文(检查编号、原因码、程序记的原因),列同包里的问题清单,给我们自己追溯;
- `finished.json`:结束时间、病例数、问题清单行数。
- `医生核对包_<构建号>/`:目录布局、每张 CSV 的列和每个文件的来源,见任务书 03「核对包的内容」。也可以直接打开包里的 `说明.pdf`:它是写给医生的完整说明,包括目录结构、每一列的意思、处理流程、关键帧和 TIC 曲线怎么看、编码含义。这里不重抄,免得两处说法不一致。`说明.pdf` 的源文件是 `src/cadx/review/readme_template.md`。
- `医生核对包_<构建号>/`:
```
说明.pdf 给医生的说明,源文件是 src/cadx/review/readme_template.md
问题清单.csv 病例号、视频号、环节、问题(一句话)
病例总表.csv 全部病例一例一行
标准答案/ 化名对照.csv、诊断.csv、跳过病例.csv、报告复核句.csv(答案库原样拷贝)
病例/<病例号>/ 只有进了资料库的病例才有
临床信息.csv 临床一路的字段
超声报告.pdf、MR报告.pdf 两路报告的描述段原文
关键帧/
医生截图.png 资料库 ultrasound/keyframes/key.png
<槽位>_第<秒>秒.png 程序定位到的关键帧,秒数取 tic.json 的 keyframe_times_s
TIC曲线.png CEUS 运行的 tic.png
TIC参数.csv 11 个灌注指标 × 紫圈、病灶去暗区两组,数值取自资料库 tic.json
回放视频.mp4 CEUS 运行的 overlay.mp4
```
CSV 都是带 BOM 的 UTF-8、中文列名、缺失为空。`TIC参数.csv` 的时间类指标保留 1 位小数、其余 2 位;某一组整组为空时最后加一行「没算出的原因」,原因从 CEUS 运行的 `summary.json` 读,经对照表写成医生的话(资料库里已经没有原因,AI 专家拿到的只是 null)。图片和视频逐字节拷贝。每列的意思和怎么看写在 `说明.pdf` 里,这里不重抄,免得两处说法不一致。
运行目录先写成 `<出包号>.partial/`,全部写完再改名成 `<出包号>/`。看到 `.partial`,说明那次出包中途出错。它不会被自动删除,留着查原因,查完由人决定删不删。已有的运行目录不删、不覆盖(`AGENTS.md`「两档标准」)。
@@ -120,4 +142,7 @@ runs/review_pack/<出包号>/ (output_root 下)
| `… 的 ceus_run 是 …,与资料库记的 CEUS 运行号 … 不符` | 答案库快照里 `build.yaml` 的 `ceus_run`(路径)与资料库 `manifest.json` 的 `ceus_source`(CEUS 运行号)对不上 | 两个库不是同一次构建写出的,检查配置是否指错 |
| `CEUS 运行目录不存在` / `是没跑完的 .partial` / `缺快照` | 构建所用的 CEUS 运行目录被移走或删了 | CEUS 运行目录只追加不删;找回原目录 |
| `CEUS 运行 failed.csv 里的视频号 … 对不上这次构建的任何病例` | 那次 CEUS 运行里失败的病例不在这次构建里,既没进库,也不在跳过清单上 | 检查 `build.yaml` 的 `ceus_run` 与 `delivery_dir`(交付包目录)是否配套,即那次 CEUS 运行是否在这份交付包上跑的 |
| `tic.json 里有 TIC结果.csv 没有中文名的字段` | build 往 `tic.json`(资料库里每例的 CEUS 结果摘要)里加了新字段,核对包还没给它起中文名 | 在 `src/cadx/review/_pack.py` 的 `TIC_ITEMS` 里补上中文名,同时补说明模板 |
| `tic.json 的字段是 …,核对包只认得 …` / `灌注指标分组是 …` / `灌注指标是 …` | build 改了 `tic.json`(资料库里每例给 AI 专家的 CEUS 参数)的字段,核对包还没跟上 | 改 `src/cadx/review/_pack.py` 的 `TIC_GROUPS`、`TIC_METRICS`,同时补说明模板 |
| `… 不在对照表里:…` | 程序记录了一种新的原因(新的检查编号、新的失败原因、新的原因码、新的列),对照表里还没有给医生的写法 | 在 `src/cadx/review/_problems.py` 的对照表里补一句医生能懂的话,并在 `tests/test_review_reasons.py` 补一条手写预期 |
| `给医生的话里出现了程序用语「…」` | 某句给医生的话里带出了检查编号、字段名、下划线、括号或运行号(多半是交付资料里的取值本身带下划线等字符) | 看是哪一句:对照表写法的问题就改写法;是交付取值带出来的,问负责人怎么写 |
| `病灶曲线拟合失败 … 与因此未取到的关键帧 … 对不上` | CEUS 运行的 `summary.json` 里拟合结果和关键帧状态互相矛盾 | CEUS 运行本身有问题,查那次运行,不要改核对包绕过 |