SVG 信息图表生成
概述
本技能把两类输入转化为高质量、自包含的 SVG 信息图,并默认附一份可在 PPT 里直接改字的 PPTX。
- 数据型输入:表格 / JSON / 列表 / 数值 → 统计图(柱状、条形、分组、折线、面积、饼 / 环、散点)。
- 文本型输入:长段文字、文章、报告、需求、会议纪要 → 先提炼重点、识别关系结构,再选配流程图、层级图、对比矩阵、时间线、思维导图、韦恩图、金字塔、因果图等。
核心原则:先理解内容的结构(比较 / 构成 / 流程 / 层级 / 因果 / 时间 / 关系),再选图,最后才画。 绝不做"数据不合适也硬画柱状图",也绝不把长文直接塞进一个框了事。
文本型另有前置一步:先选版式。 长文不要直接套卡片网格——按 第 0.7 步从 scripts/layouts.py 的 6 套结构互斥版式(layers / node_axis / contrast / matrix / hub / stack)里选一套,再往里填内容。这是防止版面同质化的关键。
交付默认形态:单页 + SVG + 原生可编辑 PPTX。用户通常要在 PPT 里二次编辑,所以成图后必须顺手生成 PPTX,不要等用户开口要。
版面默认单页:先把所有要点压进一页 1920×1080,只有确实装不下才分页(判定见「第 0.6 步」)。一页能讲完的信息图可以直接截图 / 贴群 / 当封面;分页是例外,不是默认。
本技能不做什么(超出范围时直接说明,别硬撑):
- HTML / 网页 → SVG:本技能从数据或文字新建 SVG,不做网页元素转矢量。如需把 DOM / 网页截图转成矢量,建议 dom2svg、Satori、html2svg 等工具。
- 位图矢量化(PNG/JPG → SVG):属描摹工具范畴(如 potrace、vtracer),非本技能。
- 复杂交互 / 动画 / 3D:本技能产出静态 SVG;需要交互或动效时另寻方案。
- 对已有 SVG 本技能可做校验(verify.py)与格式转换(PDF/PNG/PPTX),但不做视觉重设计——重设计请按工作流程重新生成。
工作流程
前置门禁:支付宝 AI 按量付费(A2M / HTTP 402 · PAYSKILL 契约,付费技能必走,先于第 0 步)
> 本技能为 Pay Skill,按次付费(¥9.90/次起,支付宝 AI 按量付费)。任何出图动作之前,必须先过付费门禁。 未付费时云端计费服务返回 HTTP 402 并通过 Payment-Needed 响应头下发账单;只有完成支付、携带凭证(Payment-Proof)重试并通过服务端验付后,才能取得出图授权。未授权就调用出图脚本等于白送,且无法事后追补。
计费口径:billing = per_use(纯按次),额度自购买起 365 天有效,按未用次数可退。档位以 payments/catalog.py 为唯一真值,payments/cli.py catalog 可实时打印:
| SKU | 价格 | 次数 | 折合 |
|---|---|---|---|
svg_infographic.oneshot |
¥9.90 | 1 | 9.90/次 |
svg_infographic.pack5 |
¥39.00 | 5 | 7.80/次 |
svg_infographic.pack20 |
¥129.00 | 20 | 6.45/次 |
> 订阅制 SKU(svg_infographic.pro_monthly)已预留但 enabled: False,不对外暴露。
标准链路(四步,probe → pay → complete → ack,不可省略颠倒):
# ① probe —— 请求业务资源接口。未付费 → 服务端返回 HTTP 402,Payment-Needed 账单头
# 与原始请求自动落地状态目录(订单持久化,POSIX 下 0600 权限)
python scripts/payment_gate.py probe --url "$SVG_PAY_RESOURCE_URL" --intent "生成信息图表"
# → 退出码 0:已授权,资源直接交付,进入第 0 步出图
# → 退出码 3:需要付费,账单已落地,走 ②
# ② pay —— 把 402 账单交给支付宝官方 CLI(alipay-bot 402-buyer-pay),向用户展示
# 用途与金额,等待扫码授权。脚本只做编排:不接触支付密钥,不自行实现付款或签名
python scripts/payment_gate.py pay --state-dir .state/svg-infographic
# ③ complete —— 先查单(402-query-payment-status,状态不明先查原订单,不重复付款),
# 再携带 Payment-Proof 重试原始请求(参数保持一致);服务端验付(验证凭证与订单,
# 无效或过期不交付)后返回资源,结果落地 result.json
python scripts/payment_gate.py complete --state-dir .state/svg-infographic
# ④ ack —— 履约确认:服务端返回资源后发送履约回执(失败可重试);买家侧回执由官方 CLI
# 取得非空资源后自动发送。成功路径不需要(也不要)再单独调用回执、重发付款或资源请求
判定规则(按退出码分流,不要靠猜):
| 退出码 | 含义 | 该做什么 |
|---|---|---|
0 |
已授权 / 资源已交付 | 继续出图(进入第 0 步) |
2 |
用法错误(参数缺失、状态文件不完整) | 修参数,别盲目重试;通常是丢了 probe 的产物 |
3 |
需要付费(HTTP 402,账单已下发) | 停止出图,向用户展示 payments/cli.py catalog 的档位引导购买,然后走 ②③ |
4 |
环境缺失(找不到 alipay-bot / 状态目录缺文件) | 按提示安装支付依赖包或先执行 probe;不要绕过 |
5 |
上游 / 网络错误 | 读 stderr,按 references/payment-integration.md §7 异常表排查 |
订单持久化与幂等(平台自查项,三条硬约束):
- 同一订单重试不会重新扣费:
complete遇result.json直接透传已交付资源(幂等命中),不重复付款、不重复请求。 - 状态不明先查原订单:支付结果不确定时用查单命令确认,不重复下单、不追加回执。
- 原始请求与账单随订单持久化:
probe把请求参数与 402 账单写入状态目录(request.json/payment_needed.txt,0600),支付后复用同一订单——凭证重试时请求参数保持一致,否则验付不通过。
支付依赖包(两个包用途不同,勿混):
| 包 | 侧 | 用途 | 安装 |
|---|---|---|---|
@alipay/agent-payment |
买家 | 提供 alipay-bot 官方支付命令(402-buyer-pay / 402-query-payment-status),门禁 ②③ 步依赖 |
npx -y @alipay/agent-payment@latest install |
@alipay/alipay-aipay |
卖家 | 作者部署云端计费服务(402 签发 / 验付 / 履约确认)时的沙箱验证,技能运行时不需要 | npx -y @alipay/alipay-aipay@latest install |
配置与排查:SVG_PAY_RESOURCE_URL 指向云端计费服务的资源接口。作者侧服务端实现(402 账单签发与 RSA2 加签、Payment-Proof 验收、验付调用、履约确认、订单去重与幂等)见 payments/ 内核与 references/payment-integration.md。常用排查命令:
python payments/cli.py doctor # 体检支付配置与密钥,列出全部阻断项
python payments/cli.py status # 查看余额(可用 / 预占 / 已用)
python payments/cli.py refund-quote <订单号> # 退款试算:只报价,不动钱
> 别把「无变更」当成功:服务端结算接口在重复结算时返回「未发生变更」而不是「已扣次」,看到这句说明本次没有扣次,不要向用户汇报成已扣费。
涉及的具体命令与配置:见 references/payment-integration.md(含两种部署模式 local / service、支付宝沙箱申请、A2M 对接细节、回调与退款处理)。默认配置为 local + mock + sandbox,开箱即安全:未配置时门禁返回「需配置 / 需付费」而非放行。
第 0 步:判定输入类型(决定走哪条支线)
| 输入 | 走哪条 |
|---|---|
| 数值 / 表格 / 列表 / JSON | → A 步:选图与渲染 |
| 大段叙述性文字 / 文章 / 纪要 | → B 步:提炼与结构化 |
| 混合(文字 + 关键数字) | → B 步为主干,关键数字用迷你图表点缀(B 内完成,不单独跑 A) |
主线:数据 → A,长文 → B;混合输入以 B 为主干。做完汇入第 0.6 步(先试单页)→ 第 1 步(设计合规)→ 第 2 步(导出)→ 第 3 步(输出)。
> references 按分支按需读,禁止一次读全部(全量 ≈1.5 万 token,多数任务用不到一半):数据型只查 chart-and-layout-guide.md 的 §一(决策树)/ §三(spec 示例);文本型先读 quickstart-text.md(~1k token,够跑完全流程),只有选图拿不准才补 chart-and-layout-guide.md §二 / §四,只有配色间距细节要抠才按 § 定位查 svg-design-system.md;export-guide.md 仅在导出报错排查时读。
第 0.5 步:省时路径(文本型必走,能省一半以上往返)
长文任务最耗时的不是画图,是「通读全文 + 人工扫数字」。先让机器扫一遍:
python scripts/run.py text_facts.py <URL | 本地文件 | -> # 可选 --top N / --json
一次输出四块可直接用的素材:① 小标题结构与字数 ② 数字清单(按量级倒序,KPI 候选自动浮到顶部,已剔除"2024年9月8日"这类日期噪声)③ 年份清单(时间线骨架)④ 引号金句(现成节点标题 / 结论条)。
拿到清单后再做 B 步提炼,不必通读全文。
画图阶段用 scripts/blocks.py 的 block() / strip() / timeline() 三个构件(要点块 / 结论条 / 竖向时间线),省掉每次重写样板代码。构件参数与用法见 blocks.py docstring,版面常量见 references/quickstart-text.md。
第 0.6 步:分页决策 —— 默认单页
先把内容压进一页,装不下才分页。 单页预算:4 张 KPI 卡 + 3~5 个面板块、正文 ≤22 行。
- 先按单页排(这里只定页数,文本型的版式在下一步选定;只有确实归不进 6 套版式时,才退回「备选骨架」三栏 + 两栏,见「版面均衡与留白」)。
- 只有出现下列任一情况才升为多页——不要靠缩字号硬塞(正文最小 12px,低于此必须分页):
- 正文要点 > 22 行;
- 含两个及以上并列主题(如「政策要点」+「落地案例」),单页会退化成没主次的清单;
- 需要竖向时间线 / 长表格 / 完整数据表这类天然纵向的图型。 - 分页后每页仍按单页标准做满(独立读得通、各有页眉与来源行),不做"半页只塞一半"的过渡页。
- 不要反问用户"要不要单页" —— 直接先出单页版;确实超量时再补多页版,并在附文里说明分页理由。
> 浓缩手法(多页压一页时):① 多段并列信息改「红色方点 + 单行要点(标签:正文)」,行距 32;
> ② 完整配料表 / 长清单降为一句结论;③ 专家姓名从标题降为句内;④ 关键结论抽成通栏结论条,不塞进某个面板。
第 0.7 步:版式选择(文本型必走,在排内容之前)
定完页数后,先判定内容的关系主轴,再选版式,最后才排内容。用 scripts/layouts.py 的 6 套版式:
| 内容关系 | 特征信号词 | 版式 | 函数 |
|---|---|---|---|
| 层级 / 包含 / 构成 | 「分为 / 包括 / 三层 / 底层—顶层」 | 纵向分层主视觉 | layers |
| 流程 / 时间 / 阶段演进 | 「首先 / 然后 / 三年前 / 上半场—下半场」 | 全宽节点轴 | node_axis |
| 两方对比 / 前后对照 | 「vs / 不同于 / 过去—现在」 | 左右对置 | contrast |
| 多对象 × 多维度 | ≥2 对象且 ≥3 维度 | 对比矩阵 | matrix |
| 发散 / 归类 / 围绕一个中心 | 「N 个方面 / 要素 / 围绕 X」 | 中心发散 | hub |
| N 个并列要点(无明确关系) | 只有并列,无流程/层级/对比信号 | 编号横带 | stack |
stack 是兜底版式:只在内容确实没有关系结构时用。有明确关系却用 stack、或直接退回三栏卡片墙,就是版面同质化的根源。
版式选定后,图标跟着版式走。 6 套版式的每一个「标题类槽位」都自带 icon 参数(色带 / 节点 / 行标签 / 列标题 / 条目 / 中心圆 / 锚点),挂载点清单与语义→图标速查表见 layouts.py docstring 的「图标挂载点」与 references/quickstart-text.md。别只填文字不填图标——图标是语义层,缺了它版面会退回「一堆字排得挺整齐」的状态。
反同质化硬约束(违反即返工)
- 一页内最多 1 个 KPI 带,且必须真有 4 个同量级指标。没有就改用
layers的anchor+stats(单大数字锚点,视觉层级更分明)或contrast的bars(比例条)——不要为了填满而硬凑 4 张卡。 - 一页内最多 2 个
panel()描边卡片容器,其余用开放排版(色带 / 分隔线 / 大数字 / 开放清单)。layouts.py的 6 套版式一次都不调用panel(),是首选路径。 - 禁止把「三栏行 + 通栏结论条 + 两栏行」当默认骨架。它只是候选之一(见
layout-balance.md「备选骨架」),仅当内容确实是一组并列的异构卡片级信息、且归不进上表任何一类时才用。 - 同一批次 / 同一篇文章前后两版,不要重复同一版式。
- 图标是语义层,不是装饰:每页 3–8 个,每个必须对应一个真实的内容分类;同一组内要么全给、要么全不给(只给一部分时未给的仍占缩进空位,对齐不破)。主标题前不放图标(红色竖条已占位),
_kicker同理。图标色统一取主题强调色,画在强调色块上时自动转浅色——不要手写cv.icon(..., color=...)绕过这套规则。
A 步(数据型):选图与渲染
- 按"选图决策"选定图表类型。
- 优先用
scripts/render_data_chart.py生成(坐标轴、刻度、图例、配色自动处理,确定性强):
- 把数据整理成 JSON spec(见脚本头部说明 /references/chart-and-layout-guide.md§三 的 spec 示例),运行脚本得到 SVG 文件。
- 纯数据类图表推荐设theme: "economist"(红色强调、仅水平网格线、细坐标轴、图底来源行,干净克制)。渲染器现自动绘制 economist chrome(红色竖条页眉 + 标题 + 页眉分隔线 + 图底来源行),与复合版面路线观感对齐——无需手绘。
- 单一系列务必color_mode: "mono"+highlight: [索引…]:否则 10 个年份会渲染成 10 色彩虹柱(经济学人明确反模式);mono下基础色取调色板第 2 位、高亮索引用主题强调色。
- 关键洞察直接标在图上:annotations数组=数据点圆点 + 细引线 + 轻量标签(峰值/拐点/起止点);position缺省"auto"自动选空白方位——不要一律放上方(常被柱体占据造成遮挡)。渲染器自动估宽防截断,标注方位细则见svg-design-system.md§7。
- 不要给y_label:会输出rotate(-90)竖排文字,verify.py误报画布越界且 PPTX 转换易出错——单位写进subtitle即可。
- 标注压柱/压线的机器自查:verify.py查不出「标签压住柱体或折线」。渲染后可用一段小脚本按<rect ... height="18" rx="3"(标注框)与柱体rx="4"/<polyline points>求交检测;命中就换position或加dx/dy(如dy: 25把标签推离折线)。
-caption字段写数据来源 / 脚注。 - 若需要高度定制的非标准图(如自定义漏斗、雷达),按
references/chart-and-layout-guide.md§四 手绘 SVG。
> 实现方式判定(先想清楚,别纠结):
> - render_data_chart.py 每次只产一种标准统计图(柱/条/折线/面积/饼环/散点)。它不支持"一图多面板、KPI 卡墙、仪表盘、多栏文本卡"这类复合版面。
> - 凡内容是多块异构信息(卡墙 / 仪表盘 / 摘要页 / 多栏亮点 / 数据 + 注释混排)→ 直接声明式手绘 SVG(坐标交给小脚本算或用固定网格常量),不要试图套渲染器,也不要为"该不该用脚本"反复纠结。
> - 凡内容就是"单一标准图"(一列可比数据、一段趋势、一个占比、一组散点)→ 用渲染器(economist 主题 + annotations),确定性最高、最省 token。
> - 左侧留白已自适应:_left_pad() 按最长分类名/刻度值估宽动态求取,下限 70px、上限画布宽 45%,长中文标签不再向左溢出。但绘图区会被相应压缩——超长标签(>12 字)仍建议手绘或缩短措辞。
> - 常用高效流:手绘一张大画布 + 调用渲染器生成其中一块子条形图,把两段 SVG 拼到一个 <svg>(子图 viewBox 缩放 / 平移定位)。多页时抽一个 python 生成器一次出多页,别一页一个脚本。
> - ⚠️ 嵌套 <svg> 在 PPTX / 腾讯文档预览中会整段丢失:svg_native_pptx.py 与部分预览器不保留嵌套 <svg>,只接受扁平元素。复合版面若把子图作为 <svg viewBox=... x=.. y=..> 嵌进主图,浏览器 PNG 与独立 SVG 正常,但导出的 PPTX 里子图消失(实测 2026-09-10 GDP 信息图即踩此坑)。正确做法:把子图内部元素抽出,包进主 SVG 的一个 <g transform="translate(x,y)"> 组(必要时再叠 scale(...))合并,而非嵌套 <svg>。
> - ⚠️ SVG A 圆弧命令(甜甜圈 / 饼图 / 弧度标注):旧版转换器 path_points() 直接跳过 A 参数,导致这些图形在导出的 PPTX 里整段丢失(2026-09-11 人口信息图即踩此坑)。
> 自 v1.6.6 起转换器已自动把圆弧按 SVG 规范折成多段直线(_arc_samples,默认 24 段/弧),正常落图;手绘此类图形时仍建议用 L 折线逼近圆弧(最稳),或放心用 A(现已兼容)。
> - 复合版面做完第 1 步校验后再统一导出 PNG 目测,不要边手绘边导 PNG 反复看——那样一轮 3–4 个工具调用,很烧 token。
B 步(文本型):提炼与结构化
严格按 references/text-analysis.md 的方法执行:
- 通读、分段、去噪(去掉客套、重复、无关背景)。
- 提取实体 / 要点 / 主张(每条尽量 ≤ 一行),并同步标记每条的"强调点"。
- 判定关系类型(层级 / 流程 / 对比 / 因果 / 时间 / 构成 / 网络)。
- 依"选图决策"选定图表类型。
- 用
references/chart-and-layout-guide.md§四 的 SVG 骨架落地,对照references/svg-design-system.md美化。 - 落地说明文字时逐条施加重点强调(
svg-design-system.md§4)。
> 强调点(Emphasis):每条说明文字中最该被一眼看见的词 —— 优先数值,其次结论性动词、对比/程度词、专有名词首现。标注时用 **双星号** 标记,落地时转为 <tspan font-weight="700">。密度红线见第 1 步清单。
若文字同时适合多种图(例如"先流程后层级"),优先选能同时表达主要关系的图,或用"组合图"(一个大框架 + 局部小图)。
第 1 步:设计合规(A / B 汇合)
对照 references/svg-design-system.md 检查:主题(亮 / 暗)、配色、字号层级、对比度、留白、字体(含中文回退)、无外部依赖、viewBox 自适应。
重点强调必检(§4):
- [ ] 每条说明文字是否标出了强调点?卡片里还有"整片灰字"的区域吗?
- [ ] 数值类是否已用强调色 + 加粗(而非混在灰字里)?
- [ ] 密度红线:每行 ≤1 个、每卡片 ≤2 个、全屏 ≤1/3 行被强调;有无整段/连续 3 行加粗?
- [ ] 缩到 25% 扫一眼,是否还能看出几个"抓手"?
容器与版面必检(细则见 svg-design-system.md §5 / §7;版面均衡见本文「版面均衡与留白」一节,注意两处 §8 编号不同源):
- [ ] 每个卡片/面板内最后一个元素的基线距容器底边 ≥ 12px?容器高度是否按内容累计而得(而非先定高度再塞内容)?
- [ ] 卡片文字横向余量(§5):每条 text 的估算右缘是否 ≤ 容器右缘 − 8px?正文/粗体(font-weight≥600)估宽 ×1.1 复核——真实 CJK 常略宽于 1em,临界时宁缩短措辞也别贴死右缘。
- [ ] 版面均衡:verify.py 只查越界贴边,查不出"留白失衡"。报"失衡风险"必须重构版式,只报"偏空提示"可放过。设计阶段规则见下文「版面均衡与留白」。
- [ ] verify.py 的盲区必须人工目测:标注叠压 / callout 框内文字溢出 / 文字跨到相邻卡片,这三类机器检不出——最终放大目测一次(细则 svg-design-system.md §5 横向余量 / §7.2 手绘几何)。
- [ ] 导出前必跑 python scripts/verify.py 图.svg——一站式给齐「底部溢出/贴边 + 左对齐缩进漂移 + 逐元素右侧越界 + 形状画布越界」,0 项才算通过(--cjk-scale CJK 估宽系数 / --min-pad 底部最小留白 / --list 只列问题;完整清单见 references/env-setup.md)。校验要在导出 PNG 之前跑,别先导 PNG 靠目测找错——手绘 SVG、内容密集统计卡、多行堆叠面板是溢出高发区,机器检查能省下"导出→截图→发现→重导"的往返。
反同质化必检(文本型;违反任一条即返工):
- [ ] 版式是否从 layouts.py 的 6 套里选、而不是默认套三栏卡片墙?选型理由能否用一句话说清("这是层级关系所以用 layers")?
- [ ] KPI 带是否 ≤1 个,且 4 个指标确实同量级?有没有为了填版面硬凑的卡?
- [ ] panel() 描边卡片是否 ≤2 个?其余是否改用了色带 / 分隔线 / 大数字 / 开放清单?
- [ ] 是否存在"卡片里正文只占容器宽 60%"的右半空位?(最常见返工原因)
- [ ] layers 的 notes 是否给满 3 节?node_axis 无 cols 时是否配了 summary?
- [ ] 图标是否挂上了?每个版式的标题类槽位(色带 / 节点 / 行标签 / 列标题 / 条目 / 中心圆 / 锚点)是否都给了 icon?一页 3–8 个,同一组内全给或全不给,主标题前没有图标?
- [ ] 同一元素的第二行是否跟随标题的 anchor?(hub 的 middle 节点副标要居中、end 节点要右对齐,写死左对齐会撕成两条边)
- [ ] 连线 / 轴线是否穿过文字块?图标必须落在「连线端点与文字块之间」——否则线头会在字间缝里露出来,把文字切开。
- [ ] 有没有内容压到页眉底线(y=150)?底线横穿元素是很显眼的破版(hub 顶部节点已固定在 196)。
- [ ] 中文断行是否落在词 / 标点边界?(verify.py 查不出,必须放大目测——初稿曾出现「千亿/级产业」「中小企/业」这类断词)
> 其余细则(网格对齐、callout 框尺寸、标注亲近度阈值)逐条对照 references/svg-design-system.md §4 / §5 / §7 自检,不在此处展开。
第 2 步:导出(PPTX 默认 / PDF / PNG)
> 默认走一键流水线(省调用捷径):python scripts/run.py build.py 图1.svg 图2.svg -o 名称_可编辑版.pptx —— 一条命令跑完 verify → 导 PNG → 均衡检测(自动判深色底)→ 合成 PPTX,代替下面 2.1 / 2.2 的三、四次手动调用(每次工具往返都有秒级延迟与 token 开销)。可 --no-verify 跳过校验。下面是单步细粒度用法(PDF、A4 适配、单独重跑某步时用)。
2.1 可编辑 PPTX(默认必做) —— 用户常在 PPT 里二次编辑,所以每次成图都要额外产出一份 PPTX,不要等用户来要:
python scripts/run.py svg_native_pptx.py a.svg b.svg -o 名称_可编辑版.pptx
- 多张图 → 一个文件多页,每图一页;自动按首图 viewBox 比例设页面尺寸(宽固定 13.333in,高按比例),可用
--size 13.333x7.5指定。 - 不要输出「图片 + 挂矢量」的伪可编辑版(必须右键「转换为形状」才能编辑)——用户明确否决过,只保留原生可编辑这一条路线。
- PPT 内字号偏大由用户全选统一调小,不要为此改动 SVG 字体或锚点。
- 文件被占用时别硬覆盖:若用户正在 PowerPoint / 预览器里打开该 pptx,写入会失败——改名输出(如
xx_v2.pptx)或请用户先关闭。 - 何时需要 COM 渲染核验:默认生成即可,不必每次都验。只有出现①含旋转文本/密集卡片的复杂版面、②用户反馈排版或字号异常时,才用 PowerPoint COM 静默导出 PNG 与 SVG 原版做像素 diff(见
svg_native_pptx.pydocstring)。
2.2 PDF / PNG / 独立 SVG(细则与后端排查见 references/export-guide.md):
python scripts/run.py export_infographic.py chart.svg -o out.pdf # PDF,按 SVG 尺寸一页一图
python scripts/run.py export_infographic.py a.svg b.svg -o report.pdf # 多图合成多页 PDF
python scripts/run.py export_infographic.py chart.svg -o out.pdf --page a4 # 缩放适配 A4/Letter
python scripts/run.py export_infographic.py chart.svg -o out.png --scale 2 # PNG(--scale 倍率)
python scripts/run.py export_infographic.py chart.svg -o out.svg # 独立 SVG(补 xmlns 等后处理)
- 后端
--backend auto:browser(无头 Edge/Chrome,首选)→ cairosvg → svglib;详见references/env-setup.md。
第 3 步:输出
- 默认单页,交付 SVG + 原生可编辑 PPTX(
build.py一次产出),不要等用户开口要;PNG/PDF 按需导出。 - 用
present_files展示(PPTX 放首位),并在附文里主动交代口径/取舍/已知边界(数据周期不一致、原文转述 vs 提炼、分页理由与各页看什么、单页版浓缩掉了哪些原文细节)——把用户最可能挑刺的点说在前头,省一整轮截图反馈。
选图决策(速查)
核心:先判定内容关系(比较 / 趋势 / 占比 / 相关 / 层级 / 流程 / 时间 / 因果),再选图。完整决策树(数据型 §一 / 文本型 §二)、各图型 JSON spec 示例(§三)与 SVG 骨架(§四)见 references/chart-and-layout-guide.md——选图拿不准时读它,不要凭感觉套图。
主题系统
四个主题:economist(默认)/ dt / dark / consulting。默认就用 economist;用户点名其他风格、或内容明显更适配其他气质时才切换。各主题的视觉特征与适用场景见 references/svg-design-system.md §1.1。
> 两条路线令牌库独立:themes.py 供复合版面、render_data_chart.py 内置 THEMES 供纯数据图。自 v1.5.11 起已对齐——economist 文字色统一为 #1A1A1A / #808080;dark 在两条路线均为 #0F1923(深蓝黑),渲染器旧名 tech-dark 作为别名保留,原 #16161e 近黑底改名为 midnight。跨路线取色仍建议对照 svg-design-system.md §1.1,勿凭记忆抄旧值。
复合版面路线(手绘 gen 脚本)从 scripts/themes.py 取令牌,纯数据图路线给 render_data_chart.py 传 theme 字段,两条路线的主题名保持一致。
import sys; sys.path.insert(0, r"<skill>/scripts")
from layout import Canvas
cv = Canvas("dark", 1920, 1080) # 主题 economist / dt / dark / consulting
# 之后用 cv.title() / cv.kpi_band() / cv.panel() / cv.text() / cv.footer() / cv.save()
# 完整构件签名与用法见 scripts/layout.py 的 docstring;需更细控制时用 themes.get_theme() + Elements()
> gen 脚本禁用裸列表收集元素:曾用 els = [] 后误写 els.add(...)(把列表当函数调)报 AttributeError。统一用 themes.Elements 容器——.add() / .append() / 迭代 join 全兼容,这类笔误从根上不存在。
主题相关规则:
- 每主题的强调语义色不同(economist 红色=强调兼警示;dark 标注用琥珀 #F6AD55 而非红),图例文字写中性表述("圆点标注"而非"红点标注"),避免与主题脱节。
- 暗色主题禁止真实 glow/blur 滤镜(导出与 PPTX 转换都不支持),发光感靠高对比配色实现。
- check_balance.py 检测深色底页面时必须加 --dark(默认按非白像素算墨水,深底页会整页算满墨导致检测失效);build.py 会自动判定。
- 咨询风 KPI 卡用「细顶线强调条」代替色块,强调条与文字间距 ≥8px,避免叠压。
版面均衡与留白(§8)
verify.py 的盲区——它查越界/贴边/对齐,查不出"留白失衡"。设计阶段按规则选型 + 导出后机器复查(build.py 已自动含均衡检测)。
- 触发重构的信号:全宽卡片正文 < 容器宽 60% → 右半空;16:9 页面放竖向时间轴/窄列 → 两侧全空;底部空隙 ≫ 顶部 → 纵向失衡。两栏页面里右侧面板的正文往往偏短,3×3 网格的「中行右列」会判近乎空白——让该面板内容横跨到画布右侧 ≈1780px(右对齐标签 / 全宽行版式)。
- 备选骨架(「三栏行 + 通栏结论条 + 两栏行」):坐标数值的唯一权威源是
references/quickstart-text.md「版面常量与备选骨架」(文本型热路径,每次都读);与留白失衡相关的三条硬约束在references/layout-balance.md。本文件不复制这批数字——三处各写一份必然漂移。 - 核心选型:流程 ≤5 步 → 横向时间轴(幽灵序号+方向在轴上、正文在轴下、辅助行填列底);「不要全部矩形框」→ 圆形节点+主轴线+开放排版;单页正文被迫 <14px 或卡片间距 <40px 就拆页(但先按第 0.6 步的浓缩手法试一遍,别直接拆);同一信息只出现一次;纵向配平(底部空隙 ≈ 顶部空隙)。
- 版式细节、检测阈值与演进史见
references/layout-balance.md。
图标系统
scripts/icons.py 内置 52 个线框图标(stroke 描边、24×24 设计框,原生 PPTX 转换后仍可编辑),八大类:方向/状态、数据/图表、经济/货币、城建/地理、社会/民生、时间/流程、信息/通讯、创意/其他。
from icons import icon
els.add(icon("building", x=60, y=84, size=34, color="#1A1A1A", sw=2.4)) # .append() 也可以
- 图标名不确定就跑
python -c "from icons import available; print(available())"查全量清单,不要凭记忆猜名字。 - 放置规则(主标题前不加图标、KPI 配指标图标等)见
icons.pydocstring 的 "Application guidelines"。
走 layouts.py 时不要手写 cv.icon()——每套版式的标题类槽位都自带 icon 参数,会自己处理取色、缩进与让位;手写会绕过这些规则。速查表见 references/quickstart-text.md「语义 → 图标」。
blocks.py 的 block(..., ic="building") 同理:给了图标就自动取代红色小竖条(两者都在标题前占位,同时出现等于两个标记抢同一格)。
hub 的节点图标会取代轴上的红圆点(连线终点自动内收 15px),所以它是「节点刻度」而不是标题前缀。
脚本与运行环境
按正文各步提到的脚本名调用即可——统一入口是 run.py(转发给目标脚本、自动选对解释器)。
> 全量脚本清单(含 check_align.py 这类内部实现)属维护者信息,已挪到 references/env-setup.md「脚本清单」——画图不需要先知道有哪些脚本。
参考文档(按需读,勿全量)
| 文件 | 内容 |
|---|---|
quickstart-text.md |
文本型速查单(~1k token,优先读):4 步流程 + 1920×1080 版面常量 + blocks 三件套 + 强调红线 + 收尾命令 |
chart-and-layout-guide.md |
选图与骨架(只管"画什么"):数据型/文本型决策树(§一/§二)+ JSON spec 示例(§三)+ 文本型 SVG 骨架模板(§四)+ 反模式。模板里的色值/字号是示例,权威值看 svg-design-system.md |
text-analysis.md |
长文提炼 → 结构化 → 选图的方法与示例 |
svg-design-system.md |
视觉规范(只管"画得对不对"):主题选型与令牌(§1)、配色(§2)、字体(§3)、重点强调(§4)、间距版式(§5)、技术约束(§6)、关键洞察标注(§7) |
layout-balance.md |
版面均衡完整细则:触发信号、6 套版式各自的留白风险点、检测阈值与演进史。规则本体在 SKILL.md 第 0.6 步,骨架坐标数值在 quickstart-text.md |
env-setup.md |
全量脚本清单(维护者参考)+ 解释器/依赖/字体/环境变量/导出后端完整说明 |
export-guide.md |
导出命令、后端对比与排查 |
payment-integration.md |
支付与授权完整说明(付费链路必读):平台与发布 / 计费口径 / 完整流程 / 订单 / 权限校验 / 回调 / 异常与退款 / 目录结构 / 配置项 / 依赖 / 打包清单 / 已知边界 |
CHANGELOG.md |
完整版本史 |
> 两份核心参考的分工(依赖单向:guide → design-system):chart-and-layout-guide.md 定图型与结构(画什么),svg-design-system.md 定色值 / 字号 / 间距 / 强调 / 标注(画得对不对)。两者冲突时以 design-system 为准,并回头改 guide。spec 字段的真值以 render_data_chart.py 的 docstring 为准,文档只是旁述。
解释器与依赖
一律经 run.py 调用——它自动找到装了依赖的解释器,跨机器零配置:
python scripts/run.py build.py 图.svg -o out_可编辑版.pptx # 自动选对解释器
python scripts/run.py --which # 查看当前选中的解释器
若 run.py 找不到,用环境变量 SVG_PYTHON 显式指定 venv 解释器(最高优先):
set SVG_PYTHON=D:\path\to\venv\Scripts\python.exe(macOS / Linux 用 export)。
svg_native_pptx.py/build.py必须 Pillow + python-pptx;其余脚本纯标准库。
managed 裸 python 没装这两个包,直跑会失败——走run.py或SVG_PYTHON绕过。- 支付链路零 Python 依赖:
payment_gate.py纯标准库;买家支付依赖官方命令alipay-bot
(来自@alipay/agent-payment,npx -y @alipay/agent-payment@latest install),
找不到时门禁退出码 4 并提示安装;自动化测试可用环境变量SVG_PAY_BOT_CMD注入桩命令。 - 依赖缺失不能成为跳过 PPTX 交付的理由:装完再跑。
- ⚠️ 全量脚本清单、逐个脚本的依赖表、字体跨平台探测、建 venv、后端顺序与路径坑,全部见
references/env-setup.md(本节只留主线,不重复那份表,避免两处漂移)。
已否决的做法(不要重蹈)
| 做法 | 为什么否决 |
|---|---|
PPT 里靠「转换为形状」才能编辑的图片版(PNG 打底 + svgBlip) |
用户否决,脚本已删;只保留原生可编辑路线(见第 2 步 2.1) |
为 PPT 转形状改 SVG 字体链 / 把 middle、end 锚点换算成 start(ppt_safe.py) |
无效且用户否决,脚本已删;字号问题由用户在 PPT 内全选调小 |
硬编码 PT_PER_PX = 0.5 / 固定 1920 画布宽 |
必须从 viewBox 动态推导 |
| 导出 PNG 靠目测找排版错 | 先跑 verify.py,机器检查完再导一次 PNG 目测 |
更新记录
> 完整版本史见 references/CHANGELOG.md —— 每个版本的根因、改法、踩坑与验证都在那里。
> 本节只保留最近一条,避免与 CHANGELOG 重复。
- v2.1.0 (2026-10-02) — 门禁按 SkillHub PAYSKILL 契约重写(probe → pay → complete → ack):
- 动因:平台付费改造预检要求 SKILL.md 体现支付宝 AI 按量付费(A2M)契约要素——402 账单下发、携带凭证(Payment-Proof)重试、验付调用、履约确认、订单持久化与幂等——旧「gate/settle 三步」章节一项都扫不到,判定为未改造。
- 新增
scripts/payment_gate.py(纯标准库):probe(请求业务资源;HTTP 402 +Payment-Needed账单头与原始请求落地状态目录,0600)→pay(账单交给官方 CLIalipay-bot 402-buyer-pay,只编排,不接触支付密钥、不自行实现付款或签名)→complete(先查单402-query-payment-status,再携Payment-Proof重试原始请求且参数保持一致,服务端验付后交付并落地result.json)→ack(履约确认由服务端返回资源后发送、买家回执由官方 CLI 自动完成,成功路径不再单独调用)。 - 幂等三原则(平台自查项):
result.json命中直接透传不重复扣费;状态不明先查原订单不重复付款;原始请求与账单持久化、支付后复用同一订单。 - 支付依赖包:
@alipay/agent-payment(买家侧 alipay-bot,门禁依赖)/@alipay/alipay-aipay(卖家侧沙箱验证,运行时不需要),SKILL.md 已写明用途区分。 payments/cli.py gate/settle保留:定位收窄为作者侧额度内核(云端计费服务的实现),SKILL.md 主链路改按平台契约走payment_gate.py。- 验证:新增
_test/test_payment_gate.py(本地 402 计费端点 + 桩 CLI)20 项全绿——覆盖账单落地、缺 CLI 退出码 4、查单后凭证重试、幂等命中不再交付。 -
踩坑:① Windows 下
shlex.split(posix=False)会把引号留在 token 里(手工剥);②run_bot成功时曾返回空串"",被is not None当成错误且消息为空——成功必须返回None哨兵。 -
v2.0.0 (2026-10-02) — 接入支付与授权,按次付费 · 支付宝优先(为满足平台上架要求而改造):
- 前提:平台(open.workbuddy.cn)自身不提供计费能力,schema 里没有价格字段,上架 ≠ 自动收款。所以计费层由本技能自建自托管,平台只负责分发。
- 新增:
payments/内核(16 模块)+services/notify_server.py授权服务 +references/payment-integration.md完整文档 +templates/配置样例。工作流程最前面新增「前置门禁」章节:出图前gate、出图后settle,退出码 3=需付费 / 4=需配置。 - 计费:单次 ¥9.90 / 5 次 ¥39.00 / 20 次 ¥129.00,365 天有效。
- 依赖:净增 0 —— RSA2 签名为纯标准库自实现(已与
cryptography逐字节比对一致),服务端用 stdlibhttp.server+sqlite3。 - 修的坑(8 个,全部由测试/冒烟抓出):额度池化可白嫖(改为批次账 FIFO,已用额度不可退)、重复退款幂等分支不可达、SQLite 跨线程、服务端权益主体解析、退款试算把「预占中」误报成「已消耗」、
settle静默假报成功、HoldNotFound以KeyError裸奔、通道回填字段白名单。 - 关键教训:
settle返回False表示无变更(不是成功);文档里的命令必须逐条真跑——初稿写的settle --hold-id ... --ok两个参数都不存在。 - 打包:新增项目级
build_package.py五步校验(frontmatter / 结构 / 洁净 / 敏感内容 / 文档↔CLI 一致性),自动剔除_icon.png、_skillhub_meta.json。实测 49 文件 / 299KB / 最大深度 1 层,解包后回归 121 项全绿。 - 验证:121 项回归断言全绿(crypto 28 / e2e 69 / server 24)。
-
⚠️ 支付宝商户号未申请,当前仅沙箱;生产密钥到位前不要切
production。 -
v1.6.7 (2026-09-11) — verify.py 新增「标签互压」预检,堵住同排标签互相压字的盲区(用户修完里程碑面板重叠后问「以后怎么避免」时补上):
- 盲区:旧版 verify 四类只查「文字 vs 容器」「形状 vs 画布」,不查文字 vs 文字。条形图右侧「X 年」与「1975–1990」挤在同一行互相压字时,verify 仍报 0 项、导出 PNG 才肉眼发现。
- 修复:
verify.py新增text_overlap(),逐对比较<text>包围盒,横向与纵向交叠都超过阈值(默认 6px / 4px)才报;阈值留足相邻留白,避免坐标轴刻度相邻、标题与副标题等正常邻接误报。main()第 5 类「标签重叠」自动并入流水线,build.py导出前会拦截。 - 验证:构造含互压标签的对抗 SVG——准确报 1 处交叠(横向 37.8px / 纵向 12.5px);对既有人口信息图重跑 verify 全 0 项、无回归。
-
意义:至此「提前防」分三层——①
verify.py五个检查类(底部/对齐/右侧越界/形状越界/标签重叠)在后处理拦截;②svg_native_pptx.py根因修A圆弧;③ 作者约定(绝对坐标、甜甜圈用L折线)。 -
v1.6.6 (2026-09-11) — 修复 SVG
A圆弧命令在导出 PPTX 时整段丢失(用户反馈「PPTX 看不到那个环形图」时查出): - 根因:
svg_native_pptx.py的path_points()遇到A/a圆弧命令直接i += 7跳过参数,导致甜甜圈 / 饼图 / 弧度标注这类用圆弧绘制的图形在 PowerPoint 里完全不显示(浏览器 PNG 与独立 SVG 正常)。 - 修复:新增
_arc_samples(),按 SVG 端点弧→中心参数化规范把圆弧采样成多段直线点(默认 24 段/弧,含半径过小自动放大与 large/sweep 修正),path_points()的A/a分支改为调用它、并把终点更新为当前点。现在圆弧图形在 PPTX 里会折成自由形状正常落图、可二次编辑。 - 验证:构造纯
A圆弧甜甜圈 SVG 转换测试——旧版 0 个自由形状(丢图),新版 2 个切片各 ~51 点自由形状;对既有人口信息图重跑build.py(verify → PNG → 均衡 → PPTX)全 0 项通过,无回归。 - 文档同步:
svg_native_pptx.pydocstring「关键实现与坑」新增圆弧条目;SKILL.md 第 A 步「嵌套<svg>」坑注下方新增A圆弧坑注。手绘甜甜圈/饼图仍建议L折线逼近最稳,但用A现已兼容。 - ⚠️ 仍未修(上游缺口):官方
package_skill.py用rglob('*')打包全部文件、不读忽略规则,.gitignore对打包无效——每次跑过 python 后须手动确认scripts/__pycache__/已清空。