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)
128 lines
3.5 KiB
Python
128 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
||
# /// script
|
||
# requires-python = ">=3.8"
|
||
# dependencies = [
|
||
# "python-pptx",
|
||
# "pyyaml",
|
||
# "flask",
|
||
# "watchdog",
|
||
# ]
|
||
# ///
|
||
|
||
"""
|
||
YAML to PPTX Converter
|
||
将 YAML 格式的演示文稿源文件转换为 PPTX 文件
|
||
|
||
使用方法:
|
||
uv run yaml2pptx.py input.yaml output.pptx
|
||
uv run yaml2pptx.py input.yaml # 自动生成 input.pptx
|
||
"""
|
||
|
||
import sys
|
||
import argparse
|
||
from pathlib import Path
|
||
|
||
# 导入模块
|
||
from utils import log_info, log_success, log_error, log_progress
|
||
from loaders.yaml_loader import YAMLError
|
||
from core.presentation import Presentation
|
||
from renderers.pptx_renderer import PptxGenerator
|
||
from preview.server import start_preview_server
|
||
|
||
|
||
def parse_args():
|
||
"""解析命令行参数"""
|
||
parser = argparse.ArgumentParser(
|
||
description="将 YAML 格式的演示文稿源文件转换为 PPTX 文件"
|
||
)
|
||
parser.add_argument(
|
||
"input",
|
||
type=str,
|
||
help="输入的 YAML 文件路径"
|
||
)
|
||
parser.add_argument(
|
||
"output",
|
||
type=str,
|
||
nargs="?",
|
||
help="输出的 PPTX 文件路径(可选,默认为输入文件名.pptx)"
|
||
)
|
||
parser.add_argument(
|
||
"--template-dir",
|
||
type=str,
|
||
default=None,
|
||
help="模板文件目录路径(如果 YAML 中使用了模板则必须指定)。可以是绝对路径或相对路径(相对于当前工作目录)"
|
||
)
|
||
parser.add_argument(
|
||
"--preview",
|
||
action="store_true",
|
||
help="启动浏览器预览模式,而不是生成 PPTX 文件"
|
||
)
|
||
parser.add_argument(
|
||
"--port",
|
||
type=int,
|
||
default=None,
|
||
help="预览服务器端口(默认随机选择 20000-30000 之间的端口)"
|
||
)
|
||
return parser.parse_args()
|
||
|
||
|
||
def main():
|
||
"""主函数:加载 YAML → 渲染幻灯片 → 生成 PPTX"""
|
||
try:
|
||
args = parse_args()
|
||
|
||
# 处理输入文件路径
|
||
input_path = Path(args.input)
|
||
|
||
# 预览模式
|
||
if args.preview:
|
||
start_preview_server(input_path, args.template_dir, args.port)
|
||
return
|
||
|
||
# PPTX 生成模式
|
||
# 处理输出文件路径
|
||
if args.output:
|
||
output_path = Path(args.output)
|
||
else:
|
||
# 自动生成输出文件名
|
||
output_path = input_path.with_suffix(".pptx")
|
||
|
||
log_info(f"开始转换: {input_path}")
|
||
log_info(f"输出文件: {output_path}")
|
||
|
||
# 1. 加载演示文稿
|
||
log_info("加载演示文稿...")
|
||
pres = Presentation(input_path, templates_dir=args.template_dir)
|
||
|
||
# 2. 创建 PPTX 生成器
|
||
log_info(f"创建演示文稿 ({pres.size})...")
|
||
generator = PptxGenerator(pres.size)
|
||
|
||
# 3. 渲染所有幻灯片
|
||
slides_data = pres.data.get('slides', [])
|
||
total_slides = len(slides_data)
|
||
|
||
for i, slide_data in enumerate(slides_data, 1):
|
||
log_progress(i, total_slides, f"处理幻灯片")
|
||
rendered_slide = pres.render_slide(slide_data)
|
||
generator.add_slide(rendered_slide, input_path.parent)
|
||
|
||
# 4. 保存 PPTX 文件
|
||
log_info("保存 PPTX 文件...")
|
||
generator.save(output_path)
|
||
|
||
log_success(f"转换完成: {output_path}")
|
||
|
||
except YAMLError as e:
|
||
log_error(str(e))
|
||
sys.exit(1)
|
||
except Exception as e:
|
||
log_error(f"未知错误: {str(e)}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
sys.exit(1)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|