教学课件【简化】流水线
把下载来的商用课件改造成适合自己课堂的版本。底层原子编辑交给官方 pptx 技能,本技能负责决定改什么、改成什么参数、以及怎么验收。
一、简化包含哪些操作,谁说了算
"简化"远不只是删页。按确定性分级——这决定了哪些可以直接做、哪些必须先问:
| # | 操作类别 | 典型实例 | 确定性 | 做法 |
|---|---|---|---|---|
| 1 | 删除答案 | 删「答案与解析」页、删选项旁的答案字母角标 | 高 | 自动化优先:strip_answers.py 扫描 → 核对清单 → 执行 |
| 2 | 优化习题排版 | 字号放大、消截断、消大片空白、配图移位 | 中 | 参数化规则 + 渲染验收(本技能的强项) |
| 3 | 优化字体排版 | 标题与正文字号层级、行距统一 | 中 | 按版式参数表执行,改动前给出参数建议 |
| 4 | 删除习题 | 删掉某几道不讲的题 | 低 | 必须用户指定,列清单确认 |
| 5 | 增加习题 | 从其他资料补题进来 | 低 | 必须用户提供题面/图片,列清单确认 |
| 6 | 调整顺序 | 把视频页挪到知识点后、章节重排 | 低 | 必须用户指定目标位置,列新顺序确认 |
| 7 | 更换资源 | 换视频、换封面、换配图 | 低 | 必须用户提供新素材,确认后替换 |
| 8 | 删页 / 合并页 | 删教学目标页、把松散的 5、6 页并成一页 | 低 | 必须用户确认,列"删哪页、为什么"清单 |
> 核心纪律:涉及教学意图的判断(删什么、留什么、怎么排)一律不由你决定。
> 你的职责是发现候选(哪几页像是答案页、哪几页明显同属一个知识点可以合并)、
> 说清影响(删掉后页码如何变化、哪些引用会受影响)、然后等用户拍板。
> 唯一可以自动执行的是第 1 类(删答案)——它由规则而非教学意图决定。
二、铁律
- 先探查后动手:任何改动前先跑
probe_pages.py拿到真实结构(元素 id、坐标、字号、行距、文本长度)。坐标一律以pptx.sh query的返回为准。 - 改页面前先出清单:所有删页、合并、重排、增删习题、换资源的动作,先把清单交用户确认;用户没回话就不动。
- 原子编辑只用官方工具:文字与格式用
edit-text,位置尺寸用move-shape/resize-shape,删元素用delete-shape。禁止 python-pptx 原生add_textbox/add_shape。 - 翻页级操作禁用工具链 copy:
slide-organize的copy实测不可靠(副本会跑到末尾并让后续move全部错位)。插入/复制页面一律用insert_pages.py(delete/move仍可靠)。 - 遇到「shape_id 不存在」先展平:含内联公式的题目文本框常被包在
mc:AlternateContent里。先跑flatten_ac.py。 - 放大字号必须同步公式字号:
m:oMath内是m:r不是a:r。用apply_layout.py的sz参数一并改。 - 改完必须审计:静态审计 + 版式审计 + 渲染目视,三道都要过。只通过 XML 校验不算完成。
放大了字号或动了图形位置的,另加图文重叠像素检查与内容零改动校验两道(见第三段)。 - 产物写入工作区,源课件全程只读;改写前先把上一版另存为备份。
- 宁可报错,不可静默降级:解析层(页序、关系、坐标)遇到任何不一致,必须明确报错(退出码 2 + 中文说明),绝不允许返回空表/空结果让上层误判为「没有问题」。一个「看起来合格、实际什么都没检查」的报告,比一次崩溃危险得多。
- 不打扰用户的 WPS:涉及 WPS 会话的脚本(
audit_layout/render_check)统一走_common.wps_session()——优先附着既有实例(不 Quit),只在自建实例时才 Quit;打开文件前先确认该文件未被 WPS 占用,占用则拒绝而不是硬开。 - 画布尺寸动态读取:不得硬编码 19.05 cm。从
pres.PageSetup.SlideWidth/SlideHeight读真实画布,阈值随之换算。 - 扫描器不得漏形状:收集文本框一律用
_common.walk_shapes(tree),它同时递归p:grpSp组合形状与mc:AlternateContent兼容块。只遍历spTree直接子元素会把这两类容器整体跳过,造成“静默漏报”(实测曾漏掉一套课件 17 页的全部答案)。 - “零命中”必须被验证:扫描器报 0 处时,不能默认“真的干净”。至少用一套已知含答案的样本做正对照,确认它确实能报出来;否定结论比肯定结论更容易错。
- 不得把题目一起删掉:同页既有题干又有答案时(培优课件常见),一律降为中置信度,改用段落级删除,不得整页删除。
- 判定必须落到数字上:图文是否重叠、文字是否超界、内容是否被改坏,一律以脚本的客观输出为准。
AI 视觉模型与人眼目视只能当线索,不能当依据——本类任务实测中视觉模型对同一页同时出现过
假阳性(说重叠,像素交叠实为 0)与假阴性(说没问题,实际超界)。
三、标准工作流(三段式)
第一段 · 确定性自动化(可直接做,做完报告)
这三件事不需要用户决策,做完把结果报给用户即可:
1.1 结构探查
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/probe_pages.py" 工作副本.pptx 1-29
拿到每页的元素清单、页码↔文件号映射、字号、行距、文本长度。注意页面顺序由 p:sldIdLst 决定,按文件名序号读会误判。
> 所有脚本都先经 open_deck() 做三段页序校验(sldIdLst 条数 = 解析页数 = 包内 slide 部件数),
> 不一致直接报错退出,不会给出“0 页 / 未发现问题”的假合格报告。遇到报错先查 references/trap-list.md 第六节。
1.2 删答案(优先做)
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/strip_answers.py" 工作副本.pptx
自动识别:整页的「答案 / 解析 / 参考答案 / 详解 / 点拨」页、题目页上遗留的答案字母角标(红色单字母 run 等)。输出候选清单 + 置信度 + 证据,以及可直接执行的删除指令。
识别规则与判定标准见 references/answer-removal.md。
高置信度项经用户扫一眼确认后即可执行;中低置信度项必须逐条确认。
> ⚠ 两类必须当心的判定:
> · 混合页(同页既有题干又有 【详解】)→ 脚本会降为 MEDIUM,
> 并在 B 类里定位到具体的答案段落(shape_id + 段号),删段不删页。
> · 藏在容器里的文本框——组合形状(p:grpSp)或兼容块(mc:AlternateContent)——
> 脚本会照常扫到,并且在理由里标注“需先取消组合 / 先展开”。
1.3 版式体检
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/audit_layout.py" 工作副本.pptx
输出每页每个文本框的「实测所需高度 / 当前框高 / 内容底边」,标出超页溢出(OVERFLOW)、超阈值(TIGHT)、正文起始过高(TOP)。
第二段 · 需确认的决策(列清单 → 用户拍板 → 才执行)
把下面几类候选一次列清交给用户,等回复后再动手:
- 建议删除的页:页码 + 该页标题/首句 + 删除理由(如"教学目标页")
- 建议合并的页:哪几页 + 合并后的排布设想(如"5、6 页同属加速度定义,可并成一页")
- 建议调整的顺序:原位置 → 目标位置
- 建议增删的习题:题号 + 所在页 + 理由
- 需要更换的资源:当前素材 + 期望素材(并提示用户提供新文件)
清单要带上页码变化预览(删 3 页后,原第 8 页变成第 5 页),避免后续沟通错页。
执行顺序建议:先删后合再排——先删掉不要的页,再合并松散页,最后调整顺序,可以减少页码反复变动。
第三段 · 版式整形(参数化执行)
做法见 references/layout-rules.md。
如果目标是"在放得下的前提下把字号尽量放大",不要手工二分试探,直接用求解器:
# ① 一键求解每页的最优「字号 + 行距」(内部双点标定 + 闭环复核)
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/solve_layout.py" 基线.pptx \
--pages 8,13,19 --sizes 42,40,38,36,32 --spec-out spec.txt
# ② 应用;③ 体检;④ 像素级确认;⑤ 内容没被改坏的证明
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/apply_layout.py" 基线.pptx 成品.pptx "$(cat spec.txt)"
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/audit_layout.py" 成品.pptx
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/check_overlap.py" 成品.pptx --pages 15,22
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/diff_text.py" 基线.pptx 成品.pptx
只改单页、参数已明确时,才走手工四步:
- 体检:
audit_layout.py定位溢出页。 - 定参:
目标行距 = 基准行距 × 目标高度 ÷ 基准实测高度。 - 应用:
apply_layout.py批量写入行距、位置、尺寸、字号。 - 复测:再跑
audit_layout.py,确认所有页面底边 ≤ 18.5 cm。
> 课件里的行距多数是继承来的 1.5 倍百分比行距,它比看起来高得多(40pt 字实际占 60pt 行高以上)。这是"题目显示不全"的头号原因。
让配图给文字让位时,不要按文本框外接框盲目大幅移图——外接框宽度常远大于文字实际占用宽度。
先用 audit_layout.py 的外接框相交预检做粗判,再用 check_overlap.py 的实际文字像素右边界
只补足差额(详见 references/layout-rules.md 第 6.1 节)。
若文字已排满整页宽、图无平移空间,改走"左文右图分栏",并遵守联合求解铁律:
| 路径 | 适用 | 代价 |
|---|---|---|
| 收窄文字框宽度 | 图在右侧、文字未用满页宽 | 行数变多、垂直变高 |
| 缩放图片 | 图右边界已顶到页右(无法平移) | 图变小 |
| 降字号 | 前两者仍不够 | 字变小(与目标相搏) |
> ⚠️ 收窄宽度必须同步验算垂直方向:正确做法是先定几何(文字框宽 + 图片位置尺寸),
> 再跑 solve_layout.py 求该几何下的最大可行字号。只改宽度会立刻把"横向压图"
> 变成"纵向溢出页面"——本次第 15、22 页最初只收窄宽度,文字底边马上窜到 18.88 / 19.03 cm。
>
> 最终解(同类习题页可参考):文字框收窄至 26.6~27.0 cm、图片缩到约 5.9×4.2 cm 置右侧,
> 第 15 页 34pt/53.3pt、第 22 页 36pt/48.3pt,含图 5 页全部零交叠、最小间隙 0.49 cm。
第四段 · 最终审计(必做,缺一不可)
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/audit_deck.py" 成品.pptx # 静态审计
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/audit_layout.py" 成品.pptx # 版式审计(含图文外接框预检)
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/render_check.py" 成品.pptx render/ # 视觉审计
以下两道按任务类型追加:
# 动过字号/行距/图形位置 → 像素级确认没有压图
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/check_overlap.py" 成品.pptx --pages 15,22
# 任何内容侧改动(删答案、删页、展平)→ 证明"只动了该动的"
python "$SKILL_PATH_BASH/ppt-simplifier/scripts/diff_text.py" 改动前.pptx 成品.pptx
五个脚本各司其职,缺一道就可能漏事故:
| 脚本 | 回答的问题 | 出事的典型表现 |
|---|---|---|
solve_layout.py |
字号行距该定多少 | 手工迭代十几轮 |
audit_layout.py |
放得下吗 / 改了哪些 | 文字超出底边被切 |
check_overlap.py |
压住图了吗 | 正文压住配图 |
diff_text.py |
内容动了吗 | 展平/删答案吃掉了公式 |
render_check.py |
观感对不对 | 版式合规但看着别扭 |
逐项过完再交付,清单见下方「六、最终审计清单」。
四、版式参数速查
| 参数 | 取值 | 说明 |
|---|---|---|
| 画布尺寸 | 33.87 × 19.05 cm | 人教版课件常见 13.33in×7.5in;每 cm = 360000 EMU |
| 正文起始 y | 2.75 cm | 标题(y≈0.71,高≈2.2)与分隔线(y≈2.08)之下 |
| 正文可用底边 | ≤ 18.5 cm | 超过 19.05 的内容在渲染时被裁掉 |
| 正文推荐宽度 | 32.6 cm(单栏满宽)/ 22–26 cm(左文右图) | 与配图分列时右边界与图片左边界留 ≥0.3 cm |
| 习题字号档 | 40 / 36 / 32 pt | 下限 32pt;题量少用 40,题量多用 32 |
| 标题字号 | 36 pt | 与正文保持层级不倒挂 |
| 底部留白 | ≤ 15% 页高 | 超过就加大行距铺满 |
| 行距换算 | h(L) = n×L + c;双点标定解 n、c 后任意 L 都能算 |
固定行距下内容高度与行距成正比;百分比行距不可线性外推 |
| 图文间隙 | ≥ 0.3 cm | 正文右边界与图片实际内容左边界之间(不是外接框) |
五、默认简化动作(建议清单,不是免确认清单)
这些是用户长期确立的偏好,作为默认建议提出——每次仍要把"本次实际命中的页"列出来让用户过目,不要机械套用(不同课件结构不同,套错会删掉要用的页):
- 「教学目标」「教学重难点」页 —— 建议删;
- 「课堂导入」第 2 页、「探究新知——思考与讨论」的第一页 —— 建议删;
- 所有题目的「答案 + 解析」页 —— 可自动删(属第 1 类,按扫描结果执行);
- 题目页上遗留的答案字母(如 B、A、C 角标)—— 可自动删;
- 某页被移动到其他位置后,标题要同步改成契合新语义的名称(如「课堂导入」→「探究与思考」)—— 属结构调整,随移动一并做掉。
版式类默认要求(可直接执行):
- 习题页字号不小于 32pt,可用 36 / 38 / 40;
- 习题页不得出现大片空白,也不得出现超页截断——先保证完整显示,再追求铺满。
六、最终审计清单
6.1 静态审计(audit_deck.py)
- [ ] 页数与预期一致,页序与用户确认的一致
- [ ] 所有 XML 可解析,无悬空关系引用
- [ ] 答案残留:无「答案/解析」页、无遗留答案字母
- [ ] 习题序号连续:1./2./3.… 无重号、无跳号
- [ ] 公式对象、视频、图片等关系完整(无丢素材)
6.2 版式审计(audit_layout.py)
- [ ] 无任何文本框内容底边超过 19.05 cm(超页截断)
- [ ] 各页内容底边 ≤ 18.5 cm
- [ ] 无正文起始过高(顶部大片留白)
- [ ] 底部留白 ≤ 页高 15%
6.2b 图文像素审计(check_overlap.py,动过字号/图形时必做)
- [ ] 所有相关页
交叠 0 像素(= 文字没有压住图片任何实际内容) - [ ] 最小图文间隙 ≥ 0.3 cm(外接框层面的相交预警不等同于真压住,以像素结果为准)
- [ ] 显示为
可见文字 < 真实文字的页必须处理(有字被图遮住,见 PRESS/OCCLUDED)
> ⚠️ 若测出的"文字右边界"永远紧贴图片左边界、且图片一移该边界同步移动,
> 说明测到的是图片边界而非文字,旧的两版差分法已失效——本脚本已改四版法,
> 但若自行写差分脚本,真实文字掩膜必须是 D(删文字+删图片)− C(删图片)。
6.2c 内容零改动校验(diff_text.py,有任何内容侧改动时必做)
- [ ] 逐形状比对结果为「内容零改动」,或所有差异都能在
--ignore里逐条对应到有意删除 - [ ] 公式(
m:oMath)一并比对过,没有只比a:t造成的漏报
6.3 视觉审计(render_check.py 出图后逐页看)
- [ ] 每道题的 A/B/C/D 四个选项齐全,没有整条缺失
- [ ] 没有行尾缺字、半截句子
- [ ] 正文与配图不重叠,配图未超出页面
- [ ] 字号观感统一,相邻页不跳档
三道全过才交付;任何一项不过,回到对应步骤修,修完重跑审计。
七、归档规则
| 类型 | 云盘位置 | 命名 |
|---|---|---|
| 下载原版 | 教学工作文件/物理课件/下载原版/{册}/{章}/{节} |
保持原始文件名不动 |
| 【简化】成品 | 我的课件/{册}/{章} |
原名 +【简化】或【极简】后缀 |
云盘不提供删除能力,需要删除的文件一律用 drive move-file 转入根目录「待删除」(file_id: mFR6YgKmo1M7V9CEE3sAxxYJyULNc54YW)。云端替换先征得用户同意。
八、脚本索引
| 脚本 | 用途 |
|---|---|
scripts/probe_pages.py |
探查页面结构:元素 id、坐标、字号、行距、文本长度、页序映射、完整性校验 |
scripts/strip_answers.py |
自动识别答案页与答案角标,输出候选清单(含置信度与证据)及可执行删除指令 |
scripts/audit_deck.py |
最终静态审计:页序、完整性、答案残留、习题序号连续性 |
scripts/audit_layout.py |
版式体检:WPS 实测文本框所需高度,标出溢出/贴顶/留白异常;内置图文外接框相交预检与 --baseline 基线对照(列出所有排版参数变化) |
scripts/solve_layout.py |
自动求解每页最优「字号 + 行距」:双点标定解出等效行数与内边距,按可行条件取最大字号,自带闭环复核 |
scripts/check_overlap.py |
图文重叠的像素级判定:四版渲染法掩膜(真实文字 = D−C),给出交叠像素数与最小图文间隙(PRESS/OCCLUDED/NEAR/OVERWIDE/INSIDE/OK) |
scripts/diff_text.py |
内容零改动校验:逐形状比对文本(含 m:t 公式),支持 --map 页码映射与 --ignore 有意删除 |
scripts/render_check.py |
WPS 逐页导出 PNG,供目视核对 |
scripts/apply_layout.py |
批量改写行距 / 位置 / 尺寸 / 字号(含内联公式字号) |
scripts/flatten_ac.py |
展开 mc:AlternateContent,让工具链能看见其中的形状 |
scripts/insert_pages.py |
ZIP 层确定性插入/复制页面 |
scripts/_common.py |
公共底座:DeckError、decode_xml(宽容解码)、slide_order(lxml 解析 + 三段交叉校验)、open_deck(强制前置)、walk_shapes(递归取形状,不放过组合/兼容块)、parse_pages(on_warn)、parse_layout_spec、wps_session / wps_open(会话安全)、run_guarded(统一错误出口) |
全部脚本都是纯参数化的:只接受文件路径与参数,输出文本或文件,不修改源课件。
公共错误契约
- 成功:按需输出结果(文本 / JSON / 文件)。
- 输入有问题(文件不存在、非 zip、页序不一致、页码越界且无可处理项、位置越界):退出码 2 + 一行中文说明。
- 检查发现业务问题(如答案残留、版式溢出):退出码 1 + 问题清单(这不是错误,是审计结果)。
- 任何情况下都不向用户抛 Python traceback。