skills/ppt-station-skill/SKILL.md
wangyitong a65adcc2e5 Initial commit: merged, deduplicated, and vetted skill collection
Sources: extracted from two upstream archives (skill-repo, skills-main),
merged with the following policy:

- 15 broken symlinks (pointing to /Users/jameslee/.cc-switch/skills or
  ../../.agents/skills on a foreign machine) discarded
- 3 real name collisions with identical content (ai-pair, ifind-http-api,
  zhipu-websearch) kept as one copy
- Functional overlaps deduped keeping the strongest variant:
  - docx family: kept docx (official, full toolchain) + docx-cn
    (GB/T 9704 Chinese official-document constants),
    dropped docx_writer (no scripts, name collided with docx)
  - humanizer family: kept humanizer-zh (6 zh reference docs),
    dropped humanizer (en, redundant for CN workflow)
- Skills that only ran in a foreign environment removed:
  ablemind-ops, app-publish, hlb-design-system, openclaw-adj-skill,
  claude-driver
- alphapai excluded from this public repo because its SKILL.md hard-coded
  live credentials

Result: 25 skills, 572 files, ~7.5 MB.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:47:12 +08:00

362 lines
17 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
name: ppt-station
description: "PowerPoint 数据报告自动化工具包。从结构化数据CSV/Excel/Tushare/MCP生成带图表的专业金融报告 PPT。支持 12 种页面布局、10 个主题(含研究级 morningstar/macro_research、10 种图表配色、6 种日期轴预设、4:3/16:9 双比例。内置投行级设计规范、ChartJunkCleaner 自动清洗图表样式、投行级表格(无垂直边框/数值右对齐、DeckLinter 合规审计、结论先行 insight 插槽。当用户需要创建、修改、分析 PowerPoint 演示文稿或需要从数据生成图表报告时触发。Do NOT trigger for: 非 PPT 格式PDF、Word、纯数据分析不涉及 PPT 输出。"
---
# PPT-Station
项目根: `./`(即 `skill/` 自身;`skill/ppt_station` 是 symlink → `../ppt_station`,始终与主代码同步)
## 工作流路由
| 需求 | Flow | 入口 |
|------|------|------|
| 模板+数据→PPT | A | `scripts/generate_ppt.py` — [workflow-template](reference/workflow-template.md) |
| Job JSON 声明式编排(模板) | B | `scripts/run_job.py` — [workflow-engine](reference/workflow-engine.md) |
| 解析→编辑→重建已有PPT | C | `scripts/parse_ppt.py` + `rebuild_ppt.py` — [workflow-parse-rebuild](reference/workflow-parse-rebuild.md) |
| 数据+布局声明→PPT | D (推荐) | `scripts/render_ppt.py` + Composer Job JSON |
原子工具:
- `scripts/fetch_data.py` — 数据获取datasources JSON → CSV
- `scripts/validate_job.py` — Job JSON 校验schema + 布局 + datasource/source 引用)
- `scripts/render_ppt.py` — PPT 渲染Job JSON → PPT
- `scripts/validate_ppt.py` — PPT 合规审计DeckLinter CLI 入口)
通用工具: `scripts/parse_template.py`, `scripts/describe_chart.py`, `scripts/list_presets.py`, `scripts/add_placeholders.py`
---
## Flow D 快速示例Composer Job JSON
```json
{
"mode": "composer",
"theme": "jp_finance",
"aspect_ratio": "16:9",
"default_layout_config": {
"legend_config": {"font_size_pt": 9, "font_name": "黑体"},
"value_axis_config": {"font_size_pt": 9, "font_name": "黑体"}
},
"datasources": {
"revenue": {"type": "csv", "path": "data/revenue.csv"}
},
"pages": [
{
"layout": "title_dark",
"data": {"title": "安克创新竞争壁垒分析", "date": "2026-02"}
},
{
"layout": "kpi_cards",
"data": {
"title": "核心指标",
"footnote": "来源: Wind, 公司年报",
"cards": [
{"label": "营收", "value": "247亿", "change": "+41%"},
{"label": "净利润", "value": "32亿", "change": "+55%"}
]
}
},
{
"layout": "chart_full",
"data": {
"title": "营收与利润趋势",
"source": "revenue",
"categories_col": "年度",
"series_config": [
{"key": "营收", "name": "营收(亿元)", "type": "bar", "axis": "primary"},
{"key": "净利润", "name": "净利润(亿元)", "type": "line", "axis": "secondary"}
],
"footnote": "来源: Wind, 公司年报",
"layout_config": {
"value_axis_config": {"number_format": "#,##0"}
}
}
}
],
"output": {"path": "output/anker_moat.pptx"}
}
```
**关键字段说明**
- `aspect_ratio`:幻灯片比例 `"16:9"`(默认)或 `"4:3"`,影响所有布局的宽高计算
- `default_layout_config`Job 级图表布局默认配置所有图表页继承per-page `layout_config` 只写差异项(浅合并覆盖)
- `footnote`:页脚来源文本,所有非封面/结论布局均自动渲染为页脚
- `source`:在图表页中作为 datasource 引用(值匹配已知数据源时),在非图表页中保留为脚注文本(兼容回退)
- `datasource`(新 canonical key明确的 datasource 引用,推荐在 left/right 嵌套中使用
- `style_config` 不再必需 — 使用 `jp_finance` 主题时,图表自动使用 `jp_finance` 配色方案
**原子工具工作流**
```bash
# 1. 获取数据
python scripts/fetch_data.py --config datasources.json --output data/
# 2. 校验 Job JSON
python scripts/validate_job.py job.json
# 3. 渲染 PPT
python scripts/render_ppt.py job.json
```
**仍需手写 Python 的场景**add_custom_page自定义布局不在 LAYOUT_REGISTRY 中时
---
## API 合约(编码前必读)
**完整函数签名、参数类型、所有布局数据接口**[reference/api-contracts.md](reference/api-contracts.md)
关键要点速查:
```
create_combo_chart(slide, df, categories_col, series_config,
position=(left, top), size=(width, height), ...)
series_config = [{"key": "列名", "name": "显示名", "type": "bar|line|area", "axis": "primary|secondary"}]
ChartLayoutConfig(..., date_axis_config=MONTHLY_TICKS) ← 日期轴预设在这里
add_custom_page(render_fn) → render_fn(slide, theme) ← 只有 2 个参数
composer.save("output.pptx", lint=True) ← 保存后自动 DeckLinter 审计
```
### 布局数据接口速查
| 布局 | 必填字段 | 可选字段 |
|------|---------|---------|
| `title_dark` | `title` | `subtitle`, `date`, `author` |
| `title_light` | `title` | `subtitle`, `date` |
| `kpi_cards` | `title`, `cards: [{label, value}]` | `subtitle`, `footnote`; card 可选: `change`, `note` |
| `chart_full` | `title`, `source`/`datasource`, `categories_col`, `series_config` | `subtitle`, `insight`, `footnote`, `style_config`, `layout_config` |
| `two_charts` | `title`, `left: {source/datasource, ...}`, `right: {...}` | `left_title`, `right_title`, `insight`, `footnote` |
| `chart_text` | `title`, `source`/`datasource`, `categories_col`, `series_config` | `text_title`, `text_body`, `text_bullets`, `insight`, `footnote` |
| `two_charts_vertical` | `title`, `top: {source/datasource, ...}`, `bottom: {...}` | `top_title`, `bottom_title`, `insight`, `footnote` |
| `chart_table` | `title`, `source`/`datasource`, `categories_col`, `series_config`, `headers`, `rows` | `insight`, `chart_ratio` (默认 0.62), `table_df`, `footnote` |
| `bullet_points` | `title`, `items: [{icon, label, desc}]` | `subtitle`, `footnote` |
| `comparison_table` | `title`, `headers`, `rows` | `highlight_row`, `highlight_cols`, `footnote` |
| `section_divider` | `title`, `number` | `subtitle` |
| `conclusion_dark` | `verdict` | `title`, `score`, `items`, `conclusions`, `risk`, `footnote` |
**`footnote` 字段**:所有非封面/结论布局均支持 `footnote` 字段自动渲染为页脚来源脚注8pt左下角。`source` 作为兼容回退(`footnote` 优先)。
**`source` vs `datasource` 字段**
- `source: "revenue"` — 值匹配已知 datasource 时解析为 DataFrame不匹配时保留为脚注文本兼容回退
- `datasource: "revenue"` — 新 canonical key始终视为 datasource 引用,推荐在 left/right 嵌套中使用
**`default_layout_config` 字段**Job 级):全局图表布局默认配置,所有含 `df` 的图表页自动继承。per-page `layout_config` 浅合并覆盖。典型用于统一字体/字号per-page 只写 `number_format` 等差异项。
---
## 自动化功能(新增)
### ChartJunkCleaner — 图表自动清洗
`ChartBuilder.build()` 完成后自动执行,无需手动调用:
- 移除图表外边框、plotArea 边框
- Y 轴网格线 → 极浅灰色虚线 (`#E8E8E8`, 0.5pt, dot style)
- 坐标轴刻度线 → none
- 图例框边框/填充 → 移除
手动使用:
```python
from ppt_station.chart_builder.cleaner import clean_chart
clean_chart(chart) # chart = python-pptx Chart 对象
```
### 投行级表格 (IB Style)
`add_table()` 默认启用 `ib_style=True`
- **无垂直边框** — 仅保留表头上下 + 表格底部水平线
- **数值列自动右对齐** — 检测数值型单元格,自动右对齐(首列左对齐)
- **斑马纹** — 使用 theme token `table_zebra_even` / `table_zebra_odd`
- **列高亮** — `highlight_cols=[2, 3]` 高亮指定列
### 自动页眉/页脚
`PageComposer.add_page()` 自动注入(封面/结论/分隔页除外):
- **页眉**16pt 标题 + 全宽 primary 色分隔线(使用 `add_page_header()`
- **页脚**:左侧来源 + 右侧页码(使用 `add_page_footer()`,由 `data["footnote"]` 传入,兼容回退 `data["source"]`
不再需要手动在每个布局里写标题+分隔线。
### DeckLinter — PPT 合规审计
`composer.save()` 默认 `lint=True`,自动输出审计报告。
CLI 使用:
```bash
python scripts/validate_ppt.py output.pptx # 终端摘要
python scripts/validate_ppt.py output.pptx --json # JSON 报告
python scripts/validate_ppt.py output.pptx --write-notes # 写入 slide notes
```
检查规则:
| 级别 | 规则 | 说明 |
|------|------|------|
| ERROR | `header_missing` | 非封面页必须有 y < 0.6" 的文本框 |
| ERROR | `footer_missing` | 非封面页必须有 y > 6.8" 的文本框 |
| ERROR | `bounds_overflow` | 元素越界(动态阈值:从 PPT 实际尺寸计算,适配 4:3/16:9 |
| WARN | `title_size_overflow` | 内容页标题 > 18pt |
| WARN | `chart_misaligned` | 同页多图 top 偏差 > 0.05" |
| WARN | `insight_missing` | 图表页无结论先行文本(推荐 2-3 行摘要) |
### Design Tokens主题结构化
所有主题现在包含完整的结构 token`_LAYOUT_DEFAULTS` 兜底):
| Token | 默认值 | 用途 |
|-------|--------|------|
| `slide_w` | 13.333 | 幻灯片宽度16:94:3 时自动设为 10.0 |
| `slide_h` | 7.5 | 幻灯片高度(固定) |
| `cover_title_size` | 36 | 封面标题字号 |
| `page_title_size` | 16 | 内容页标题字号 |
| `chart_subtitle_size` | 11 | 图表副标题字号 |
| `footer_size` | 8 | 页脚字号 |
| `header_y` | 0.25 | 页眉 y 坐标 |
| `divider_y` | 0.80 | 分隔线 y 坐标 |
| `content_y` | 1.00 | 内容区起始 y |
| `footer_y` | 7.10 | 页脚 y 坐标 |
| `content_w` | 自动派生 | 内容区宽度 = `slide_w - 2 * margin`16:9 下为 12.133 |
| `table_header_bg` | 跟随 primary | 表头背景色 |
| `chart_default_scheme` | 跟随主题名 | 图表默认配色方案 |
图表配色现在自动关联主题:使用 `jp_finance` 主题时,图表自动使用 `jp_finance` 配色,无需手动指定 `style_config`
---
## 常见陷阱
1. series_config 用 `key`/`name`/`type`/`axis` — 不是 `column`/`chart_type`
2. `position=(Inches(x), Inches(y))` 元组 — 不是 `left=`/`top=` 关键字
3. 日期轴预设传 `ChartLayoutConfig(date_axis_config=MONTHLY_TICKS)` — 不是 `CategoryAxisConfig(date_axis=...)`
4. `add_custom_page(fn)` 的 fn 签名是 `(slide, theme)` — 没有 `prs` 参数
5. kpi_cards 用 `label`/`value` — 不是 `title`/`unit`
6. bullet_points 用 `label`/`desc` — 不是 `title`/`body`
7. conclusion_dark 用 `verdict`/`items` — 不是 `summary`/`cards`
8. `ChartLayoutConfig` 没有 `has_gridlines` 参数(网格线由 ChartJunkCleaner 自动处理)
9. `composer.prs` — 不是 `composer._prs`
10. 不要手写 `add_text(标题) + add_rect(分隔线)` — 使用 `add_page_header(slide, title, theme)` 自动处理
11. 不要手写页脚来源脚注 — 在 data 中传 `"footnote": "来源: Wind, 公司年报"` 即可自动渲染(`source` 兼容回退,但推荐 `footnote`
12. conclusion_dark 新增 `conclusions` 列表(`[{title, desc}]`)用于左侧要点 — 不是 `items``items` 在右侧指标卡片)
13. `comparison_table` 新增 `highlight_cols` 列索引列表 — 不是 `highlight_col`(单数)
14. `composer.save()` 默认 `lint=True` — 禁用审计传 `lint=False`
15. `source` 在顶层图表页中会被 pop 为 DataFrame — 脚注文本请用 `footnote`,不要用 `source`
16. `default_layout_config` 是浅合并 — per-page `layout_config` 的整个子 key 覆盖默认(如 `legend_config` 整体替换,不是字段级合并)
17. 图表页推荐提供 `insight` 字段2-3行结论文本— DeckLinter 会 WARN `insight_missing`
18. `two_charts_vertical``top`/`bottom`,不是 `left`/`right`
19. `chart_table``rows` 可省略 — 如果有 `table_df``df` 会自动转换为 headers/rows
---
## 设计规则
**金融报告级 PPT 标准。完整规则**[reference/design-rules.md](reference/design-rules.md)
核心规则:
1. **50/50 双图是默认** — 相关图表并排在一页(`two_charts` 布局),不要一图一页
2. **禁止 emoji** — 用编号("01")或色块代替。金融报告零 emoji
3. **标题 16pt** — 不超过 18pt。投行级标准
4. **纯白背景** — 内容页用 `FFFFFF`,不用浅色系 bg_light
5. **每页有来源** — 底部 8pt 灰色脚注:"来源Wind, 公司年报"
6. **全宽分隔线** — 标题下方 12.133" 宽 × 0.015" 高 `text_dark` 色细线(不是 2" 短装饰线)
7. **最多 3 色** — 每张图表不超过 3 种颜色
8. **少用 section_divider** — 10-15 页报告不需要分隔页,用标题前缀区分章节
---
## NEVER / ALWAYS
1. **NEVER** 使用绝对路径。脚本用 `Path(__file__).resolve().parent.parent` 定位 `skill/` 根目录(即 `ppt_station` 包所在目录)
2. **NEVER** 在 Job JSON 中用 `merge` 变换——未实现。用 `from: [src1, src2]` concat 替代
3. **NEVER** 依赖 PptEngine 图表分支传递完整参数——复杂图表用 Flow D
4. **NEVER** 跳过 QA——首次渲染必有问题至少一次检查-修复循环
5. **NEVER** 在金融报告中使用 emoji
6. **NEVER** 手写 `gen_xxx.py` 脚本——用 Composer Job JSON 替代
7. **NEVER** 手写标题+分隔线——用 `add_page_header()` 自动处理
8. **NEVER** 手写页脚来源脚注——用 `data["footnote"]` 自动渲染(兼容 `data["source"]`
9. **NEVER** 在每个图表页重复 `layout_config` 字体/字号——用 Job 级 `default_layout_config`per-page 只写差异
10. **NEVER** 硬编码幻灯片宽度 `13.333` — 使用 `theme["slide_w"]`4:3 时自动适配
11. **ALWAYS** 先读 [api-contracts.md](reference/api-contracts.md) 再编码(特别是上下文压缩后)
12. **ALWAYS** 使用主题同名的 color_scheme现已自动关联无需手动指定 `style_config`
13. **ALWAYS** 通过 `data["footnote"]` 传入数据来源(自动渲染为页脚),不要用 `source``source` 会被引擎尝试解析为 datasource
14. **ALWAYS** 优先使用 `two_charts` 布局组合相关图表
15. **ALWAYS** 优先用 Composer Job JSONFlow D不要写一次性 Python 脚本
16. **ALWAYS** 先调 `validate_job.py` 校验再渲染
17. **ALWAYS** 检查 DeckLinter 输出——`save()` 默认运行ERROR 级问题必须修复
18. **ALWAYS** 在图表页提供 `insight` 文本DeckLinter 会 WARN `insight_missing`
---
## 主题选择
| 场景 | 主题 |
|------|------|
| 金融/银行 | `jp_finance` |
| 养老金/保险 | `pension_warm` |
| 科技/互联网 | `tech_blue` |
| 政府/国企 | `state_red` |
| ESG/绿色 | `esg_green` |
| 路演/投屏 | `dark_pro` |
| 研究/晨星风格 | `morningstar`(深石板灰+暖橙body_size=11kpi_size=36 |
| 宏观研究 | `macro_research`(深藏蓝灰+净蓝,低调中性灰 accent |
| 通用商务 | `midnight` / `charcoal` |
完整色值: [reference/design-themes.md](reference/design-themes.md)
---
## QA 流程(必须执行)
### Step 0: DeckLinter自动
`composer.save()` 默认运行 DeckLinter输出到 stderr。ERROR 级问题必须修复。
手动运行:
```bash
python scripts/validate_ppt.py output.pptx # 终端摘要
python scripts/validate_ppt.py output.pptx --json # JSON 报告
python scripts/validate_ppt.py output.pptx --write-notes # 写入 slide notes
```
### Step 1: 内容
```bash
python -m markitdown output.pptx # 或 scripts/parse_ppt.py output.pptx
```
检查内容遗漏、错别字、残留占位符。
### Step 2: 结构
```bash
python scripts/describe_chart.py output.pptx
```
检查系列数量、类型、轴分配。
### Step 3: 视觉
方式一(推荐):`soffice` → PDF → 图片 → subagent 视觉检查
方式二fallbackpython-pptx 直接检查形状位置和尺寸
### Step 4: 修复→再验证
至少一次修复-验证循环。一个修复往往引入另一个问题。
---
## 参考文档
| 文档 | 用途 | 何时读取 |
|------|------|---------|
| [api-contracts.md](reference/api-contracts.md) | 函数签名、数据接口、新增 Helper API | **每次编码前** |
| [design-rules.md](reference/design-rules.md) | 投行级设计标准 + 表格/图表自动化规范 | **每次设计报告前** |
| [design-themes.md](reference/design-themes.md) | 10 主题完整色值 + Design Tokens + 比例预设 | 选择/自定义主题时 |
| [chart-config.md](reference/chart-config.md) | 图表配置完整字段 | 复杂图表配置时 |
| [institutional-design-analysis.md](reference/institutional-design-analysis.md) | 77页逐页设计分析 | 需要高级图表/布局灵感时 |
| [placeholder-syntax.md](reference/placeholder-syntax.md) | 占位符语法 | Flow A 模板替换时 |
| [job-schema.md](reference/job-schema.md) | Job JSON Schema | Flow B 编排时 |
| [connectors-transforms.md](reference/connectors-transforms.md) | 数据源+变换 | 数据处理时 |
| layout-*.md (12个) | 新布局设计规格 | 实现新布局时 |