diff --git a/PROGRESS.md b/PROGRESS.md index 18581a0..2d9a3ed 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -23,6 +23,7 @@ ### 2026-06-08 +- **ppt skill 工作流批量化(减高轮数 task 的来回)**:实测高成本 task 几乎全是 100+ 轮的"逐步 tool 调用循环"(rust→PPT 34 轮、文献采集 245 轮),每轮重发整段上下文,轮数是 token 体量的线性乘数。ppt 是最易压、风险最低的试点:原 §阶段二**逐页**(每页 `读spec→glob图标→一个 run_python 加页→等用户确认→下一页`,N 页 ~2N 轮)。改法:① 阶段一 spec 增「逐页大纲」表(页|版式|标题|要点|图标),作为**替代逐页确认的前置 checkpoint**——改文字大纲比建完 slide 再推翻便宜;② 阶段二改成**写一个 `build_deck.py` 一次建整 deck**(同进程 `new_presentation`→按大纲循环 `add_slide`→一次 `save`,坐标天然一致;`pptx_helpers` 模块化已消解原"逐页防漂移"理由),图标**全 deck 批量预取**(不逐页拉);③ quality_check 一次 → 改脚本重跑(不 edit 成品);④ 可选"风格探针"(先建封面+1 页看观感)兜视觉返工险。N 页从 ~2N 轮降到 ~3-4 轮。改 `skills/ppt/SKILL.md`(阶段一/二/三 + 反模式 + 文件树)、`references/layouts.md`(§通用起手换成"整 deck 单脚本"模板)、`SKILL_LIST.md`(流程描述/典型产物同步)。冒烟过:单脚本 `new_presentation`+循环 `add_slide`+`save` 建 2 页成功,API 调用与模板一致。**注**:数据采集类(host 工具中转免不了)是另一条路(拆采集/处理相位),未动。 - **修进度还原错乱 + 进度区移到对话区顶部(codex 式)**:根因(查 DB 实锤)= 上下文压缩把旧 `task_progress` tool_call 参数换成 `{"_compacted":true,"step_id":"sX"}` 这种"看着像合法调用"的标记,① 毒化模型让它后续照抄出残废 `update_step`(丢了 `step.status`)并入库,② 残废格式前端 `applyProgressAction` 读不到 `args.step` → s4/s5 永停 pending → 进度显示不对。修复:`context.py` 对 `task_progress` 参数**一律不压缩**(参数本就小,压缩省不了几个 token 却两头坏事);旧的 `_compact_task_progress_arguments` 整个删除。**进度展示重构**:删掉每条消息卡内联进度块(`renderProgressHtml`/`renderProgressInto` 移除),进度统一只在**对话区顶部**单一 `#task-progress-dock`(从 composer 上方移到 `chat-stream` 之上、`flex-shrink:0` 钉顶不滚)实时显示;**完成态折叠**——全部步骤 completed 时 dock 自动收成一行 `✓ 全部完成 · N/N 步`(`
` 点开看清单)。prompt + tool 描述改为"跑完把最后一步标 `completed`、不要 `clear`",留住全绿收尾。校验:`python -m unittest tests.test_context_compaction tests.test_task_progress_tool`(12 过,改写 `test_keeps_old_task_progress_arguments_intact` 断言参数原样保留);`node --test tests/frontend_task_progress.test.mjs`(2 过)。 - **修登录无反应(`$ is not defined`)+ 补 favicon 消 404**:`newtask.js` 用了 DOM 简写 `$`(`dom.js` 导出的 `getElementById`)却漏 import,模块加载到顶层 `$("hd-new").onclick` 即抛 `ReferenceError: $ is not defined`,中断 newtask 全部绑定及其 import 的 auth/chat 链路 → 点登录无反应。补 `import { $ } from "./dom.js"` 与其余模块对齐。另在 `dev.html` `` 加内联 SVG data-URI ``(蓝底白机器人),浏览器不再请求根 `/favicon.ico`,消掉 404;选内联 SVG 而非新增 `.ico` 文件 / 服务端路由,零新增文件零 app.py 改动。 - **新增 Codex 式 `task_progress` 进度工具 + Web 固定进度区**:`TaskProgressTool` 默认注册到 agent,支持 `set_plan/update_step/clear`,返回极短 UI-only 结果;上下文压缩对旧 `task_progress` tool_call/result 做专门折叠,避免进度历史长期占 prompt。前端新增 `progress.js` 做 task 级进度状态合并,修复 `update_step` 只带 `{id,status}` 时因缺标题不显示的问题;当前进度显示从助手消息内提升到 `#task-progress-dock`(对话流下方、输入框上方),历史消息内仍保留进度块作记录。system prompt + coding/ppt/proposal/analyze skill 加轻量使用约定,要求只在多步骤关键阶段少量更新。**部署侧补静态资源 no-cache**:`NoCacheStaticFiles` 替换默认 `StaticFiles`,让浏览器重新校验 `/static/*.js` 等资源,避免前端修复已部署但旧 `chat.js` 仍被缓存导致看不到进度区。校验:`pytest tests/test_context_compaction.py tests/test_task_progress_tool.py tests/test_executor_docker.py tests/test_static_vendor.py -v` 相关集通过;`node --test tests/frontend_task_progress.test.mjs` 2 过;`node --check web/static/js/chat.js web/static/js/progress.js` 过。 diff --git a/SKILL_LIST.md b/SKILL_LIST.md index 78380cf..dc7ade7 100644 --- a/SKILL_LIST.md +++ b/SKILL_LIST.md @@ -1,7 +1,7 @@ # zcbot Skill 清单 服务对象:中国建筑材料科学研究总院 —— 无机非金属材料 R&D(水泥 / 混凝土 / 玻璃 / 陶瓷 / 耐火 / 新型建材) -最后更新:2026-06-05 +最后更新:2026-06-08 Skill 总数:14 zcbot 的"skill"是一份可加载的工作流脚本(`skills//SKILL.md` + 配套 templates / scripts / Python helper),模型在识别用户意图后挂载对应 skill,按其内置的阶段化流程产出可交付物。本文档面向**使用方 / 协作方**,按"做什么、什么时候用、什么时候别用、典型产物"组织。 @@ -16,7 +16,7 @@ zcbot 的"skill"是一份可加载的工作流脚本(`skills//SKILL.md` + | 科研写作 | [standard](#standard) | 起草标准:国标 / 行标 / 团标(含 T/CSTM)+ 编制说明 | | 科研写作 | [patent](#patent) | 写发明专利技术交底书(供代理师转写) | | 科研写作 | [review](#review) | 审稿 / 润色 / 校对(中英文,长文档分段深审) | -| 演示出图 | [ppt](#ppt) | 生成 PowerPoint 演示稿(商务红主题,逐页验收) | +| 演示出图 | [ppt](#ppt) | 生成 PowerPoint 演示稿(商务红主题,大纲对齐后一脚本整建) | | 演示出图 | [plot_pub](#plot_pub) | 出版级 matplotlib 学术图(中文 + viridis + 矢量) | | 文献检索 | [research](#research) | 查 paper_server(OpenAlex 元数据 + Sci-Hub 下载) | | 文献检索 | [documents](#documents) | 查内部 7 学科材料知识库(21W+ 论文,跨语言检索;host-side tool 持 key) | @@ -137,7 +137,7 @@ zcbot 的"skill"是一份可加载的工作流脚本(`skills//SKILL.md` + ### ppt **生成 PowerPoint 演示文稿 (.pptx)。** -把材料(汇报草稿 / 项目方案 / 调研报告)变成可演示的 .pptx。流程:**先定调 → 逐页生成 → 验收**,不一口气把整份 deck 丢出去。 +把材料(汇报草稿 / 项目方案 / 调研报告)变成可演示的 .pptx。流程:**先定调(8 项 + 逐页大纲)→ 一个脚本建整 deck → quality_check 验收**。方向在大纲阶段对齐,执行阶段一把出稿(不逐页来回)。 **触发**: - ✅ 用户明确点名 PPT / 幻灯片 / 演示文稿 / .pptx / slide / deck @@ -167,7 +167,7 @@ zcbot 的"skill"是一份可加载的工作流脚本(`skills//SKILL.md` + - `quality_check.py` 验收(越界 / 文本溢出 / 颜色一致) - 素材摄取走 markitdown 把 PDF/DOCX/PPTX/XLSX/HTML/URL 统一转 Markdown -**典型产物**:`.pptx`(逐页用户确认后 append,可中途修改)。 +**典型产物**:`.pptx` + `build_deck.py`(整 deck 构建脚本,改稿/修验收项都改它重跑)。 --- diff --git a/skills/ppt/SKILL.md b/skills/ppt/SKILL.md index 255413f..44c1dd7 100644 --- a/skills/ppt/SKILL.md +++ b/skills/ppt/SKILL.md @@ -5,9 +5,9 @@ description: 生成 PowerPoint 演示文稿 (.pptx) 文件。✅ 触发:用户 # PPT -把材料变成可演示的 .pptx。**先定调,再出稿,再验收** —— 不要一口气把整份 deck 丢出去。 +把材料变成可演示的 .pptx。**先定调(spec + 逐页大纲),再出稿(一个脚本建整 deck),再验收(quality_check)** —— 方向在大纲阶段对齐,不在逐页阶段反复来回。 -进度展示建议:多页 deck 任务用 `task_progress` 标记「摄取素材 / 八条对齐 / 逐页生成 / 质量检查 / 交付」等关键阶段;不要把每一页的内部文件写入都作为进度步骤。 +进度展示建议:多页 deck 任务用 `task_progress` 标记「摄取素材 / 八条对齐 + 逐页大纲 / 图标预取 / 脚本建 deck / 质量检查 / 交付」等关键阶段;不要把每一页的内部写入都作为进度步骤。 ## 资源 - `scripts/pptx_helpers.py` —— **版式工具箱模块**:配色/字体常量 + `new_presentation`/`load`/`add_slide`/`set_palette` + `add_textbox`/`add_rect`/`add_dot`/`add_badge`/`page_title`/`apply_brand` 等 helper。每页 `import pptx_helpers as P` 调用,**不要把 helper 源码默写进 run_python** @@ -71,21 +71,32 @@ glob /*--*.spec.md → 按文件名字典序排,取最 把这 8 项写进上面那个 task 级 spec 文件,以表格形式给用户预览,问一句"按这个开干?"。**spec 写定后不再改**(要改就走 §0 的「重定调」分支,以 today 为前缀写新版,旧版保留)。 -### 阶段二: 执行 (Executor) — 逐页生成 +**8 项之外,spec 还要含一张「逐页大纲」表** —— 这是阶段二一个脚本建整 deck 的输入,也是替代"逐页确认"的前置 checkpoint(改一行文字大纲,比建完一页 slide 再推翻便宜得多): -每页前 **必须 read 一次 current spec**(按 §0 的 glob 规则拿到的字典序最大那份),只用里面定的颜色/字体/图标 —— **不允许凭记忆或临时发挥**。这条规则是为了对抗长 deck 中的上下文漂移。 +| 页 | 版式 | 标题 | 核心信息 / 要点(≤5) | 图标 / 图表 | +|---|---|---|---|---| +| 1 | L1 封面 | <主标题> | <副标题 / 定位> | — | +| 2 | L4 三栏 | <标题> | <要点 1 / 2 / 3> | `target` / `cpu` / `chart-bar` | +| … | … | … | … | … | +| N | L9 尾页 | Q&A / 致谢 | <联系方式> | — | -每页流程: -1. 读 current spec(即使刚读过) -2. **图标先于版式**: 这一页要用什么概念图标? 先 `glob` 两处看有没有现成 —— 种子库 `/assets/icons/`(只读,`` 是 `load_skill` 头里的绝对路径)+ 本 task `/assets/icons/`;没有就 `python /scripts/fetch_icon.py --set tabler --color C00000 --size 128 -o /assets/icons/...` 拉一个(种子库只读,新图标落 task 目录);`add_picture` 嵌入。**几何形状(圆点/徽章/装饰线)不算图标,走 layouts.md helper 即可** -3. 写一个 `run_python` block 添加这一页:顶部 `import pptx_helpers as P`(`sys.path` 指到 `/scripts`)→ `prs = P.load(...)`(首页用 `P.new_presentation`)→ `P.set_palette(spec_path=...)`(每页重读 spec 注入配色)→ `P.add_slide` + 各 helper → `prs.save`。**helper 一律 `P.xxx` 调用,不默写源码**(防长 deck 漂移),起手见 `layouts.md §通用起手` -4. 报这一页:版式、标题、要点条数、用了哪些图标 -5. 用户确认 / 微调后再下一页 -6. 用户确认了**实质改动**(改版式 / 换图标 / 改文案要点 / 增删页 / 调主色)后,追加一行到 `/REVISIONS.md` —— 见 §修订日志 +大纲连同 8 项一起给用户预览,**BLOCKING 等用户确认整份结构**(页数、每页讲什么、用什么版式/图标)后再进阶段二。用户在这一步推翻方向 = 改表格文字,零 slide 返工。 -**为什么逐页?** 一次性出全 deck 中途改方向就要全推翻;逐页能让用户在第 2 页就发现问题。 +### 阶段二: 执行 (Executor) — 一个脚本建整 deck -**例外**: 用户明确说"别问,直接全做了" —— 一次跑完,但跑完必须用 `quality_check.py` 验收。 +方向已在阶段一的「逐页大纲」里跟用户对齐过,执行阶段就是把大纲机械落成 slide。**不逐页 run_python**(每页一轮来回烧轮数/token);整 deck 在一个脚本、一个进程内构建,坐标天然一致(`pptx_helpers` 已把画布常量统一,漂移问题已解决)。 + +流程: +1. **读 current spec**(按 §0 的 glob 规则拿字典序最大那份),含 8 项 + 逐页大纲;只用里面定的颜色/字体/图标/页结构,**不凭记忆发挥**。 +2. **图标批量预取(全 deck 一次,不逐页)**: 把大纲里所有页需要的图标概念汇总,`glob` 两处看现成 —— 种子库 `/assets/icons/`(只读)+ 本 task `/assets/icons/`;缺的在**一个 `run_python` 里批量** `fetch_icon.py --set tabler --color C00000 --size 128 -o /assets/icons/...` 拉齐。**几何形状(圆点/徽章/装饰线)不算图标,走 layouts.md helper**。 +3. **写 `build_deck.py` 到 ``,一次建整 deck**: 顶部 `import pptx_helpers as P`(`sys.path` 指到 `/scripts`)→ `prs = P.new_presentation(...)` → `P.set_palette(spec_path=...)` → **按大纲循环每页**(`P.add_slide` + 各 helper,每页一个小函数 `page_1(prs)`…清晰)→ 末尾一次 `prs.save(...)`。**helper 一律 `P.xxx`,不默写源码**。起手见 `layouts.md §通用起手(整 deck 单脚本)`。先 `write` 脚本文件再 `run_python(script_path=...)` 跑(避免大段源码进对话历史)。 +4. **quality_check 一次**(见阶段三)→ 按报告**改 `build_deck.py` 重跑**(不要逐页 edit 成品 .pptx —— 改源脚本可复现、可再跑)。 +5. 报整份 deck:页数、各页版式、用到的图标;问用户要不要改。 +6. 用户确认了**实质改动**(改版式 / 换图标 / 改文案要点 / 增删页 / 调主色)后,追加一行到 `/REVISIONS.md` —— 见 §修订日志。 + +**风格探针(可选,降视觉返工险)**: 用户对观感没底、或这是全新风格时,可先只建**封面 + 1 内页**给用户看一眼,确认后把 `build_deck.py` 的页范围放开重跑补齐其余页 —— 仍是改一个脚本,不退回逐页。用户要快("直接全做")就跳过探针,整 deck 一把出。 + +**为什么不再逐页?** 逐页的两个理由都已消解:① 防坐标漂移 → `pptx_helpers` 模块化已解决;② 早发现方向问题 → 前移到阶段一「逐页大纲」确认(改文字比改 slide 便宜),视觉观感由可选探针 + 整 deck 后批改兜底。代价是放弃"逐页即时纠错",换来 N 页从 ~2N 轮降到 ~3-4 轮。 ### 阶段三: 验收 @@ -93,7 +104,7 @@ glob /*--*.spec.md → 按文件名字典序排,取最 python /scripts/quality_check.py / --spec /--.spec.md ``` -不通过的项,回头 edit 对应页。 +不通过的项,**改 `build_deck.py` 重跑**(改源脚本可复现;不要直接 edit 成品 .pptx)。 ## 设计原则 (硬规则速查) - **每页一个核心信息**: 一页讲一件事,塞两件就拆页 @@ -117,6 +128,7 @@ python /scripts/quality_check.py / --spec /source/.md) ├── --.spec.md # 八条对齐落定,task 级宪法;命名见 system prompt 约定;按 short_id 主锚,重定调时写新日期,旧版保留 ├── slides/ # 各页用到的图片素材 (chart_p3.png 等),多 task 时文件名前缀区分 +├── build_deck.py # 整 deck 构建脚本(一次建完所有页);改稿/修 quality_check 项都改它重跑 ├── REVISIONS.md # 修订日志:每次卡点用户确认的实质改动,见 §修订日志 └── .pptx # 最终产物 (按主题命名,多 task 时主题必须不同) ``` @@ -174,7 +186,8 @@ python /scripts/quality_check.py / --spec **要点**:版式 helper 已全部收进 `scripts/pptx_helpers.py`,**不要再把 helper 源码默写进每页的 run_python** —— 每页只 `import pptx_helpers as P` 然后调用。这样长 deck 里不会出现第 7 页和第 2 页的 `apply_brand` 坐标对不上的漂移,也省 token。配色用 current spec(命名见 SKILL.md §阶段一)里的实际 hex —— 通过 `P.set_palette()` 注入,默认商务红。 -## 通用起手 (每页 run_python 顶部) +## 通用起手(整 deck 单脚本 — 默认路径) + +阶段二写一个 `build_deck.py`,一个进程内建完整份 deck、末尾 `save` 一次(**不逐页 run_python**)。每页一个小函数,主流程按逐页大纲依次调用: ```python import sys sys.path.insert(0, "/scripts") # 用 system prompt 注入的绝对路径替换 import pptx_helpers as P -# —— 第一页(创建 deck)—— -prs = P.new_presentation("16:9") # 默认 16:9;可传 "4:3" / "9:16" / "3:4" -P.set_palette(spec_path="/--.spec.md") -slide = P.add_slide(prs) -# ... 见下面各 L 版式 ... -prs.save("/.pptx") +SPEC = "/--.spec.md" +OUT = "/.pptx" -# —— 后续页(追加到已有 deck)—— -prs = P.load("/.pptx") # 从文件实际尺寸回填画布常量 -P.set_palette(spec_path="/--.spec.md") # 每页都重读 spec -slide = P.add_slide(prs) -# ... 见下面各 L 版式 ... -prs.save("/.pptx") +def page_1_cover(prs): + slide = P.add_slide(prs) + P.apply_brand(slide, "cover") + # ... 见 L1 封面 ... + +def page_2(prs): + slide = P.add_slide(prs) + # ... 见对应 Lx 版式 ... + +# ... 按大纲补齐 page_3 … page_N ... + +def main(): + prs = P.new_presentation("16:9") # 默认 16:9;可传 "4:3" / "9:16" / "3:4" + P.set_palette(spec_path=SPEC) # 整 deck 设一次配色(同进程内常驻) + for build in (page_1_cover, page_2, ...): # 按逐页大纲顺序 + build(prs) + prs.save(OUT) + +main() ``` +跑法:先 `write` 这个脚本到 `/build_deck.py`,再 `run_python(script_path="/build_deck.py")`。要改(quality_check 报错 / 用户要调)→ 改脚本里对应 `page_x` 函数,重跑整脚本(可复现,不 edit 成品 .pptx)。 + +> **风格探针 / 增量补页**:要先看封面 + 1 页观感,把 `main()` 的循环临时缩到前 2 个函数跑一遍,确认后放开重跑;或对已存在的 deck 追加单页时用 `prs = P.load(OUT)` 载入再 `add_slide`(`load` 按文件实际尺寸回填画布常量)。**常规整建不用 `load`**。 + ⚠️ 一律用 `P.xxx`(不要 `from pptx_helpers import *`)—— `set_palette` 靠改模块属性覆盖配色,`import *` 会把旧绑定拷进页面命名空间导致覆盖不生效。 ## Helper API 速查 (都在 `P.` 命名空间下)