行业培训 PPT 生成器(FY27 升学规划模板 · 五板块 60 页)
输入一个行业/产业名词(如"低空经济"),产出一份面向有经验志愿规划师的培训 PPT:
产业深度但不写成纯研报,全程串政策、城市、专业岗位,直接可在咨询中使用。
安装与环境(拿到本技能先做这三步)
- 放到技能目录:
unzip industry-training-ppt.zip -d ~/.workbuddy/skills/
→ 得到~/.workbuddy/skills/industry-training-ppt/(下文记作$SKILL)。 - 装依赖:
pip install -r requirements.txt
- 必需:python-pptx(PPT 读写)、Pillow(图片预裁);建议 Python 3.9+。
- 可选:playwright+ 本机 Chrome —— 渲染级质检与抓图要用,不装也能出 PPT,但少一道关键质检。
- skillHub 发布版:模板是二进制文件、上传通道不收,故随包以 base64 分片
存放(assets/template/FY27_template.b64/;发布副本的背景图已重采样到
1920px 宽以压进 10MB 上传限制,文字/母版/几何零改动)。装完先跑一次
python scripts/restore_template.py一键还原(check_env.py 检测到模板
缺失时也会自动触发还原)。 - 自检:
python scripts/check_env.py --fix-hint,必需项全 ✅ 再开工。检查四项:
依赖 / 模板(assets/template/FY27_template.pptx,须 5 页样例页 + 13.333×7.5in)/ 本机 Chrome / 微软雅黑字体。
- 模板是版式保真的底版,缺失则无法生成;
- 全篇强制微软雅黑,Windows 自带,macOS / Linux 需自行安装(装过 Microsoft Office 的 Mac 通常已有);
字体缺失会让容量引擎(按微软雅黑字宽估算)全部失效,务必确认。
脚本清单(scripts/)
| 脚本 | 作用 | 依赖 |
|---|---|---|
build_pptx.py |
outline.json → .pptx(10 种版式渲染 + 容量引擎) | pptx, Pillow |
check_pptx.py |
字号/溢出估算级体检 | pptx |
shot_pptx.py |
渲染截图 + --check 渲染级重叠检测 |
pptx, playwright, Chrome |
check_lines.py |
逐字符量真实行盒,报提前换行/孤字尾行 | playwright, Chrome |
fit_columns.py |
文字柱与配图等高后处理(--apply) |
playwright, Chrome |
fetch_images.py |
按关键词抓图去重 | playwright, Chrome, Pillow |
diff_pptx.py |
对比两版 pptx 学到用户改版标准 | pptx |
compare_decks.py |
回归基准:重跑件 vs 已交付册,七维度查是否变形 | pptx |
package_skill.py |
把本技能打成可分发的 zip(排除垃圾文件、保真不重编码) | stdlib |
check_env.py |
开工前环境自检 | stdlib |
restore_template.py |
从随包 base64 分片还原模板 pptx(md5 校验) | stdlib |
- 格式:.pptx,基于
assets/template/FY27_template.pptx(FY27 培训师共创会·升学规划场模板)复制样例页生成,只改文字与插图,不动母版与底图。 - 模板页型:封面 / 目录(恰好 5 项,白字加粗)/ 篇章页(54pt 标题+96pt 序号)/ 主题页 / 封底。
- 样式约定(用户 2026-09-23 手工精修 2.0 版后定稿 v7,全部实测自用户文件):
- 全篇字体统一微软雅黑;
- 内容页主标题:左上角 32pt 加粗藏青 #0F1E64,左侧小色块与标题文字垂直居中对齐;
- 字号整体放大(v7 核心改动,见下表);
- 重点高亮:outline 文本中用
**重点**标记,渲染为橙色 #F55F0A 加粗; - 页内只放产业内容,规划师解读写该页
notes备注(每页必填)。
v7 字号表(用户 2.0 版实测,脚本常量已固化,勿再下调)
| 位置 | v4 | v7 |
|---|---|---|
| 内容页主标题 | 32 | 32 |
| text-image 【小标题】 | 24 | 32(正文超容时整块降 24) |
| text-image 正文 | 22 | 28(超容自动降 24) |
| image-points / numbered-full 编号 | 26 | 28(橙) |
| image-points / numbered-full 块标题 | 24 | 28(藏青加粗) |
| image-points / numbered-full 正文 | 22 | 24 |
| cards3 卡标题 / 正文 | 22 / 20 | 28 / 28(短文)→ 24(长文) |
| grid4 块标题 / 正文 | 20 / 20 | 32 / 28(装不下自动降 24) |
| stat-cards 大数字 | 28–40 | 32–44 自适应;注脚 18→24(加粗居中) |
| compare 栏标题/维度/数值 | 26/20/24 | 全部 32;VS 圆字 32→40→再回 32(见下方注),底部结论 24 |
| stages3 阶段标签 / 头标题 | 18 / 22 | 28 / 32;卡内正文 24 |
| quadrant 徽标+标题 / 正文 | 44/22 / 18 | 28 / 24 |
| cards2x2 卡标题 / 正文 | 22 / 20 | 28 / 24;徽章数字 24 |
| 目录项 | 32 | 40 |
| 封面主标题 | 72 | 80(左 1.32in、宽 10.69in,副标题下移 0.2in) |
| 图注 caption | 14 | 14(唯一保持小字) |
> 注(2026-10-15 实机校正):VS / 对比圆里的字实际渲染是 32pt,不是 40pt。
> v7 曾把常量提到 VS_SZ = 40,但 v8.7 起 compare 恒走无图分支、圆直径缩到 1.10in,
> 40pt 塞不进 1.10in 的圆,render_compare 里已写死 sz=32(VS_SZ 常量停用)。
> 别照字号表的"40"去反推旧稿,也不要调回 40——1.9in 老圆会压住左列 70×75px(见 v8.7 §4)。
v7 版面几何(用户 2.0 版实测)
- 撑满原则(最重要):内容区尽量占满版面——文本框左缘 0.45in(对齐标题色块左线)、
右缘 12.75in;内容区纵向 1.40–6.85in(v4 是 1.55 起,用户整体又上移了)。 - 卡片类图形(cards2x2 / stages3)左缘保持 0.85in,但加宽到 12.75 右缘。
- 卡片尽量加宽、间隙收窄:cards3 卡宽 3.90(间隙 0.30);stat-cards 卡宽 2.88(间隙仅 0.10)。
- 配图尽量放大:text-image 右图 4.6×4.7in;image-points 左图 5.3×4.6in;grid4 中心图 3.6×4.3in。
- grid4 / numbered-full 即使没有中心图也要配图;grid4 无图时四块自动拉成满幅 2×2。
v7.1 容量引擎(2026-09-23 下午,重叠返修后确立——本 skill 的核心排版能力)
字号不是写死的,是"容器装得下的最大档"。 所有文本区按此流程定字号:
- 先扣文本框内边距:左右各 0.1in、上下各 0.05in(
PAD_X/PAD_Y)。任何容量计算
都必须先扣(此前所有重叠/露底的根因就是漏了这一步)。 - 模拟折行:微软雅黑宽度单位 CJK=1.0、ASCII=0.55;行数 = ceil(单位宽 ÷ (可用宽/字号));
行高 = 字号 × 1.3(模板 lnSpc 130%)。 - 字号阶梯:从目标字号逐级下降直到装下
(cards3 正文 28→26→24→22→20;列表 28/24→26/22→24/20→22/18;卡片正文 24→22→20)。 - 标题折行也要算:标题超宽会折两行("误区一:就是无人机"9 字在 3.4in 内必折),
高度预算用head_h()实算,不能假设单行。 - 行高按最高块:列表类多块的行高取 max(各块需要),取平均会把长块饿死(互压)。
- 铁律:stat 大数字必须单行(可用宽÷单位宽×72×0.92 安全系数,宁可小不折行);
目录项 wrap=False 一行排开;装不下就警告拆页,绝不硬塞。 - 封面标题自适应:单行 ≥56pt 优先,否则两行且总高 ≤1.87in;副标题动态放标题下方 0.18in
(用户 2.0 版封面 80pt 两行实测压住了副标题——照抄前先渲染验证)。
v8 编号列表页返修(2026-10-13,电气行业册用户看图反馈)
- 编号列表正文不手工断行:numbered-full(带图)每块正文写成一行(≤20 字),
交给自动折行;块标题 + 一行正文 + 行距在整页高度内均匀拉伸
(_list_rows装下后row_h = max(row_h, avail/n))。
1a. 禁止逗号后硬断行(2026-10-14 用户二轮反馈):outline 里所有,\n式手工断行
都会产生"莫名断句",必须合并成自然流交给自动折行(text-image/image-points/grid4/
cards3/cards2x2/quadrant 正文一律不带\n;仅 stages3 三点结构与 stat-cards 注脚
这类窄容器保留人工分行)。合并时若原文靠换行分隔(无标点),必须补上,/、/;,
防止出现"调节性电源机组升级改造持续"式连读。 - 配图 cover 裁剪:text-image / image-points / numbered-full 的图框改用
add_picture_fit(..., cover=True)——按图框比例居中裁剪填充,横图不再在近方形框内
大量留白;裁掉比例超过min_keep=0.5时退回 contain(grid4 中心图仍用 contain)。 - 图框加大:numbered-full 右图 (7.95, 1.42, 4.8×5.0)、image-points 左图 (5.6×4.95),
文本列宽同步改 7.35 / 6.5。 - **
**高亮** 不能跨 \n 行**:跨行时星号按字面渲染,高亮必须完整落在单行内。 - compare 的
note必须写在 compare 对象内部(写在 page 层不渲染)。 - stat-cards 大数字避免「65%以上」这类中文后缀(会折行),用「超65%」;
4 卡注脚每行实渲染约 ≤6.5 个汉字位。
v8.2 断行返修(2026-10-14,用户三轮反馈:「第一行往右多写一点」)
- 编号/小标题与正文必须行内连排(不得分成两个段落):
image-points、numbered-full 用_inline_block_lines(),把「01 标题:」与正文写在
同一个<a:p>里(标题加粗藏青,正文灰),第一行一直往右写到写满才折第二行;
text-image 本来就是【小标题】+正文同段,不要再拆成两段(拆开就会在标题行右侧
留一大块空白,用户看到的就是这个「空了一格」)。 - 加宽文本列、缩图保比例:text-image 文本列 7.5→8.0in(图框 8.5,1.42,4.25×5.0);
numbered-full 文本列 7.35→7.8in(图框 8.35,1.42,4.4×5.0);image-points 6.05/6.7。 - 折行空隙的根因与改法:提前折行 99% 是「拉丁/数字串不可断 + 中文标点避头尾」
造成(如DTU/FTU,整块 140px 装不进剩余 121px;Ansys/MATLAB还会被从字母中间
劈开)。改法是调文案而不是调渲染:
-/换、(Ansys、MATLAB)或把拉丁词挪进括号仿真(Ansys、MATLAB);
- 拆短拉丁串(DTU/FTU→DTU、FTU,让DTU、先上第一行);
- 删字让下一个整串能挤上第一行(「集群总产值超 1400 亿元」→「集群产值 1400 亿元」)。 - 第四道关
check_lines.py(断行检测,必跑):
bash $PY $SKILL/scripts/check_lines.py 成品.pptx # 阈值 70px $PY $SKILL/scripts/check_lines.py 成品.pptx --pages 15 --dump # 逐行打印断行位置
逐字符用Range.getBoundingClientRect()量真实行盒,按垂直重叠合并成视觉行,
报「提前换行(非末行右空 > 阈值)」和「孤字尾行」。
- 阈值默认 70px:CJK 避头尾标点天然会留 1~1.7 个字(28pt 时约 37px/字),
阈值设 46px 会满屏误报;>70px(≈1.8 字)才是需要改文案的真问题。
- 判定单位必须是段落(.tx的子 div = pptx 的<a:p>):小标题独占一行是设计
使然,按文本框判会把所有卡片标题全误报成「提前换行」。
v8.4 图片渲染与版式一致性(2026-10-14 生物医药册踩坑后新增,务必遵守)
- 哪些版式真的会渲染图片(读
build_pptx.py各render_*确认,不要假设):
- ✅ 渲染图:text-image(右图 4.25×5.0)、image-points(左图 5.6×4.95)、
numbered-full(右图 4.4×5.0)、quadrant(中心图 3.6×4.3)、grid4(中心图 3.6×4.3)
- ❌ 不渲染图:cards3、cards2x2、stat-cards、stages3
→ 因此 outline 里若给 cards3/cards2x2/stages3 写了image,图片会被静默丢弃。
要配图就必须选上表✅ 的版式。
- ✅ v8.6 起compare也渲染图了:有图时自动切「左竖图 + 右侧上下两段对比」布局
(见下文第 7 条第 8 点),此时note行会被忽略。 - 相邻版式重复必须自查(写完outline.json 立刻跑这段):
python bad=[(i,lay(pg[i])) for i in range(1,len(pg)) if lay(pg[i])==lay(pg[i-1])] assert not bad, bad
初稿极易出现 15–20 处连续同版式。消除时注意块数上限:
image-points=3、stages3=3、quadrant/cards2x2/grid4=4、compare用compare 对象、
stat-cards=2–4、其余 3–4。凑不齐就用 text-image ↔ image-points ↔ numbered-full 三向轮转。 - 配图必须按图框比例预裁(build 前一步),否则 contain 居中会留大片空白、与文字柱不等高:
python spec={'text-image':(4.25,5.0),'image-points':(5.6,4.95),'numbered-full':(4.4,5.0), 'quadrant':(3.6,4.3),'grid4':(3.6,4.3)} # (宽,高) 英寸 —— 见下方校注
偏差 >0.04 就居中裁切后另存,再把image.path指向新图。
- 校注(2026-10-15 实测):grid4/quadrant的图框真实尺寸是 3.74×3.42in
(render_grid4/render_quadrant里cbox = (4.78, 1.50, 3.74, 3.42),比例 1.09,略横)。
但历史所有册子的图都是按上表 3.6×4.3(比例 0.84,竖版) 预裁的,contain 进 3.74×3.42 的框后
实际占位只有约 2.86×3.42in,左右各留 ~0.44in 空白。- 想和已交付册子保持一致 → 继续按 3.6×4.3 竖比预裁(现状,别改);
- 想让中心图填满图框 → 改成按 3.74×3.42(比例 1.09)预裁,视觉会与旧册子不同,
属外观变更,改之前先问用户。
- 绿底抠图残留要程序化检测(百度图库设备图高发,纯目检易漏):
把图缩到 60×60,统计四边 12px 内g>60 and g>r*1.25 and g>b*1.25的像素占比,
>0.30 判为绿底必须换图。实测 81 张里能抓出 3 张(生物反应器、测序仪)。 - 断行不只来自拉丁串:
48%,、2026、2200 亿元这类「数字+中文标点」是不可断整体,
缩短 heading 完全无效,只能改中文表述(48%→「近一半」)、删字或换说法。
连续 3 次改不动就果断换表述,不要在同一句上反复试。 - 手写 outline.json 的两个低级错:compare 的
note行尾多打一个}会让JSON 解析失败;
键名不可中英混用(写risk而不是风险会导致该行不渲染)。 - ⚠️ compare 字段结构(2026-10-14 二次踩坑,用户看到三页 VS 空白):
脚本契约是compare: {center, left:{label, items:[{k,v}]}, right:{...}, note},
不是rows: [[k,v],...]——rows 会被静默忽略,页面只剩 VS 圆和两个标签。
且每侧 ≤4 行(超出被[:4]截断);32pt 下列宽 4.95in 只容约 11 汉字单位,
每行k+v控制在 ≤8 汉字 才不超框(超出 19px 的教训)。
写完 outline.json 后先 grep 一下rows,再检查所有版式的特殊字段
(stat-cards 的value、stages3 的stage、quadrant 的badge)是否与
build_pptx.py各render_*函数的 docstring 一致——以脚本为准,不以大纲文件为凭。 - ✅ v8.6 compare 已支持配图(2026-10-14 脑机接口册修复,用户反馈「VS 对比页是空白的」):
- 症状根因:compare 原版式无图位 → ①违反「每页必配图」硬规则 ②下半页大面积留白,
在 PowerPoint 里看起来就是「空白的一页」。
- 解法:给render_compare加图位——有图时改为「左侧竖图 + 右侧上下两段对比」
(左图 2.90×3.20in @CONTENT_X,文字列 x=3.75 宽 9.00in,两段各 seg=(col_h−0.26)/2)。
- 为什么不用 VS 圆:1.9in 的圆在两列间隙里必然压住文字列(零重叠红线),
缩到 0.8in 又显得空洞。改用藏青/橙色标签区分对比方,VS 语义由页标题承担。
- 有图时不支持note行:note 折行会与下段互压(实测 30px),结论写进页标题。
- 竖构图图(比例 0.8~1.4)在 2.90in 宽框内几乎满框;不要改成通栏横条
(12.3×0.95in 框装竖图会留大片空白,cover 也会因 keep<0.5 退回 contain)。
- 段高预算:fit_body估算偏乐观,3 项 32pt 实测需 seg≥2.45in 才不溢出 35px。
- ⚠️ v8.8 已回滚本条:两段式实测超容,render_compare现has_img=False恒走经典
VS 布局、忽略 image 字段(compare 归图形型版式无需配图)。本条布局参数仅作历史参考。 - 纯列表版式必须换版式才配图(同上踩坑确认):
cards2x2与cards3一样不渲染图,
4 页 cards2x2 的配图被静默丢弃。替代路径(保持相邻不重复):
cards2x2→text-image(≤3块)/ grid4(4块)/ quadrant(4块)。
stat-cards/compare/stages3是图形型版式,无需配图,
但不要给它们写 image 字段(会被丢弃)。 - 配图匹配度审查要按「渲染截图」而非图库文件目检(2026-10-14 脑机接口册返修):
- 只有text-image/image-points/numbered-full/grid4/quadrant五种版式
真正渲染 image;对cards3/cards2x2/stat-cards/stages3/compare换图是无效劳动。
- 流程:outline 提取「页标题↔image.path」→ img_final 拼 contact sheet 只初筛会渲染的页
→ 替换(优先复用 img_raw 未用候选,不够再 fetch_images 按精准关键词抓)→ 重建 →
shot_pptx.py --pages <替换页>出截图 → 逐张目检图与页主题是否对得上。
- 图库常见坑:知乎/Veer/南方+ 水印、纯 skyline 与政策页错位、产品与场景错位
(如手术机器人配「运动功能重建」应为外骨骼训练)。 add_picture_fit返回 5 元组(left, top, w, h, bottom)——v8.4 起第 5 个是图片实际底边,
图注定位用它而不是box[1]+box[3](cover 裁剪后图高可能小于图框)。- ⚠️ 预裁文件名必须带来源目录前缀(2026-10-14 三次踩坑,用户反馈"图片与内容匹配度太低"的根因):
多批抓图分到img_raw/、img_raw2/、img_raw3/,但文件名都是01_1.jpg递增。
预裁脚本把 basename 写进同一个img_fit/目录 → 同名文件互相覆盖,后裁的顶替先裁的,
部分页面显示的是完全错误的图(如 ADC 页显示成泰州医药城门牌)。修法和规则:
- 预裁输出命名img_fit/{来源目录}_{原名}.jpg(如img_raw2_03_1.jpg);
- 逐页分配配图时以"页标题关键词 ↔ 图片内容"逐一对照,而非按抓取批次顺序沿用;
- 用完整路径做重复校验(Counter(完整路径),basename 校验会误报/漏报);
- 内容主题与配图的张力优先"场景一致":模式动物→实验小鼠、临床 CRO→医生查房、
医学事务→学术会议、AI 制药→分子模拟渲染图、头部玩家→总部大楼,
不要为了省事给所有页都配"通用实验室照"。
v8.3 文字柱与配图等高(2026-10-14 用户带截图反馈:「三大段文字错开一点距离,
和右侧图片保持整体高度一致,页面结构更和谐」)
- 问题:text-image / image-points / numbered-full 的文本列默认从内容区顶部顺序堆叠,
块少时文字只占柱高一半(实测 P38 集群地图·长三角:文底 4.96in vs 图底 6.42in,
矮 1.46in),右侧大图撑满 5.0in,页面右实左虚。 - 解法
scripts/fit_columns.py(build 之后的第 ⑤ 步,渲染后处理):
- 先从 pptx 识别「文+一列图」页并记录文本框坐标/图框底边;
- Playwright 真实渲染量出文字实际渲染底边(注意多页纵向堆叠,必须减去页面自身
getBoundingClientRect().top,否则坐标会飙到几十 inch);
-slack = 图底 - 文底 - 0.06in,slack ≥ 0.25in 才处理;
- text-image(单框多段)→ 把 slack 均分到各段space_before(第 0 段保持 6pt 不动,
避免整体下移);image-points / numbered-full(每块一框)→ 按块序号整体下移i*gap;
- 复测确认文底落在[图底-0.15in, 图底+0.03in],带--apply才写文件(先自动备份 .bak_fit)。 - 单隙上限 0.8in:3 块文本撑满 5.0in 柱高时间隙约 0.7in,这是"等高对齐"的必然代价;
嫌散就把块写长一点(每块多一行,空隙自动变小)。 - 筛选条件:文字柱只取
top > 1.3in(内容区)且width > 5.0in的框——
页标题 11.6in 宽会被误选(曾导致"文本框数与块数不符"全部跳过)。 - 流水线顺序(缺一不可,v8.3 起为五步):
build_pptx.py→check_pptx.py→shot_pptx.py --check→check_lines.py→
fit_columns.py --apply→ 复跑 ②③④(fit 会改 spcBef/位移,必须复检)。 fit_columns.py --apply只能跑一次(2026-10-14 集成电路册实测):第二次跑复测坐标
会把已调整的量再算一遍,8/10 达标 → 0/2。必须重来就build_pptx.py重建,
或从.bak_fit恢复后再 apply。8/10 达标(余 2 页差 0.4~0.7in)属可接受。
v8.4 标题单行铁律与 stat 大数字(2026-10-14 集成电路册,39 处→0)
- 标题必须单行,且上限按真实字体量、不按字数估:32pt 微软雅黑加粗在 11.6in 标题框内,
实测安全上限约 1085px(框宽 1114px 减内边距)。用 Playwright 量真实宽度最准:
python pg.evaluate("(t)=>{const e=document.getElementById('t');e.textContent=t;" "return e.getBoundingClientRect().width;}", title)
超限的连锁后果:折成两行 → 文本超出自框 45px → 第二行压到正文(互压 600×15px)。
本轮 52 个内容页有 16 条标题超限,逐条缩短后归零。build的溢出估算查不出这个,
只有shot_pptx.py --check能报。 - 标题缩短的优先手法(保持"标题即结论"):删副词(「已经/正在/就在眼前」)→
数字取整(5225.9 亿元→5225 亿元)→ 去掉末尾补充说明 → 换成更短的名词短语。
不要把标题改成主题词(会丢掉结论性)。 - stat-cards 大数字禁止中文后缀:
不足3%、超65%、约28%都可能折成两行
(违反 v8.2「大数字必须单行」铁律)。改法:<3%、<65%,
或把「不足/超」挪进下方注脚。注脚每行实渲染 ≤6.5 个汉字位(4 卡时)。 - text-image 的 8.0in 文字列最多容 3 块:第 4 块即使每块只写一行,22pt 仍超容。
需要第 4 块内容时改用numbered-full(通栏 12.3in),不要硬塞 text-image。
numbered-full可容 3–6 块,是清单页的默认选择。 - 版式相邻去重用分配器,不要手工 patch:写「各页声明版式 + 语义替代表 +
块数/字段相容性检查 + 前瞻代价」的贪心算法——声明版式优先,仅当与上一页冲突时
才从替代表里选「后续冲突最少」的那个。手工改LAYOUT_OVERRIDE容易顾此失彼
(改 A 制造 B 的冲突,来回返工)。同时校验块数区间与专用字段
(stat-cards 要value、quadrant 要badge、stages3 要stage)。
分配器必须「配图感知」:能渲染图片的只有text-image/image-points/
numbered-full/grid4;若把配图页分到 cards2x2 / stat-cards 等版式,
图片会被静默丢弃(实测 5 页丢图,pptx 里只有 29 张而 outline 有 34 个配图页)。
上一版式要取「实际分配结果」而非「声明值」,否则前页声明不同但实际撞上仍会重复。 - text-image 带图时只能容 3 块(正文列 8.0in;无图满幅时才是 12.3in 可容 4 块):
4 块即使每块一行,22pt 仍报「仍超容」。分配器里对「带图 + >3 块」的 text-image
直接判不可用,让给 numbered-full(通栏 12.3in,可容 3–6 块)。 - 图库先拼 contact sheet 再挑:抓 3 批约 165 张 → 拼图逐张目检 → 剔除带水印、
带 LOGO、AI 生成图、带字海报、主题不符(向日葵/猫/AI 城堡/旧教材/微信截图)→ 约 71 张入选。
城市类关键词命中率低(西安/天津=0 张),改用「城市+科技园/高新区」或航拍替代;
政策页用产业园航拍、城市页用对应城市实景,避免全册反复用同一张基地图。
自检:build 后比对「outline 配图页数」与「pptx 含图页数」,不一致说明有图被丢弃。 - 匹配度返修流程(2026-10-14 集成电路册):交付后用户嫌「图与内容不匹配」时——
渲染全部配图页截图 → 2 页一拼 tile 逐页目检 → 按问题类型更换(CGI/AI 渲染、
视觉中国/百家号/CSDN/知乎水印、软件设置弹窗截图、带品牌字的芯片渲染、重复用图、
通用楼宇冒充城市地标)。关键词避坑:「汽车芯片」首屏几乎全是 AI 渲染图(注意
「豆包AI生成」「IMAGINED WITH AI」角标),换「智能汽车座舱 / 汽车ECU实物」等实物向词;
城市页要用地标级实景(如深圳春笋)而非任意楼宇。换图必须按图框比例预裁再入库,
并复跑全套质检(fit_columns --apply 仍只能跑一次)。
v8.7 渲染级几何缺陷(2026-10-14 具身智能册,21→0 处,已修进 build_pptx.py)
本轮再次证明:估算器全线 PASS ≠ 能交付。 check_pptx 全绿,但渲染级检测
报出 21 处。六个根因(均已修脚本,后续行业册直接受益):
add_caption未开word_wrap— 图注整句单行横溢,压住 grid4 底部两块,
实测互压 100~143×26px。修:tf.word_wrap = True+ 框高 0.4→0.62in
(开换行后可能折两行,0.4in 会溢出 16px)。add_picture_fit必须返回图片实际底边 —cover=True裁剪后图片高度
可能小于图框,调用方按box[1]+box[3]定位图注会留 1~2in 空隙。
改为返回 5 元组(left, top, w, h, bottom),4 处调用点同步解包。- stat-cards 大数字不能按字符数估宽 — 中文被高估约 45%,
不足30%/80至90%会折行,违反 v7.1「大数字必须单行」铁律。
修:用_units()(CJK=1.0 / ASCII=0.55),内边距 0.5→0.62in,
注脚与标题统一同一宽度基准。文案侧配合:用<30%、进口这类
短表达,比不足30%、仍依赖进口更容易单行。 - compare 无图分支的 VS 圆会压住左列 — 旧几何圆心 6.665 / 直径 1.9in
落在左列(0.63~5.58)内部,渲染互压 70×75px。修:圆心移到两列间隙中点
6.815、直径 1.10in、字号 32(VS_SZ=40在 1.1in 圆里放不下)。 - compare note 框高 — 24pt 结论句在 12.1in 内多为一行,但中文避头尾会折行,
0.5in 实测溢出 41px → 0.55in、y 6.30。 - 篇章页标题框加高必须与序号框同步 — 标题框左右 1.0→1.15in 且高度 +0.14in
才能消掉 4px 溢出;但只加标题框会反向挤压序号框溢出 13px,两个框要一起加。
另记两条文案侧经验:
- **高亮** 跨行会被字面渲染(东北大/学),按 v8.2 办法把高亮移到短词组
(东北大学、…,**全部为双一流**)而不是改渲染。
- 文字柱等高优先加文案而非拉空隙:text-image 页空隙 1.4in 时给每块补
一句实质信息,版面更饱满且增加内容价值;补完注意 4 页会超容,需回退压缩。
渲染级验证(交付前必跑,估算通过 ≠ 真的不重叠)
$PY $SKILL/scripts/shot_pptx.py 成品.pptx --check # 浏览器真实排版检测
$PY $SKILL/scripts/shot_pptx.py 成品.pptx --pages 5,8 -o /tmp/shots # 截图目检
--check用 Playwright + 本机 Chrome 按真实字体渲染,量出每个文本的实际占位:
文字超出自框 / 露出卡片底色 / 文字互压 / 文本压图,逐条列出(自动识别 wrap=none 的
单行文本框,不误报)。- 检测为 0 处(或仅剩模板固有的 ≤5px)才允许交付;必须再抽查截图目检。
--pages的页码是物理幻灯片号 = outline.json 页码 + 2(封面、目录占位;
2026-10-14 具身智能册实测)。按大纲页码截图会看错页,先用内容标题核对偏移。-o输出目录建议给绝对路径(相对路径会让 file:// 导航失败)。- 教训:2026-09-23 曾因只跑估算脚本就交付,被用户发现多处重叠与露底——
估算模型永远有偏差,渲染级检测 + 肉眼目检缺一不可。 - 交付前质检关(2026-10-14 定型,缺一不可):
①build_pptx.py无容量预警 → ②check_pptx.pyPASS →
③shot_pptx.py --check≈0(仅剩模板固有 ≤5px)→ ④check_lines.py无提前换行 →
⑤fit_columns.py --apply文字柱与配图等高 → 复跑 ②③④(⑤会改段前距/位移)。 - 若当前会话的模型读不了图片(无法目检截图),用
check_lines.py --dump的逐行
右空像素值代替目检,并如实告诉用户"未经肉眼确认",不要谎称已目检。 - 用户 2.0 版自身也有 66 处渲染级问题(含封面标题压副标题、P34 通栏底图文字不可读),
学习用户的布局思想,但不照抄具体数值——每个数都要过一遍容量引擎。
回归基准:改脚本后必须和已交付册子对一次(2026-10-15 定型)
# ① 用旧大纲重跑一遍(build → fit_columns --apply)
cd <old_outline 所在目录> # 相对图片路径依赖它,见下方注意
$PY $SKILL/scripts/build_pptx.py outline.json -o /tmp/rebuild.pptx
$PY $SKILL/scripts/fit_columns.py /tmp/rebuild.pptx --apply
# ② 与当初交付的成品逐层比对(页数/几何/文本/字体/图片 md5/备注)
$PY $SKILL/scripts/compare_decks.py /tmp/rebuild.pptx 当初交付.pptx
2026-10-15 实机结论(基准=《生物医药与创新药行业分析培训.pptx》65 页、《新能源行业分析培训.pptx》63 页):
七项里页数、形状数、文本、run 级字体字号粗体颜色、图片 md5、备注全部一致;
几何差异只落在三类、每一类都是脚本的既定改进或测量噪声:
1. compare 中心圆:旧稿 1.9in/圆心 6.665/字 40pt(会压住左列),现网 1.10in/圆心 6.815/字 32pt
—— v8.7 §4 的既定修复,新稿更正确;
2. grid4 / quadrant 中心图:2026-10-14 02:39 交付时这两页的图被静默丢弃,
现脚本会画出来(render_* 里有 add_picture_fit)——符合「每页必配图」硬规则;
3. fit_columns 造成的 ≤0.16in 位移(4 页/65 页):Chrome 二次测量噪声,在允许带
[图底-0.15in, 图底+0.02in] 内,不是脚本变化。
重跑件三道质检全绿(check_pptx PASS / shot --check 0 处 / check_lines 无提前换行),
即当前脚本能把交付标准原样复现。
操作注意(2026-10-15 加):
- outline 里是相对图片路径时,build 的当前目录必须是 outline 所在目录;
build_pptx.py 已加自动兜底(CWD 找不到就回退到 outline 同级目录),但不要依赖它。
- 缺图不再静默:找不到的图会在 stdout 列出物理页码,并核对「应出图页数 vs 实际图片数」,
不一致必报警。看到报警先补图再说,别带着丢图的册子往下走。
内容页版式字典(layout 字段,缺省:有图=text-image,无图=numbered-full)
| layout | 结构(v7 尺寸) | 适用内容 | blocks |
|---|---|---|---|
text-image |
左文右图(正文 7.5in + 右图 4.6×4.7in);无图时正文满幅 12.3in | 需逐条展开的文本型页 | 3–4 |
image-points |
左大图 5.3×4.6in + 右侧 01/02/03 编号论点(栏宽 6.75in) | 定义/特征类,看图说话 | 3 |
cards3 |
三栏浅色卡片(卡宽 3.90in + 28pt 徽章+标题+正文) | 误区、三要素 | 恰好 3 |
grid4 |
中央图 3.6×4.3in + 四角论点;无图时四块拉成满幅 2×2 | 四象限信息、带图盘点 | 恰好 4 |
numbered-full |
全宽 01/02/03 通栏编号列表(v7 起也支持右侧配图) | 清单页(岗位清单、城市清单同样要配图) | 3–6 |
compare |
中心圆 + 左右两列「标签+数值」 | 两两对比:vs 传统领域、城市对比、本专科对比(用 compare 字段) |
每侧 ≤4 行 |
stat-cards |
2–4 张大数字卡(数字 32–44pt 按卡宽自动缩放保证单行 + 24pt 加粗居中注脚) | 关键数据盘点:规模、增速、渗透率(用 value 字段,注脚每行 ≤8 字 ≤2 行) |
2–4 |
stages3 |
三列彩色头卡片(藏青/亮蓝/橙,头卡 28+32pt) | 时间演进:政策演进、里程碑、爆发节点(用 stage 字段) |
恰好 3 |
quadrant |
2×2 彩底大字母卡(徽标+标题 28、正文 24) | 框架分析:PEST、SWOT(用 badge 字段) |
恰好 4 |
cards2x2 |
2×2 编号卡片(整体上移到 y=1.37) | 四类要点清单 | 恰好 4 |
多样性规则(用户要求:不单一也不花哨):相邻内容页不得连用同一版式;
60 页全册至少用到 6 种版式;按上表「适用内容」选型,不要全程左文右图;
compare/quadrant/stages3 只在内容确实匹配时用,不为凑版式硬套。
- "相邻"要跳过篇章页:篇章页本身已是视觉分隔点,隔在中间的两个内容页不算重复
(2026-10-15 复核生物医药/新能源两册,计入篇章页时误报 2 处 / 1 处,真实为 0)。
- 结构:五大板块约 60 页,规范见 references/structure.md;
逐页大纲的颗粒度标准见范例 references/example-low-altitude.md(低空经济 60 页定稿)。
工作流(按序执行)
1. 确认参数(一句话即可,不反复确认)
默认直接开做:行业口径按通行定义(如低空经济=1000 米以下空域综合经济形态)、
地域默认中国大陆、篇幅默认 60 页、封面副标题默认"主讲:XXX"(用户给了就用用户的)。
2. 列逐页大纲(先于检索,先给用户确认一次)
按 references/structure.md 的五板块结构列出每一页的小主题(颗粒度对齐
references/example-low-altitude.md),写成 outline.md 呈现给用户确认方向,只确认一次。
3. 分主题检索核实
逐页补数据:市场规模、政策文件名与文号、试点省份清单、企业与岗位、专业名称与代码。
- 每个数字带「年份+口径+来源机构」;查不到写"公开数据缺失",严禁凭印象填数。
- 预测标"预测/预期+机构+年份";禁用虚词(广阔/迅速/良好…)。
- 板块四必须落到真实专业名称/代码和分分数段(高分/中分/专科)建议。
4. 配图(每个内容页都要 1 张,高清无水印)
v7 新规(来自用户 2.0 版):用户在我原版基础上给 4 页"清单类"页补了图(图片数 15→19,
包括「岗位清单(一)(二)(三)」「六城 eVTOL 试点」)。所以不存在"清单页不需要配图"——
numbered-full / cards2x2 / cards3 这类纯列表页同样要配图,实在没图就换版式。
通栏背景图玩法:整幅图铺满内容区 + 叠一层半透明色块遮罩,再把文字压上去(用户 P34 用过),
但遮罩必须保证正文对比度 ≥4.5:1。
用户已明确:内部小范围培训使用,不用管图片版权和来源,但要求高清、无水印、与内容匹配。
# 先按你的环境设置两个变量(Windows 用 Git Bash / PowerShell 同理)
PY=<你的 Python 解释器,建议 3.9+>
SKILL=<本技能目录,如 ~/.workbuddy/skills/industry-training-ppt>
$PY $SKILL/scripts/fetch_images.py --kw "关键词1;关键词2;..." --out img_raw --per 8 --min-px 800
- 搜索结果会混入无关图/带水印图,必须逐张目检(拼 contact sheet 看图),
剔除带水印、带 LOGO、主题不符的;优先实景照。 - 在 outline.json 的 content 页加
"image": {"path": "...", "caption": "图注"},
图注一句话说明画面与内容的关系。
5. 写 outline.json
按 assets/outline.example.json 的 schema:
- meta.title(封面主标题 ≤14 字)、meta.subtitle、meta.toc(恰好 5 项,与板块同名);
- pages 数组:section(每板块 1 页,no=01–05)+ content:
- title = 结论句;layout 按上方版式字典选型(注意相邻页不重复);
- blocks 数量匹配版式(cards3=3、grid4=4、其余 3–4),heading ≤12 字,
text 行数/行长按版式容量(text-image 每行 ≤22 字、image-points ≤17、卡片每卡 ≤45 字总量);
- 重点词 **...**;image + caption(text-image/image-points/grid4 需要图);
- 页内只放产业内容本身;"对规划师意味着什么/要学什么"一律写进该页 notes
(演讲者备注,解读本页核心重点 + 规划师落点,不出现在页面上);
- 封面/目录/封底由 meta 自动生成,不写进 pages。
6. 生成 + 质检(必须全绿再交付)
PY=<你的 Python 解释器>
SKILL=<本技能目录>
$PY $SKILL/scripts/build_pptx.py outline.json -o <行业>培训.pptx
$PY $SKILL/scripts/check_pptx.py <行业>培训.pptx # 字号/溢出估算
$PY $SKILL/scripts/shot_pptx.py <行业>培训.pptx --check # 渲染级重叠检测(必须≈0)
$PY $SKILL/scripts/shot_pptx.py <行业>培训.pptx -o /tmp/shots # 截图逐版式目检
- 三道关:build 预警 → check 估算 → shot 渲染级检测 + 截图目检,缺一不可。
- 渲染检测报的问题必须修到 0(模板固有 ≤5px 除外);看截图确认无叠字、无露底、
无换行断得难看(如"报/告"、"亿"字掉行)再交付。
7. 交付
present_files 交付 .pptx(主)+ outline.md(逐页大纲)。
结尾提醒:标注"公开数据缺失"的页需人工补充核实后再用于正式培训。
8. 用户返修后:用 diff 学标准(重要)
用户常会自己在 WPS 里改一版发回来。先把当时生成的原版 .pptx 留一份(别被覆盖),再:
$PY $SKILL/scripts/diff_pptx.py 原版.pptx 用户版.pptx --summary # 聚合统计
$PY $SKILL/scripts/diff_pptx.py 原版.pptx 用户版.pptx --only 8,34 # 指定页细看
读出「字号怎么改的 / 左缘往哪移了 / 卡片加宽多少 / 哪几页补了图」,把结论写进本文件的
v7 字号表与版面几何,并同步改 scripts/build_pptx.py 顶部的常量区。
(坑:工作区里的同名 .pptx 可能已被 WPS 存成用户版,务必用生成时那一份做基准。)
硬性规则
- 模板即风格:只用 build_pptx.py 在模板样例页上改字/插图,不改母版、不删底图、
不自建色块样式(标题左侧小色块由脚本统一加)。 - 字体统一微软雅黑(封面/目录/篇章/标题/正文全部);字号严格按上面 v7 字号表
(正文主力 24–28pt,块标题 28–32pt,目录 40pt,封面 80pt),图注是唯一允许 14pt 的。
重点词一律用**...**橙色加粗,不手动改色。 - 版式多样性:按版式字典选型,相邻内容页不重复同一版式,全册至少用到 6 种版式;
不花哨——特殊版式(compare/quadrant/stages3/stat-cards)只在内容匹配时用。 - 五板块不可乱序、不可删除:破认知→拆产业→政策城市→人才专业→收尾;
页数配比如 structure.md,总页数 55–65。 - 每页独立小主题、标题即结论;页内只讲产业内容(用户 2026-09-23 新规:
去掉页内"规划师含义"板块),规划师视角的解读写进每页notes备注区,
备注 = 本页核心重点 + 对志愿规划意味着什么,每页都必须有备注。 - 放不下拆页不缩字号;各版式行长上限见版式字典与 structure.md。
- 零重叠(用户 2026-09-23 红线,低级错误不能犯):
- 每个逻辑块只用一个文本框(标题段+正文段用段落间距分层),禁止按行拆框
(割裂且无法二次排版);
- 文字与图形必须留安全距离:图形内文字控制在图形内接区域 70% 以内
(如圆内只放 ≤2 个大字,长文案一律放圆外);
- 字号一律走容量引擎(见 v7.1),禁止先定字号再硬塞;
- 交付前三道关全绿:build 预警 0 + check 估算 PASS + shot 渲染级检测 ≈0 + 截图目检。 - 目录恰好 5 项(模板只有 5 个目录槽);篇章页序号 01–05。
- 配图三性 + 每页必配:高清(≥800px)、无水印、与内容匹配;逐张目检后才允许进
outline;每个内容页都要有图(含清单类页),图尽量放大到 ≥4.6in 宽。 - 数据三要素:任何数字能回答"哪一年、什么口径、谁说的"。
与其他 skill 的边界
- 本 skill:用户指定结构(五板块 60 页)+ FY27 升学规划模板直出,轻量、版式即模板原样。
industry-research-ppt:研究增强版(武器库分析框架、自建渲染、配图 ≥12 页、source_audit)。
用户没指定用哪个时,提到"60 页/五板块/按我的模板"走本 skill。