Files
CADx-4/research-wiki/任务书/03-医生核对包.md
T
iomgaa 14d6f8e153 docs: 任务书 03 医生核对包;TIC 拟合约束文献核查记录
来源:负责人 2026-10-17 要求把 29 例处理结果整理成医生能看的格式并做成长期入口(表格 CSV、文字 PDF、视频不压缩、不向医生提问、问题清单只写现象);文献核查为负责人要求的质量门依据核对,结论待医生看过后再定。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 05:09:34 -04:00

12 KiB
Raw Blame History

任务书 03:医生核对包

目标

把一次构建(library/ + answers/)和它装入的那次 CEUS 运行,整理成医生不用写代码就能看懂的一个文件夹:表格一律 CSV,文字一律 PDF,图和视频原样。负责人把文件夹打成压缩包、用 U 盘拷给医生,请医生核对我们的处理结果。

这是一项长期功能:以后医生每交一版数据,跑完 ceus_quant 和 build,再跑一次本入口,就得到新的核对包。所以按正式模块写,带测试和 guide,不写成一次性脚本。

来源:负责人 2026-10-17「我们把处理完的结果……整理一份給医生看看」「不需要问医生问题」「文本文件尽可能 pdf,表格尽可能 csv」「需要作为一项长期的功能……有一个入口能执行这个」;视频不压缩(「本来视频就模糊,你压缩不是更模糊」);病例目录用医生的病例号、问题清单只写现象、没进库的病例只在表里出现(负责人 2026-10-17 认可)。

不做什么

  • 不向医生提问,不做反馈表。
  • 问题清单只写程序观察到的现象,不写原因推测、不写我们查过的文献、不写建议。
  • 不改 CEUS 算法、不改质量门、不改资料库的内容。质量门的去留等医生看过之后再定(文献核查记录在 research-wiki/scratch/2026-10-17-TIC拟合约束文献核查/,本任务不用读)。
  • 不压缩视频,不缩放、不重新编码任何图片和视频。

核对包的内容

runs/review_pack/<运行号>/
  snapshot/                        快照(不给医生,打包时由负责人去掉;见下文)
  医生核对包_<构建号>/              负责人整个打包的就是这个目录
    说明.pdf
    问题清单.csv
    病例总表.csv
    标准答案/
      化名对照.csv
      诊断.csv
      跳过病例.csv
      报告复核句.csv
    病例/
      <病例号>/                    只有进了资料库的病例,目录名用医生的病例号(如 P001)
        临床信息.csv
        超声报告.pdf
        MR报告.pdf
        关键图.png
        关键帧/<槽位>_第<秒>秒.png  例如 B0_第1.6秒.png;秒数保留一位小数;没定位的槽位没有文件
        TIC曲线.png
        TIC结果.csv
        回放视频.mp4

逐项要求:

  • CSV:UTF-8 带 BOM(Excel 双击打开中文不乱码),列名用中文。缺失值留空,不写 null、NaN。
  • 病例总表.csv:这次构建涉及的全部病例一例一行(进库的加跳过的;40 例交付包就是 40 行),按病例号排序。列:病例号、视频号、化名(没进库的留空)、是否进入资料库、没进的原因(检查编号和说明)、CEUS 定量是否成功、CEUS 失败在第几步、7 个槽位各一列(取到写视频时间秒数,没取到写「未取到」,CEUS 失败或没装 CEUS 时留空)。
  • 问题清单.csv:列为病例号、视频号、环节、问题。按病例号排序,一个病例可以多行。来源和写法见下文「问题清单的来源」。
  • 标准答案/:答案库的 4 张表照原样转成上面的 CSV 规格,列名不改。诊断编码和其他编码列照原值写;说明文件里写明编码含义(诊断 1 IPMN、2 SPN、3 MCN、4 SCN,出自交付包表头;其他编码列写「未解码」,解码开关见 build.yaml)。
  • 临床信息.csv:资料库临床一路的字段,一行;列名用交付包原列名。
  • 超声报告.pdf、MR报告.pdf:资料库里的报告原文(就是 AI 专家看到的那段,结论段已被程序去掉),PDF 第一行写「病例号 Pxxx 超声描述(结论段已去除)」之类的标题,正文照抄不改字。
  • 关键图.png、关键帧/:从资料库拷贝(已去附加数据的那份),逐字节不变,只改文件名。
  • TIC曲线.png、回放视频.mp4:从 CEUS 运行目录逐字节拷贝。
  • TIC结果.csv:把资料库的 tic.json 摊平成「项目、值」两列的长表:四条曲线各自的拟合是否成功和 R²、灌注指标逐项、紫圈曲线是否可用、7 个槽位的状态与时间或原因。项目名用中文加原字段名,例如「病灶整体曲线 拟合成功(roi_all.success)」。
  • 没装 CEUS 结果的构建(ceus_run 为 null)也能出包:没有关键帧、TIC 曲线、TIC 结果、回放视频,病例总表里 CEUS 各列留空,说明文件写明这次没有 CEUS 结果。

问题清单的来源

每条都能追到某个已有文件里的某个值,不另做判断:

环节 来源 写法
装配资料库 答案库的跳过清单 检查说明 + 涉及的文件、列和值,原样写
CEUS 第 N 步 CEUS 运行的 failed.csv 「第 N 步失败:」+ 原因原文
TIC 拟合 tic.json 里病灶整体、病灶去暗区两条曲线 success 为 false 「病灶整体曲线未完成拟合」(去暗区同理);原因码(如 parameter_on_boundary)照写在括号里,并在说明文件里逐个解释每个原因码的意思
关键帧 tic.json 里没定位的槽位 「B0 未取到:」+ reason 原文
紫圈 pan_curve_usable 为 false 「紫圈曲线不可用」

报告复核句(标准答案/报告复核句.csv)不进问题清单,单独成表。

说明.pdf

源文件是仓库里的一份版本化 Markdown 模板(放在 src/cadx/review/ 下,随代码走),出包时填入这次的构建号、CEUS 运行号、病例计数,再转成 PDF。至少写清:

  1. 这个包是什么、从哪次交付数据处理来(构建号、CEUS 运行号、生成日期);包里含患者资料,只在临床方与我们之间传递。
  2. 目录结构,每个文件是什么。
  3. 每张 CSV 每一列的意思。
  4. 我们的处理流程,用医生能懂的话分步讲(读交付包和检查 → CEUS 的第 1–9 步各做什么 → 装进资料库),问题清单里「环节」一列的每种取值对应哪一步。
  5. 7 个关键帧各代表什么时刻、怎么取(B0、D1–D4 来自拟合曲线,F1、F2 按推注时间取),以及「未取到」的几种原因。
  6. TIC 曲线图怎么看:每条线是什么(图上标注是英文,在这里逐个对照成中文)、竖线是什么。
  7. 化名是什么、为什么有;报告里的结论段为什么被去掉(AI 专家不能看到医生的诊断倾向);资料库只放「所见」。
  8. 编码列的含义(诊断编码,以及「未解码」的列)。
  9. 跳过病例为什么整例跳过、每例只记第一项没过的检查。

转换工具:pandoc 把 Markdown 转成 docx,再用 soffice --headless --convert-to pdf 转 PDF(本机都有,中文字体用已装的 Noto CJK)。报告 PDF 用同一条路。两个工具的版本记进快照。工具缺失直接报错。

怎么实现

模块

新建组织层模块 review(src/cadx/review/),藏住「核对包长什么样」这个决定:目录布局、每个文件的格式、问题清单的来源与写法、说明模板。

  • 依赖:library(按化名读出各路)、answers(读 4 张表)、runs(读快照、读 CEUS 运行,见下)。不依赖 build、delivery、ceus。
  • 它读的是已经构建好的 library/ 和 answers/,不碰交付包。病例总表里的 40 例 = 答案库的化名对照 + 跳过清单。
  • 只有 library 能引用 PIL:review 拷图片只按字节拷,不打开图片。

CEUS 运行目录的读取挪进 runs。 现在 build 的 _ceus.py 自己读 runs/ceus/<运行号>/ 的布局(failed.csv、summary.json、关键帧),review 也要读。按 结构.md 第三部分「出现第二个使用者再收进模块」,把读 CEUS 运行目录(打开运行、读 failed.csv、按视频号找结果目录和其中的文件)收进 runs,build 和 review 都经 runs 读。tic.json 挑哪些字段仍只在 build 里列(可见性的唯一决定处不动)。挪完 build 的行为不变,原有测试照过。

入口

scripts/review_pack.py --config config/review_pack.yaml。配置(字段定义在 review,全部必填):

  • library_dir、answers_dir:某次构建的资料库和答案库目录,两者目录名(构建号)必须相同,不同就报错;
  • output_root:runs/review_pack。

CEUS 运行从资料库 manifest.json 的 CEUS 来源字段读,不另配。

运行目录先写 .partial,跑完改名,已存在报错(规则同前两份任务书)。快照记 git 状态、配置原文、构建号、CEUS 运行号、pandoc 和 soffice 版本。快照放在 医生核对包_<构建号>/ 外面,负责人只打包里面那个目录。

终端只打印计数:病例数、问题清单行数(按环节分)、PDF 份数、拷贝的视频总大小、耗时。不打印病例号。

规模

部分 预期行数
review(含说明模板以外的代码) 300–500
scripts/review_pack.py ≤ 80
runs 增量(读 CEUS 运行) ≤ 150,build 相应减少

测试

预期值照本任务书写,不从实现里推。用现有的假交付包和假 CEUS 运行(tests/fake_delivery.py、tests/fake_ceus_run.py)构建一次,再出包:

  • 目录结构与上面一致;进库病例每例一个目录、名为病例号;跳过的病例没有目录、在病例总表和问题清单里有。
  • 每张 CSV 以 BOM 开头、列名与本任务书一致、缺失值为空串。
  • 问题清单:每种来源至少各造一例,断言行数和「环节」「问题」原文。
  • 关键图、关键帧、TIC 曲线、回放视频与源文件逐字节相同;关键帧文件名的秒数等于 tic.json 里的 video_time_s 保留一位小数。
  • TIC结果.csv 的值与 tic.json 逐项相同。
  • ceus_run 为 null 的构建也能出包,CEUS 相关文件都不存在。
  • 资料库与答案库构建号不同时报错。
  • 说明和报告 PDF 生成成功、非空(这条依赖 pandoc 和 soffice,照常进 make check;如果让 make check 多出 30 秒以上,在报告里写明耗时,不自行加标记跳过)。
  • build 原有测试全部照过(CEUS 运行读取挪进 runs 之后)。

真跑

用当前真实构建 20261016-094248-1de88a5-dirty 出一次包。报告:运行号、病例数、问题清单按环节分的行数、包的总大小、耗时;挑 1 个病例目录和 说明.pdf 的路径供负责人目视检查。不在报告里写病例号以外的任何病例内容。

文档

  • 新写 research-wiki/guides/医生核对包.md:什么时候跑、怎么跑、产物在哪、打包前去掉 snapshot/。过一轮「硕士生阅读」。
  • 结构.md:第三部分加 review(组织层,可依赖 library、answers、runs),依赖表和 import-linter 契约同步;第四部分加核对包一节(指向本任务书和 guide,不抄布局);第五部分配置表加 review_pack.yaml;第六部分加规模;第八部分加对外接口。
  • WORK_LOG.md。

审阅

「其余部分」那一档,写完派一个全新上下文的子 Agent 审一轮:只给本任务书、结构.md 第三到第五部分和 diff。重点:问题清单有没有漏掉某个来源、有没有写进推测性的话;拷贝是否逐字节;CEUS 运行读取挪进 runs 后 build 行为是否不变;review 有没有写进 library/ 或 answers/(不许)。Codex 连不上就跳过。

报告

  1. 提交号;各部分行数。
  2. make check 完整输出。
  3. 真跑结果(见上)。
  4. 审阅意见和处理。
  5. 和本任务书、结构.md、AGENTS.md 不一致的地方,以及为什么。