Refactor yaml2pptx.py from a 1,245-line monolithic script into a modular architecture with clear separation of concerns. The entry point is now 127 lines, with business logic distributed across focused modules. Architecture: - core/: Domain models (elements, template, presentation) - loaders/: YAML loading and validation - renderers/: PPTX and HTML rendering - preview/: Flask preview server - utils.py: Shared utilities Key improvements: - Element abstraction layer using dataclass with validation - Renderer logic built into generator classes - Single-direction dependencies (no circular imports) - Each module 150-300 lines for better readability - Backward compatible CLI interface Documentation: - README.md: User-facing usage guide - README_DEV.md: Developer documentation OpenSpec: - Archive refactor-yaml2pptx-modular change (63/70 tasks complete) - Sync 5 delta specs to main specs (2 new + 3 updated)
9.9 KiB
PPTX Generation
Purpose
PPTX generation 系统负责使用 python-pptx 库创建符合 OOXML 标准的 PowerPoint 文档。它管理演示文稿的整体属性(如尺寸),按顺序添加幻灯片,并提供命令行接口供用户使用。
Requirements
Requirement: 系统必须创建符合 OOXML 标准的 PPTX 文件
系统 SHALL 使用 python-pptx 库生成符合 Office Open XML (OOXML) 标准的 .pptx 文件。
Scenario: 生成的 PPTX 文件可被 PowerPoint 打开
- WHEN 系统生成 PPTX 文件
- THEN 该文件可被 Microsoft PowerPoint 正常打开和编辑
Scenario: 生成的 PPTX 文件可被其他软件打开
- WHEN 系统生成 PPTX 文件
- THEN 该文件可被 LibreOffice Impress、Google Slides 等软件正常打开
Scenario: PPTX 文件扩展名正确
- WHEN 系统保存演示文稿
- THEN 输出文件的扩展名为
.pptx
Requirement: 系统必须支持设置演示文稿尺寸
系统 SHALL 支持设置演示文稿的幻灯片尺寸,支持 16:9 和 4:3 两种标准比例。
Scenario: 创建 16:9 比例的演示文稿
- WHEN metadata 中指定
size: "16:9" - THEN 系统创建 10×5.625 英寸的幻灯片
Scenario: 创建 4:3 比例的演示文稿
- WHEN metadata 中指定
size: "4:3" - THEN 系统创建 10×7.5 英寸的幻灯片
Scenario: 默认使用 16:9 比例
- WHEN metadata 中未指定 size 字段
- THEN 系统默认使用 16:9 比例
Scenario: 不支持的尺寸比例报错
- WHEN metadata 中指定了不支持的尺寸比例(如 "21:9")
- THEN 系统抛出错误,提示仅支持 16:9 和 4:3
Requirement: 系统必须按顺序添加幻灯片
系统 SHALL 按照 YAML 中 slides 列表的顺序,依次添加幻灯片到 PPTX 文件。
Scenario: 幻灯片顺序与 YAML 一致
- WHEN YAML 中 slides 列表为
[slide1, slide2, slide3] - THEN 生成的 PPTX 文件中,幻灯片顺序为 slide1、slide2、slide3
Scenario: 空幻灯片列表生成空演示文稿
- WHEN YAML 中 slides 列表为空
- THEN 系统生成一个不包含任何幻灯片的 PPTX 文件(或抛出警告)
Requirement: 系统必须使用空白布局
系统 SHALL 为每个幻灯片使用空白布局(blank layout),以便完全自定义内容。
Scenario: 使用空白布局添加幻灯片
- WHEN 系统添加幻灯片
- THEN 使用
prs.slide_layouts[6](空白布局)而非预定义布局
Scenario: 空白幻灯片不包含占位符
- WHEN 创建新的空白幻灯片
- THEN 幻灯片不包含任何预定义的标题或内容占位符
Requirement: 系统必须保存到指定路径
系统 SHALL 将生成的 PPTX 文件保存到用户指定的路径。
Scenario: 保存到指定文件路径
- WHEN 用户指定输出路径为
output/presentation.pptx - THEN 系统将 PPTX 文件保存到该路径
Scenario: 自动创建输出目录
- WHEN 输出路径包含不存在的目录(如
output/subdir/file.pptx) - THEN 系统自动创建所需的目录结构
Scenario: 输出路径已存在时覆盖
- WHEN 指定的输出文件路径已存在
- THEN 系统覆盖原有文件(或提供选项询问用户)
Scenario: 无写入权限时报错
- WHEN 输出路径没有写入权限
- THEN 系统抛出错误,提示权限不足
Requirement: 系统必须使用 python-pptx 的单位转换函数
系统 SHALL 使用 python-pptx 提供的 Inches() 函数将英寸值转换为 EMU(English Metric Units)。
Scenario: 使用 Inches() 转换坐标
- WHEN 元素 box 定义为
[1, 2, 8, 3] - THEN 系统调用
Inches(1),Inches(2),Inches(8),Inches(3)转换为 EMU
Scenario: EMU 转换的精度
- WHEN 使用 Inches(1.0)
- THEN 返回值为 914400 EMU(1 英寸 = 914400 EMU)
Requirement: 系统必须处理颜色转换
系统 SHALL 将十六进制颜色值(如 "#4a90e2")转换为 python-pptx 的 RGBColor 对象。
Scenario: 十六进制颜色转 RGB
- WHEN 颜色值为 "#4a90e2"
- THEN 系统转换为 RGBColor(74, 144, 226)
Scenario: 短格式十六进制颜色
- WHEN 颜色值为 "#fff"(短格式)
- THEN 系统扩展为 "#ffffff" 并转换为 RGBColor(255, 255, 255)
Scenario: 无效颜色格式报错
- WHEN 颜色值不是有效的十六进制格式
- THEN 系统抛出错误,提示颜色格式无效
Requirement: 系统必须使用 uv 运行 Python 脚本
系统 SHALL 使用 uv 运行转换脚本,通过 Inline script metadata 指定依赖。
Scenario: 脚本包含 Inline script metadata
- WHEN 查看
yaml2pptx.py文件头部 - THEN 包含
# /// script块,定义 python-pptx 和 PyYAML 依赖
Scenario: 使用 uv 运行脚本
- WHEN 执行转换命令
- THEN 使用
uv run yaml2pptx.py而非python yaml2pptx.py
Scenario: 禁止直接安装依赖
- WHEN 需要使用 python-pptx 或 PyYAML
- THEN 不使用
pip install,而是在 script metadata 中声明依赖
Requirement: PptxGenerator 必须内置渲染器
系统 SHALL 将 PptxGenerator 类重构为内置渲染器的架构,渲染逻辑作为类的私有方法,而不是独立的函数。
Scenario: PptxGenerator 包含渲染方法
- WHEN 开发者查看 PptxGenerator 类
- THEN 应包含
_render_element(),_render_text(),_render_image(),_render_shape(),_render_table()等私有方法
Scenario: add_slide 方法调用内置渲染器
- WHEN 调用
generator.add_slide(slide_data, base_path) - THEN 系统应在方法内部调用
_render_element()来渲染每个元素
Scenario: 渲染方法接收元素对象
- WHEN 渲染方法被调用
- THEN 应接收元素对象(如 TextElement, ImageElement)而不是字典
Requirement: PptxGenerator 必须位于 renderers 模块
系统 SHALL 将 PptxGenerator 类从主脚本提取到 renderers/pptx_renderer.py 模块中。
Scenario: PptxGenerator 在独立模块中
- WHEN 开发者查看项目结构
- THEN PptxGenerator 类应定义在
renderers/pptx_renderer.py文件中
Scenario: 主脚本导入 PptxGenerator
- WHEN yaml2pptx.py 需要使用 PptxGenerator
- THEN 应通过
from renderers.pptx_renderer import PptxGenerator导入
Requirement: 渲染器必须通过类型检查分发元素
系统 SHALL 在 _render_element() 方法中使用 isinstance() 检查元素类型,分发到对应的渲染方法。
Scenario: 分发文本元素
- WHEN
_render_element()接收到 TextElement 对象 - THEN 系统应调用
_render_text(slide, elem)
Scenario: 分发图片元素
- WHEN
_render_element()接收到 ImageElement 对象 - THEN 系统应调用
_render_image(slide, elem, base_path)
Scenario: 分发形状元素
- WHEN
_render_element()接收到 ShapeElement 对象 - THEN 系统应调用
_render_shape(slide, elem)
Scenario: 分发表格元素
- WHEN
_render_element()接收到 TableElement 对象 - THEN 系统应调用
_render_table(slide, elem)
Requirement: 渲染方法必须访问元素对象的属性
系统 SHALL 通过元素对象的属性(如 elem.content, elem.box)访问数据,而不是通过字典的 get() 方法。
Scenario: 访问文本元素属性
- WHEN
_render_text()渲染文本元素 - THEN 应使用
elem.content,elem.box,elem.font等属性
Scenario: 访问图片元素属性
- WHEN
_render_image()渲染图片元素 - THEN 应使用
elem.src,elem.box等属性
Scenario: 访问形状元素属性
- WHEN
_render_shape()渲染形状元素 - THEN 应使用
elem.shape,elem.box,elem.fill,elem.line等属性
Scenario: 访问表格元素属性
- WHEN
_render_table()渲染表格元素 - THEN 应使用
elem.data,elem.position,elem.col_widths,elem.style等属性
Requirement: 系统架构保持简洁
系统 SHALL 采用两层架构(模板 + 演示文稿),颜色和样式直接在模板中定义。
Scenario: 模板自包含样式
- WHEN 查看模板文件
- THEN 颜色值直接以十六进制格式指定(如 "#4a90e2")
Scenario: 无需主题配置
- WHEN 创建新的演示文稿
- THEN metadata 中不需要指定 theme 字段
Scenario: 模板独立配色
- WHEN 创建新模板
- THEN 可以为该模板定义独立的颜色方案,不受其他模板影响
Requirement: 系统必须提供命令行接口
系统 SHALL 提供命令行接口,接受输入 YAML 文件路径和输出 PPTX 文件路径。
Scenario: 基本命令行使用
- WHEN 执行
uv run yaml2pptx.py input.yaml output.pptx - THEN 系统读取 input.yaml,生成 output.pptx
Scenario: 仅提供输入文件时自动命名输出
- WHEN 执行
uv run yaml2pptx.py input.yaml - THEN 系统自动生成输出文件名为
input.pptx
Scenario: 显示帮助信息
- WHEN 执行
uv run yaml2pptx.py --help - THEN 系统显示使用说明和参数列表
Scenario: 输入文件不存在时报错
- WHEN 提供的输入文件路径不存在
- THEN 系统抛出错误,提示输入文件未找到
Requirement: 系统必须报告转换进度
系统 SHALL 在转换过程中输出进度信息,包括当前处理的幻灯片数量。
Scenario: 输出转换开始信息
- WHEN 开始转换
- THEN 系统输出 "开始转换: input.yaml"
Scenario: 输出幻灯片处理进度
- WHEN 处理每个幻灯片
- THEN 系统输出 "处理幻灯片 N/M"
Scenario: 输出转换完成信息
- WHEN 转换成功完成
- THEN 系统输出 "转换完成: output.pptx"
Scenario: 转换失败时输出错误
- WHEN 转换过程中发生错误
- THEN 系统输出详细的错误信息和堆栈跟踪(调试模式下)