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>
15 KiB
API Contracts — 函数签名与数据接口
本文档是 ppt-station 所有公开 API 的精确合约。编码前必读。
1. create_combo_chart()
from ppt_station.chart_builder.api import create_combo_chart
create_combo_chart(
slide, # pptx Slide 对象
df, # pandas DataFrame
categories_col, # str — X轴列名
series_config, # List[Dict] — 见下方格式
position=(Inches(1), Inches(2)), # (left, top) 元组
size=(Inches(8), Inches(4.5)), # (width, height) 元组
style_config=None, # StyleConfig 实例
layout_config=None, # ChartLayoutConfig 实例
)
series_config 格式(4个字段全部必需)
series_config = [
{"key": "营收(亿)", "name": "营收(亿)", "type": "bar", "axis": "primary"},
{"key": "增长率", "name": "增长率", "type": "line", "axis": "secondary"},
]
| 字段 | 说明 | 可选值 |
|---|---|---|
key |
DataFrame 列名 | 必须与 df 列名完全一致 |
name |
图表图例显示名 | 任意字符串 |
type |
图表类型 | "bar", "line", "area" |
axis |
轴分配 | "primary" (左轴), "secondary" (右轴) |
常见错误:用 column 代替 key、用 chart_type 代替 type、缺少 name 字段。
2. StyleConfig
from ppt_station.chart_builder.styles import StyleConfig
StyleConfig(
color_scheme="tech_blue", # 配色方案名(见 COLOR_SCHEMES)
line_width_pt=2.0, # 线宽 pt: 0.5/0.75/1.0/1.5/2.0/2.25/3.0
marker_style="none", # "none"/"circle"/"square"/"diamond"/"triangle"
marker_size=5, # 标记点大小 pt
)
3. ChartLayoutConfig
from ppt_station.chart_builder.layout import (
ChartLayoutConfig, LegendConfig, ValueAxisConfig, CategoryAxisConfig,
)
from ppt_station.chart_builder.date_axis import MONTHLY_TICKS # DateAxisConfig 预设
ChartLayoutConfig(
title=None, # str — 图表内标题(通常 None,标题放页面上)
legend_config=LegendConfig(...), # 图例
category_axis_config=CategoryAxisConfig(...), # 横轴
value_axis_config=ValueAxisConfig(...), # 主值轴(左)
secondary_value_axis_config=ValueAxisConfig(...), # 次值轴(右)
date_axis_config=MONTHLY_TICKS, # DateAxisConfig 日期轴(优先于 category_axis_config)
)
关键:date_axis_config 在 ChartLayoutConfig 上,不在 CategoryAxisConfig 上。
LegendConfig
LegendConfig(
position=LegendConfig.TOP, # TOP/BOTTOM/LEFT/RIGHT/CORNER
font_size_pt=9,
font_name="黑体",
)
CategoryAxisConfig
CategoryAxisConfig(
is_date_axis=False, # 是否日期轴
major_unit_days=None, # 主刻度天数
font_name="黑体",
font_size_pt=10,
number_format=None, # 如 "yyyy-mm-dd"
)
没有 date_axis 参数。 日期轴预设传入 ChartLayoutConfig(date_axis_config=...)。
ValueAxisConfig
ValueAxisConfig(
number_format="#,##0", # 数字格式
font_name="黑体",
font_size_pt=9,
)
日期轴预设
| 预设 | 间隔 | 适用 |
|---|---|---|
DAILY_TICKS |
1天 | 1-30天 |
WEEKLY_TICKS |
7天 | 1-6月 |
BIWEEKLY_TICKS |
14天 | 季度 |
MONTHLY_TICKS |
1月 | 年度 |
QUARTERLY_TICKS |
3月 | 多年 |
YEARLY_TICKS |
1年 | 长期 |
4. PageComposer
from ppt_station.composer import PageComposer
composer = PageComposer(theme="jp_finance") # 主题名(从 theme 自动读取 slide_w/slide_h)
# 方式一:注册布局
composer.add_page("layout_name", data_dict)
# 自动注入页眉(add_page_header)和页脚(add_page_footer)
# 封面/结论/分隔页除外(title_dark, title_light, conclusion_dark, section_divider)
# 页脚来源从 data["footnote"] 获取(兼容回退 data["source"]),页码自动计算
# 方式二:自定义渲染(无 data)
composer.add_custom_page(render_fn)
# render_fn 签名: def render_fn(slide, theme) → None ← 只有 2 个参数
# 方式三:自定义渲染(带 data)
composer.add_custom_page(render_fn, data=my_dict)
# render_fn 签名: def render_fn(slide, data, theme) → None ← 3 个参数
composer.save("output.pptx") # 自动运行 DeckLinter
composer.save("output.pptx", lint=False) # 跳过审计
常见错误:render_fn(slide, prs, theme) — 没有 prs 参数。
4.1 ChartJunkCleaner(自动,无需手动调用)
ChartBuilder.build() 完成后自动执行清洗:
- 移除图表外边框、plotArea 边框
- Y 轴网格线 → 极浅灰色虚线 (
#E8E8E8, 0.5pt, dot) - 坐标轴刻度线 → none
- 图例框边框/填充 → 移除
手动使用:
from ppt_station.chart_builder.cleaner import clean_chart, ChartJunkCleaner
clean_chart(chart) # 便捷函数
# 或
ChartJunkCleaner(chart).clean() # 完整控制
4.2 DeckLinter(保存时自动运行)
from ppt_station.qa.deck_linter import DeckLinter
linter = DeckLinter("output.pptx")
report = linter.run()
linter.print_summary(report) # 终端摘要
linter.to_json(report) # JSON 字符串
linter.write_to_notes(report) # 写入 PPT slide notes
检查规则:header_missing, footer_missing, bounds_overflow(动态阈值,适配 4:3/16:9), title_size_overflow, chart_misaligned, insight_missing(图表页无结论先行文本)
4.3 页眉/页脚 Helpers
from ppt_station.composer.helpers import add_page_header, add_page_footer
add_page_header(slide, "页面标题", theme)
# 输出: 16pt 标题 + 全宽 primary 色分隔线 (使用 theme tokens: page_title_size, header_y, divider_y)
add_page_footer(slide, theme, source="Wind, 公司年报", page_num=3, brand="PPT Station")
# 输出: 左侧来源 + 右侧页码/品牌 (使用 theme tokens: footer_size, footer_y)
注意:注册布局自动调用,custom_page 不自动调用(需手动使用)。
4.4 PptEngine — Job JSON 渲染
source / datasource / footnote 语义
| 字段 | 位置 | 语义 |
|---|---|---|
datasource |
顶层或 left/right/top/bottom 嵌套 | 新 canonical key,始终视为 datasource 引用 |
source |
顶层或 left/right/top/bottom 嵌套 | 值匹配已知 datasource 时解析为 DataFrame 并 pop;不匹配时保留为脚注文本(兼容回退) |
footnote |
顶层 | 页脚来源文本,auto-footer 优先读取 |
推荐:顶层脚注用 footnote,嵌套 datasource 引用用 source 或 datasource。
default_layout_config(Job 级)
{
"default_layout_config": {
"legend_config": {"font_size_pt": 8, "font_name": "黑体"},
"value_axis_config": {"font_size_pt": 8, "font_name": "黑体"},
"secondary_value_axis_config": {"font_size_pt": 8}
}
}
- 作用:所有含
df的图表页(包括 left/right 嵌套)自动继承此配置 - 合并策略:浅合并,per-page
layout_config的 key 覆盖默认 key(整个子对象替换,非字段级合并) - 无
df的页面(kpi_cards, bullet_points 等)不注入 - Optional:不提供时不注入,完全兼容旧 JSON
5. 布局数据接口
title_dark / title_light
{"title": "标题", "subtitle": "副标题"} # subtitle 可选
kpi_cards
{
"title": "页面标题",
"footnote": "来源: Wind, 公司年报", # 可选,auto-footer 渲染
"cards": [
{"label": "指标名", "value": "数值", "change": "+5.9%"}, # change/note 可选
]
}
常见错误:用 title 代替 label,用 unit 作为单独字段(应把单位写进 value)。
bullet_points
{
"title": "页面标题",
"footnote": "来源: 行业报告", # 可选,auto-footer 渲染
"items": [
{"icon": "01", "label": "要点标题", "desc": "要点描述"},
]
}
常见错误:用 title 代替 label,用 body 代替 desc。
chart_full / chart_text
{
"title": "页面标题",
"df": df, # pandas DataFrame(引擎从 source/datasource 解析)
"categories_col": "日期", # X轴列名
"series_config": [...], # 同 create_combo_chart 的 series_config
"insight": "结论先行文本...", # 可选,2-3行结论摘要(header 和图表之间)
"footnote": "来源: Wind", # 可选,auto-footer 渲染
"style_config": StyleConfig(...), # 可选
"layout_config": ChartLayoutConfig(...), # 可选(可由 default_layout_config 继承)
}
Job JSON 中:df 由 source/datasource 字段解析,不直接传 DataFrame。
two_charts(50/50 双图)
{
"title": "页面标题",
"left_title": "左图标题", # 可选
"right_title": "右图标题", # 可选
"insight": "结论先行文本...", # 可选,header 和图表之间
"footnote": "来源: Wind", # 可选,auto-footer 渲染
"left": {
"df": df1, "categories_col": "日期", "series_config": [...],
"style_config": ..., "layout_config": ...,
},
"right": {
"df": df2, "categories_col": "日期", "series_config": [...],
"style_config": ..., "layout_config": ...,
},
}
Job JSON 中:left/right 内用 source/datasource 指向数据源,footnote 放顶层。
two_charts_vertical(上下双图)
{
"title": "页面标题",
"top_title": "上图标题", # 可选
"bottom_title": "下图标题", # 可选
"insight": "结论先行文本...", # 可选,header 和上图之间
"footnote": "来源: Wind", # 可选,auto-footer 渲染
"top": {
"df": df1, "categories_col": "日期", "series_config": [...],
"style_config": ..., "layout_config": ...,
},
"bottom": {
"df": df2, "categories_col": "日期", "series_config": [...],
"style_config": ..., "layout_config": ...,
},
}
设计特点:两个图表均使用全宽(最大化时间轴跨度),上下等高,中间 0.15" 间隔。适合共享日期轴的趋势对比。
Job JSON 中:top/bottom 内用 source/datasource 指向数据源。
chart_table(左图右表)
{
"title": "页面标题",
"df": df, # 图表数据
"categories_col": "日期",
"series_config": [...],
"headers": ["指标", "值"], # 表格表头(可省略,从 table_df/df 自动提取)
"rows": [["A", "1"], ...], # 表格数据行(可省略,从 table_df/df 自动转换)
"table_df": table_df, # 可选,表格数据 DataFrame(自动转为 headers/rows)
"insight": "结论先行文本...", # 可选
"chart_ratio": 0.62, # 可选,图表宽度占比(默认 0.62)
"footnote": "来源: Wind", # 可选
}
设计特点:左图表 (62%) + 右表格 (38%),表格使用投行级样式(ib_style)。适合趋势可视化 + 截面数据快照组合。
Job JSON 中:图表数据用 source/datasource,表格数据用 table_df 对应的 datasource 或直接传 headers/rows。
comparison_table
{
"title": "标题",
"headers": ["指标", "公司A", "公司B"],
"rows": [["营收", "100亿", "80亿"], ...],
"highlight_row": 0, # 可选,高亮行索引
"highlight_cols": [1, 2], # 可选,高亮列索引列表
"footnote": "来源: Wind, 公司年报", # 可选,auto-footer 渲染
}
表格默认启用投行级样式(ib_style=True):无垂直边框、数值列自动右对齐、斑马纹。
注意:footnote 统一由 auto-footer 渲染(不再在表格下方手动添加)。
section_divider
{"title": "章节名", "number": "01"}
conclusion_dark(左右分栏布局)
{
"verdict": "核心结论(必填)",
"title": "结论", # 可选,默认"结论"
"score": "8/10", # 可选,左侧顶部大字
"conclusions": [ # 可选,左侧要点列表(最多3条)
{"title": "高壁垒", "desc": "品牌+渠道双重优势"},
{"title": "稳增长", "desc": "营收年化增速 20%+"},
],
"items": [{"label": "评分", "value": "8/10"}], # 可选,右侧指标卡片
"risk": "风险提示文字", # 可选,右侧底部
"footnote": "脚注", # 可选
}
布局结构:左侧 55%(score + verdict + conclusions)| 右侧 45%(items 卡片 + risk)
常见错误:用 summary 代替 verdict,用 cards 代替 items。conclusions(左侧要点)和 items(右侧指标)是不同字段。
6. 完整示例:双轴组合图(自定义页面)
from pptx.util import Inches
from ppt_station.composer import PageComposer
from ppt_station.chart_builder.api import create_combo_chart
from ppt_station.chart_builder.styles import StyleConfig
from ppt_station.chart_builder.layout import (
ChartLayoutConfig, LegendConfig, ValueAxisConfig, CategoryAxisConfig,
)
from ppt_station.chart_builder.date_axis import MONTHLY_TICKS
def render_my_chart(slide, theme):
# 页眉(自动: 16pt 标题 + 全宽分隔线)
from ppt_station.composer.helpers import add_page_header, add_page_footer
add_page_header(slide, "股价走势(2024-2026)", theme)
# 图表 — style_config 可省略,自动使用主题配色
m = theme["margin"]
content_y = theme.get("content_y", 1.00)
footer_y = theme.get("footer_y", 7.10)
create_combo_chart(
slide, price_df, categories_col="日期",
series_config=[
{"key": "成交量", "name": "成交量", "type": "bar", "axis": "secondary"},
{"key": "收盘价", "name": "收盘价", "type": "line", "axis": "primary"},
],
position=(Inches(m), Inches(content_y)),
size=(Inches(12.133), Inches(footer_y - content_y - 0.3)),
# style_config 省略 — 自动使用 jp_finance 配色
layout_config=ChartLayoutConfig(
legend_config=LegendConfig(position=LegendConfig.TOP, font_size_pt=9, font_name="黑体"),
value_axis_config=ValueAxisConfig(number_format="#,##0.00", font_name="黑体", font_size_pt=9),
secondary_value_axis_config=ValueAxisConfig(number_format="#,##0", font_name="黑体", font_size_pt=9),
date_axis_config=MONTHLY_TICKS,
),
)
# 页脚(来源 + 页码)
add_page_footer(slide, theme, source="Tushare, Wind")
composer = PageComposer(theme="jp_finance")
composer.add_custom_page(render_my_chart)
composer.save("output.pptx") # 自动运行 DeckLinter