

Hello,大家好,我是人月聊IT。
今天接着聊Claude Skills,在前面我分享过一篇文章,大家可以简单将Skills理解为一个综合了智能体+MCP+代码解析执行能力的综合智能体,这种智能体能够更加方便你在本地完成复杂任务。
简单来看就是你原来要写Python代码做的事情,比如将word文档转换为pdf或markdown格式文件,现在可以通过Python代码来完成。你原来需要通过MCP工具调用来完成的时候,现在转到Skills技能定义里面,技能体也可以完成MCP调用并进行结果整合。
所以今天我们简单测试下Document-Skills这个日常文档,PPT写作处理的智能体,看下其核心逻辑究竟如何?
首先还是进入ClaudeCode后通过命令快速安装:
输入下面命令安装document-skills
/plugin marketplace add anthropics/skills
/plugin install document-skills@anthropic-agent-skills安装完成后,我们让AI自己输出该Skills的功能如下:

好了,我们还是用我前面一篇文章输出的费曼学习法文章为例,让该AI参考该智能体定义来帮我输出一个完整的PPT文件。由于挂接的是GLM 4.6 大模型,大家可以看到实际效果只能说一般。










好了,这个不是我们今天完整的重点。今天这篇文章重点还是分析下该Skills实现的内部逻辑究竟是如何的,具体如下:
Document-Skills PPTX 是一个专门用于处理PowerPoint演示文稿的高级技能工具,它提供了从创建、编辑到分析的完整PPT处理能力。该技能采用多层技术架构,结合了HTML到PPT转换、OOXML操作、模板系统等多种技术手段。
适用场景:从头创建新的演示文稿
技术栈:
核心算法流程:
1. HTML文件解析
↓
2. Playwright浏览器渲染
↓
3. DOM元素提取与定位
↓
4. CSS样式解析与转换
↓
5. 位置计算(px → pt → 英寸转换)
↓
6. PptxGenJS元素创建
↓
7. 样式应用与验证
↓
8. 输出PPTX文件关键技术细节:
适用场景:精确编辑现有PPT文件
技术实现:
核心文件结构:
presentation.pptx (ZIP)
├── [Content_Types].xml # 内容类型定义
├── _rels/ # 关系文件
├── ppt/ # 演示文稿核心
│ ├── presentation.xml # 主演示文稿元数据
│ ├── slides/ # 幻灯片内容
│ │ ├── slide1.xml
│ │ ├── slide2.xml
│ │ └── _rels/ # 幻灯片资源关系
│ ├── slideLayouts/ # 布局模板
│ ├── slideMasters/ # 母版设计
│ ├── theme/ # 主题文件
│ ├── media/ # 媒体资源
│ ├── notesSlides/ # 演讲者备注
│ └── comments/ # 评论系统XML操作核心算法:
# 伪代码示例
def edit_slide_xml(slide_path, modifications):
# 1. 解析XML文件
tree = ET.parse(slide_path)
root = tree.getroot()
# 2. 定位目标元素
shapes = root.findall('.//p:sp', namespaces)
# 3. 应用修改
for shape in shapes:
if shape_matches_criteria(shape):
apply_text_modification(shape)
apply_style_changes(shape)
# 4. 验证XML结构
validate_xml_structure(tree)
# 5. 保存修改
tree.write(slide_path)适用场景:基于现有模板创建新演示文稿
工作流程:
1. 模板分析阶段
├── 文本提取:使用markitdown解析模板内容
├── 视觉分析:生成缩略图网格进行布局分析
├── 库存盘点:创建template-inventory.md清单
└── 设计提取:分析颜色方案、字体、布局模式
2. 内容映射阶段
├── 内容结构化:将用户内容映射到模板布局
├── 布局选择:根据内容类型选择合适的模板幻灯片
├── 索引规划:生成template_mapping数组
└── 占位符匹配:确保内容与占位符对应
3. 执行阶段
├── 幻灯片重组:使用rearrange.py重新排列模板
├── 内容替换:使用replace.py批量替换文本
├── 样式保持:保持原有设计元素
└── 质量检查:检查内容匹配度主要处理函数:
1.**getViewportScale()**
// 计算视口缩放比例
const viewportScale = {
width: pageWidth / layoutWidthInches,
height: pageHeight / layoutHeightInches
};2.**getSlideElements()**
// 提取幻灯片元素并进行分类处理
const elements = await page.evaluate(() => {
const allElements = document.querySelectorAll('*');
return Array.from(allElements).map(el => ({
tagName: el.tagName.toLowerCase(),
className: el.className,
textContent: el.textContent.trim(),
style: window.getComputedStyle(el),
position: el.getBoundingClientRect()
}));
});3.**validateTextBoxPosition()**
// 验证文本框位置合规性
function validateTextBoxPosition(slideData, bodyDimensions) {
const minBottomMargin = 0.5; // 0.5英寸底部边距
const errors = [];
slideData.elements.forEach(el => {
if (isTextElement(el.type)) {
const bottomEdge = el.position.y + el.position.h;
const distanceFromBottom = slideHeightInches - bottomEdge;
if (fontSize > 12 && distanceFromBottom < minBottomMargin) {
errors.push(`Text box "${el.text.substring(0, 20)}..." ends too close to bottom edge`);
}
}
});
return errors;
}核心数据结构:
@dataclass
class ParagraphData:
"""段落数据结构"""
text: str
alignment: Optional[str] = None # LEFT, CENTER, RIGHT
bullet: Optional[bool] = None # 是否为项目符号
level: Optional[int] = None # 缩进级别
space_before: Optional[float] = None # 段前间距(点)
space_after: Optional[float] = None # 段后间距(点)
line_spacing: Optional[float] = None # 行间距(点)
font_name: Optional[str] = None # 字体名称
font_size: Optional[float] = None # 字体大小(点)
bold: Optional[bool] = None # 加粗
italic: Optional[bool] = None # 斜体
underline: Optional[bool] = None # 下划线
color: Optional[str] = None # RGB颜色值
@dataclass
class ShapeData:
"""形状数据结构"""
placeholder_type: Optional[str] = None # 占位符类型
left: float # 左边距(英寸)
top: float # 顶边距(英寸)
width: float # 宽度(英寸)
height: float # 高度(英寸)
paragraphs: List[ParagraphData] # 段落列表
rotation: Optional[float] = None # 旋转角度
group_id: Optional[str] = None # 组ID
递归组处理算法:
def extract_from_groupshape(group_shape, parent_offset=(0, 0)) -> List[ShapeData]:
"""递归处理组形状,计算绝对位置"""
shapes = []
group_offset = (group_shape.left, group_shape.top)
for shape in group_shape.shapes:
current_offset = (
parent_offset[0] + group_offset[0],
parent_offset[1] + group_offset[1]
)
if shape.shape_type == MSO_SHAPE_TYPE.GROUP:
# 递归处理嵌套组
shapes.extend(extract_from_groupshape(shape, current_offset))
else:
# 处理单个形状
shape_data = extract_shape_data(shape)
shape_data.left += current_offset[0]
shape_data.top += current_offset[1]
shapes.append(shape_data)
return shapes批量替换流程:
def replace_text_content(pptx_path, replacement_json, output_path):
"""批量替换PPT文本内容"""
# 1. 提取现有内容库存
inventory = extract_text_inventory(pptx_path)
# 2. 验证替换JSON的合法性
validation_errors = validate_replacements(replacement_json, inventory)
if validation_errors:
raise ValueError(f"Invalid replacements: {validation_errors}")
# 3. 打开PPT文件进行修改
prs = Presentation(pptx_path)
# 4. 逐页应用替换
for slide_idx, slide in enumerate(prs.slides):
slide_id = f"slide-{slide_idx}"
if slide_id in replacement_json:
apply_slide_replacements(slide, replacement_json[slide_id], inventory[slide_id])
# 5. 保存修改后的文件
prs.save(output_path)技能内置18种专业配色方案:
const colorPalettes = {
'Classic Blue': ['#1C2833', '#2E4053', '#AAB7B8', '#F4F6F6'],
'Teal & Coral': ['#5EA8A7', '#277884', '#FE4447', '#FFFFFF'],
'Bold Red': ['#C0392B', '#E74C3C', '#F39C12', '#F1C40F'],
// ... 更多配色方案
};两列布局优先策略:
function optimizeLayout(content) {
if (hasChartOrTable(content)) {
// 使用两列布局:文本 + 图表
return {
type: 'two-column',
ratio: content.text_heavy ? '40/60' : '60/40',
text_column: extractTextContent(content),
visual_column: extractVisualContent(content)
};
} else {
// 使用单列布局
return {
type: 'single-column',
content: structuredContent(content)
};
}
}安全字体列表:
- Arial(无衬线,通用)
- Helvetica(无衬线,Mac/印刷)
- Times New Roman(衬线,正式)
- Georgia(衬线,屏幕阅读)
- Courier New(等宽,代码)
- Verdana(无衬线,屏幕优化)
async function processSlidesParallel(htmlFiles, pptx) {
const concurrency = 3; // 并发数量限制
const chunks = chunkArray(htmlFiles, concurrency);
for (const chunk of chunks) {
const promises = chunk.map(htmlFile =>
html2pptx(htmlFile, pptx).catch(error => ({
error: error.message,
file: htmlFile
}))
);
const results = await Promise.all(promises);
handleProcessingResults(results);
}
}def generate_thumbnail_grid(pptx_path, output_prefix, cols=5):
"""生成缩略图网格用于质量检查"""
# 1. 转换PPT为PDF
pdf_path = convert_pptx_to_pdf(pptx_path)
# 2. 将PDF转换为图片
images = convert_pdf_to_images(pdf_path)
# 3. 创建网格布局
grid = create_image_grid(images, cols)
# 4. 保存检查结果
grid.save(f"{output_prefix}.jpg")// 步骤1:文章内容分析
const articleStructure = analyzeArticle(articleContent);
/*
返回结果:
{
title: "费曼学习法",
sections: [
{ type: "introduction", content: "...", key_points: [...] },
{ type: "methodology", content: "...", steps: [...] },
{ type: "benefits", content: "...", items: [...] }
]
}
*/
// 步骤2:PPT结构规划
const pptStructure = planPresentationStructure(articleStructure);
/*
返回结果:
{
slides: [
{ type: "title", content: { title: "...", subtitle: "..." } },
{ type: "introduction", content: { overview: "...", key_points: [...] } },
{ type: "methodology", content: { steps: [...], visual: "flowchart" } }
]
}
*/
// 步骤3:HTML幻灯片生成
const htmlSlides = await generateHTMLSlides(pptStructure);
// 步骤4:PPT文件生成
const pptx = new pptxgen();
pptx.layout = 'LAYOUT_16x9';
for (const htmlSlide of htmlSlides) {
const { slide, placeholders } = await html2pptx(htmlSlide.file, pptx);
// 添加图表到占位符
if (placeholders.length > 0 && htmlSlide.chart) {
slide.addChart(pptx.charts.BAR, htmlSlide.chart.data, placeholders[0]);
}
}
// 步骤5:质量验证
await pptx.writeFile('output.pptx');
await generateQualityCheck('output.pptx');Document-Skills PPTX 是一个功能强大、技术先进的PPT处理工具。它通过多种技术模式的组合,提供了从简单文本转换到复杂模板重用的完整解决方案。其核心算法设计精巧,能够准确地将HTML内容转换为专业级的PowerPoint演示文稿,同时保持了高度的可定制性和扩展性。
该技能特别适合需要批量生成演示文稿、基于模板创建内容、或进行精确PPT编辑的场景,是现代办公自动化的重要工具。