# ppt-station skill

Claude Code skill，在对话中通过 `/ppt-station` 触发。自动路由到合适的工作流生成、解析或编辑 PowerPoint。

## 目录结构

```
skill/
├── SKILL.md                    # skill 元数据 + 路由表 + 速查表
├── README.md                   # 本文件
├── scripts/                    # CLI 工具（全部 stdout=JSON, stderr=日志）
│   ├── generate_ppt.py         # Flow A: 模板替换生成
│   ├── run_job.py              # Flow B: Job JSON 声明式编排
│   ├── parse_ppt.py            # Flow C-1: PPT → JSON
│   ├── rebuild_ppt.py          # Flow C-2: JSON → PPT
│   ├── parse_template.py       # 工具: 解析模板占位符
│   ├── describe_chart.py       # 工具: 描述已有图表结构
│   ├── list_presets.py         # 工具: 查询配色/日期轴/图表预设
│   ├── add_placeholders.py     # 工具: 给现有 PPT 注入占位符
│   ├── gen_moutai_report.py    # 示例: 茅台年度分析报告
│   └── gen_moutai_risk.py      # 示例: 茅台风险分析报告
├── reference/                  # 详细参考文档
│   ├── chart-config.md         # 图表配置完整字段
│   ├── job-schema.md           # Job JSON Schema
│   ├── placeholder-syntax.md   # 占位符语法
│   ├── connectors-transforms.md# 数据连接器 + 变换操作
│   ├── workflow-template.md    # Flow A 详解
│   ├── workflow-engine.md      # Flow B 详解
│   ├── workflow-parse-rebuild.md# Flow C 详解
│   └── workflow-tushare.md     # Flow D 详解
└── tests/                      # Bash 集成测试
    ├── test_parse_template.sh
    ├── test_generate_ppt.sh
    ├── test_run_job.sh
    ├── test_parse_rebuild.sh
    └── test_describe_chart.sh
```

## 四条工作流

### Flow A — 模板替换

最常用。模板 PPT 中放好 `{变量名}` 和 `{@图:图表名}` 占位符，配合 config.json + CSV 数据生成最终 PPT。图表样式最丰富（双轴、8 种配色、日期轴预设）。

```bash
# 1. 查看模板有哪些占位符
python scripts/parse_template.py aim/aim03.pptx

# 2. 准备 config.json + CSV，然后生成
python scripts/generate_ppt.py aim/aim03.pptx config.json output.pptx

# 3. 验证生成的图表
python scripts/describe_chart.py output.pptx
```

### Flow B — Job JSON 声明式编排

适合多数据源编排。一个 job.json 声明数据源（CSV/Excel/Tushare）、变换管道、幻灯片配置，一键生成。

```bash
# 验证 schema
python scripts/run_job.py job.json --dry-run

# 正式生成
python scripts/run_job.py job.json
```

> 注意：Job 引擎的图表渲染分支对复杂双轴图支持有限，复杂图表请用 Flow A。

### Flow C — 解析→编辑→重建

对已有 PPT 做微调（批量文本替换、结构检查）。不适合改图表数据。

```bash
python scripts/parse_ppt.py input.pptx parsed.json   # PPT → JSON
# 编辑 parsed.json ...
python scripts/rebuild_ppt.py parsed.json output.pptx  # JSON → PPT
```

### Flow D — Tushare 实时数据

在 Flow A 或 B 中接入 Tushare 实时 A 股数据。需要 `TUSHARE_TOKEN` 环境变量或 `.env` 文件。

```bash
# 完整示例：茅台年度报告（自动拉数据+生成图表+输出 PPT）
python scripts/gen_moutai_report.py

# 风险分析报告
python scripts/gen_moutai_risk.py
```

## 工具脚本速查

| 脚本 | 用途 | 用法 |
|------|------|------|
| `parse_template.py` | 解析模板占位符清单 | `<template.pptx> [--flat]` |
| `describe_chart.py` | 描述已有图表结构 | `<input.pptx> [--slide N]` |
| `list_presets.py` | 查询所有可用预设 | `[--color-schemes\|--date-axis\|--chart-presets\|--all]` |
| `add_placeholders.py` | 给已有 PPT 注入占位符 | `<in.pptx> <out.pptx> <map.json>` |

所有脚本遵循统一约定：**JSON 输出到 stdout，日志输出到 stderr**。

## 内置预设

### 配色方案（8 种）

| 名称 | 色值 | 场景 |
|------|------|------|
| `aim00` | `C0C0C0` `C00000` `305496` `808080` | 养老金报告：浅灰柱+深红线 |
| `default` | 深红/深蓝/深橙/深灰 + 浅色 | 通用 |
| `dark_only` | `C00000` `0070C0` `ED7D31` `595959` | 深色系 |
| `light_only` | `FF9999` `9DC3E6` `F4B183` `BFBFBF` | 浅色系 |
| `red/blue/orange/gray_series` | 各两色渐变 | 单系列强调 |

### 日期轴预设（6 种）

| 预设 | 间隔 | 格式 | 数据量 |
|------|------|------|--------|
| `DAILY_TICKS` | 1 天 | `mm-dd` | 1-30 天 |
| `WEEKLY_TICKS` | 7 天 | `yyyy-mm-dd` | 1-6 个月 |
| `BIWEEKLY_TICKS` | 14 天 | `yyyy-mm-dd` | 季度 |
| `MONTHLY_TICKS` | 1 月 | `yyyy-mm` | 年度 |
| `QUARTERLY_TICKS` | 3 月 | `yyyy-mm` | 多年 |
| `YEARLY_TICKS` | 1 年 | `yyyy` | 长期 |

### 养老金图表预设（4 种）

| 预设 | 系列 | 所需列 |
|------|------|--------|
| 当年收益率走势 | bar(右)+line(左) | `分类`, `沪深300指数(收盘价)`, `组合收益率（左轴）` |
| 成立以来收益率 | area(右)+line(左) | `分类`, `组合规模(万元)`, `累计收益率` |
| 权益仓位走势 | area(右)+line(左) | `分类`, `沪深300指数(收盘价)`, `权益仓位（人社部口径）` |
| 久期走势 | bar(右)+line(左) | `分类`, `中债新综合总财富指数(收盘价)`, `久期` |

## 智能配置（新增）

skill 底层的 `ppt_station` 新增了两个模块，可大幅减少手工配置：

### StyleExtractor — 从参考 PPT 提取风格

```python
from ppt_station.extractors import StyleExtractor
profile = StyleExtractor("reference.pptx").extract()
style_config = profile.to_style_config()      # → StyleConfig
layout_config = profile.to_chart_layout_config()  # → ChartLayoutConfig
```

### ChartAdvisor — DataFrame 自动推荐图表配置

```python
from ppt_station.advisors import ChartAdvisor
rec = ChartAdvisor.suggest(df, title="三一重工 vs 沪深300")
# rec.to_kwargs() → {"categories_col", "series_config", "layout_config", "style_config"}
```

自动识别中文金融列名（收益率→line/primary/0%，指数→bar/secondary/#,##0 等），3 行代替 30+ 行手工配置。

## 测试

```bash
cd ppt-st

# 跑所有集成测试
for t in skill/tests/test_*.sh; do bash "$t"; done

# 单独跑
bash skill/tests/test_parse_template.sh
bash skill/tests/test_generate_ppt.sh
bash skill/tests/test_run_job.sh
bash skill/tests/test_parse_rebuild.sh
bash skill/tests/test_describe_chart.sh

# ChartAdvisor + StyleExtractor 单元测试
python output/sany_moat/test_advisor.py
```

## 关键约束

1. **路径**：脚本内部用 `Path(__file__).resolve()` 定位项目根，不要用绝对路径。CSV 路径相对于 config.json 所在目录。
2. **merge 变换未实现**：Job JSON 中不要用 `merge`，用 `from: [src1, src2]` concat 替代。
3. **占位符匹配**：`{@图:ChartName}` 与 config.json 中的 key 必须完全一致（区分大小写）。
4. **Tushare 索引数据**：用 `pro_bar(asset="I")` 而非 `index_daily`（后者可能失败）。

## 参考文档

| 文档 | 内容 |
|------|------|
| [chart-config.md](reference/chart-config.md) | 图表系列、样式、布局、日期轴完整字段 |
| [job-schema.md](reference/job-schema.md) | Job JSON 声明式配置完整结构 |
| [placeholder-syntax.md](reference/placeholder-syntax.md) | 文本/图表/表格占位符格式 |
| [connectors-transforms.md](reference/connectors-transforms.md) | 3 种数据源 + 7 种变换操作 |
| [workflow-template.md](reference/workflow-template.md) | Flow A 模板替换详解 |
| [workflow-engine.md](reference/workflow-engine.md) | Flow B Job 引擎详解 |
| [workflow-parse-rebuild.md](reference/workflow-parse-rebuild.md) | Flow C 解析重建详解 |
| [workflow-tushare.md](reference/workflow-tushare.md) | Flow D Tushare 集成详解 |
