1
0
Files
PPTX/openspec/changes/archive/2026-03-02-add-browser-preview/design.md
lanyuanxiaoyao cd7988cbd5 feat: initial implementation of html2pptx with OpenSpec documentation
Add core Python script (yaml2pptx.py) for converting YAML to PowerPoint:
- Element rendering: text, image, shape, table, chart
- Template system with placeholders
- PPTX generation with python-pptx

OpenSpec workflow setup:
- 3 archived changes: browser-preview, template-dir-cli, yaml-to-pptx
- 7 main specifications covering all core modules
- Config and documentation structure

30 files changed, 4984 insertions(+)
2026-03-02 14:28:25 +08:00

251 lines
7.8 KiB
Markdown
Raw 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.
## Context
当前 `yaml2pptx.py` 是一个命令行工具,接收 YAML 文件作为输入,生成 PPTX 文件作为输出。脚本使用 uv 的 Inline script metadata 管理依赖(`python-pptx``pyyaml`),包含完整的 YAML 解析、模板渲染、元素渲染和 PPTX 生成逻辑。
现在需要在同一个脚本中添加预览模式,当用户使用 `--preview` 参数时,启动一个轻量级的 Web 服务器,提供浏览器实时预览功能。预览模式需要复用现有的 YAML 解析和模板渲染逻辑,但将输出目标从 PPTX 改为 HTML/CSS。
## Goals / Non-Goals
**Goals:**
-`yaml2pptx.py` 中添加预览模式,通过 `--preview` 参数启用
- 使用轻量级的 Web 框架Flask提供 HTTP 服务
- 使用 Server-Sent Events (SSE) 实现浏览器自动刷新
- 使用 watchdog 监听 YAML 文件变化
- 复用现有的 `Presentation` 类和 YAML 解析逻辑
- 将 YAML 元素(文本、形状、表格、图片)渲染为 HTML/CSS
- 保持向后兼容,不影响现有的 PPTX 生成功能
**Non-Goals:**
- 不追求 100% 像素级精确的预览效果HTML/CSS 与 PPTX 渲染存在差异是可接受的)
- 不支持交互功能(如点击元素查看属性、拖拽调整位置等)
- 不支持导出为静态 HTML 文件
- 不支持多用户同时预览
- 不支持 PPTX 动画和过渡效果的预览
## Decisions
### 决策 1: 集成到现有脚本 vs 独立脚本
**选择**: 集成到 `yaml2pptx.py` 中,通过 `--preview` 参数启用
**理由**:
- 保持项目简洁,只有一个主脚本
- 用户体验更统一,无需记忆多个命令
- 更容易复用现有的解析逻辑和类定义
- 减少代码重复和维护成本
**替代方案**: 创建独立的 `preview.py` 脚本
- 优点:代码分离更清晰
- 缺点:需要重复导入或复制代码,增加维护成本
### 决策 2: Web 框架选择
**选择**: Flask
**理由**:
- 轻量级,适合本地开发工具
- API 简单,易于实现
- 社区成熟,文档丰富
- 支持 Server-Sent Events
**替代方案**:
- FastAPI: 更现代,但对于简单的预览服务来说过于复杂
- Python 内置 http.server: 太简单,不支持动态路由和 SSE
### 决策 3: 实时刷新方案
**选择**: Server-Sent Events (SSE)
**理由**:
- 单向推送,符合需求(服务器通知浏览器刷新)
- 浏览器原生支持,无需额外的 JavaScript 库
- 实现简单,约 10 行代码
- 无需 WebSocket 的复杂握手和双向通信
**替代方案**:
- WebSocket: 过于复杂,需要 Flask-SocketIO 依赖
- 轮询: 延迟高,资源浪费
- Meta refresh: 固定时间刷新,无法响应文件变化
### 决策 4: 文件监听方案
**选择**: watchdog
**理由**:
- 跨平台,支持 macOS、Linux、Windows
- 成熟稳定,广泛使用
- API 简单,易于集成
- 可以监听整个目录(包括模板文件变化)
**替代方案**:
- 轮询文件修改时间: 延迟高,不够优雅
- 操作系统原生 API: 不跨平台,实现复杂
### 决策 5: 单位转换策略
**选择**: 固定 DPI (96 DPI),幻灯片固定尺寸 960x540 像素
**理由**:
- 实现简单,无需复杂的缩放计算
- 960x540 是合理的预览尺寸16:9 比例)
- 用户可以使用浏览器缩放功能Cmd +/-)调整大小
- 与 PPTX 的英寸单位转换清晰1 英寸 = 96 像素
**替代方案**:
- 自适应缩放: 更灵活,但实现复杂,需要处理百分比定位
- CSS 英寸单位: 不同浏览器可能有差异
### 决策 6: HTML 渲染策略
**选择**: 使用 `<div>` + 内联样式渲染元素
**理由**:
- 简单直接,易于实现
- 使用绝对定位模拟 PPTX 的坐标系统
- 内联样式避免 CSS 类管理的复杂性
- 文本使用 `pt` 单位保持与 PPTX 一致
**元素映射**:
- 文本元素: `<div>` + `font-size: Xpt`
- 形状元素: `<div>` + `background-color` + `border-radius`
- 表格元素: `<table>` 标签
- 图片元素: `<img>` 标签
**替代方案**:
- SVG 渲染: 更精确,但实现复杂
- Canvas 渲染: 性能好,但无法选择文本,调试困难
### 决策 7: 代码组织
**选择**: 在 `yaml2pptx.py` 末尾添加预览相关代码,使用条件判断分离两种模式
**结构**:
```python
# 现有代码PPTX 生成)
class Presentation: ...
class PptxGenerator: ...
# 新增代码(预览模式)
# HTML 渲染函数
def render_element_to_html(elem): ...
# Flask 应用
app = Flask(__name__)
@app.route('/'): ...
@app.route('/events'): ...
# 主函数修改
def main():
if args.preview:
# 启动预览服务器
start_preview_server()
else:
# 生成 PPTX现有逻辑
generate_pptx()
```
**理由**:
- 清晰分离两种模式的逻辑
- 不影响现有代码的可读性
- 易于维护和测试
## Risks / Trade-offs
### 风险 1: HTML/CSS 渲染与 PPTX 渲染存在差异
**风险**: 预览效果与最终 PPTX 可能不完全一致(字体渲染、间距、换行等)
**缓解措施**:
- 在文档中明确说明预览仅供参考
- 使用相同的单位系统pt、英寸尽量保持一致
- 提供快速生成 PPTX 的方式进行最终确认
### 风险 2: 依赖增加
**风险**: 新增 `flask``watchdog` 依赖,增加脚本启动时间和依赖管理复杂度
**缓解措施**:
- 使用 uv 的 Inline script metadata 自动管理依赖
- 仅在预览模式下导入 Flask 和 watchdog延迟导入
- 依赖都是轻量级库,影响较小
### 风险 3: 端口冲突
**风险**: 默认端口 5000 可能被其他服务占用
**缓解措施**:
- 提供 `--port` 参数允许用户指定端口
- 捕获端口占用错误,提示用户更换端口
### 风险 4: 文件监听性能
**风险**: 监听大型目录可能影响性能
**缓解措施**:
- 仅监听 YAML 文件所在目录,不递归监听
- 使用 watchdog 的高效事件机制
- 添加防抖逻辑,避免短时间内多次刷新
### 权衡 1: 简单性 vs 功能完整性
**权衡**: 选择简单的实现方案,牺牲一些高级功能(如元素交互、网格线、标尺等)
**理由**: 预览功能的核心价值是快速反馈,简单实现可以更快交付,后续可根据需求迭代
### 权衡 2: 精确性 vs 速度
**权衡**: 使用 HTML/CSS 渲染而不是生成 PPTX 再转图片,牺牲精确性换取速度
**理由**: 实时预览的核心是速度,用户可以随时生成 PPTX 进行精确确认
## Migration Plan
### 部署步骤
1.`yaml2pptx.py` 的 Inline script metadata 中添加依赖:
```python
# dependencies = [
# "python-pptx",
# "pyyaml",
# "flask", # 新增
# "watchdog", # 新增
# ]
```
2. 添加预览相关代码(约 200 行)
3. 修改 `parse_args()` 函数,添加 `--preview` 和 `--port` 参数
4. 修改 `main()` 函数,根据参数选择模式
5. 更新 README.md添加预览功能的使用说明
### 回滚策略
- 如果预览功能有问题,用户仍可使用原有的 PPTX 生成功能(完全向后兼容)
- 可以通过 git revert 回滚到之前的版本
- 预览功能是可选的,不影响核心功能
### 测试计划
1. 单元测试:测试 HTML 渲染函数的正确性
2. 集成测试:测试预览服务器的启动和文件监听
3. 手动测试:在不同浏览器中测试预览效果
4. 兼容性测试:确保不影响现有的 PPTX 生成功能
## Open Questions
1. 是否需要支持多幻灯片的缩略图导航?
- 当前方案:垂直排列显示所有幻灯片
- 可选方案:添加左侧缩略图导航栏
2. 是否需要支持深色模式?
- 当前方案:仅支持浅色背景
- 可选方案:添加深色模式切换
3. 是否需要显示元素边框和尺寸标注?
- 当前方案:不显示辅助信息
- 可选方案:添加调试模式,显示元素边框和尺寸
这些问题可以在实现后根据用户反馈决定是否添加。