refactor: modularize yaml2pptx into layered architecture
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)
This commit is contained in:
74
utils.py
Normal file
74
utils.py
Normal file
@@ -0,0 +1,74 @@
|
||||
"""
|
||||
工具函数模块
|
||||
|
||||
提供日志输出和颜色转换等通用功能。
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
# ============= 日志输出函数 =============
|
||||
|
||||
def log_info(message):
|
||||
"""输出信息日志"""
|
||||
print(f"[INFO] {message}")
|
||||
|
||||
|
||||
def log_success(message):
|
||||
"""输出成功日志"""
|
||||
print(f"[SUCCESS] ✓ {message}")
|
||||
|
||||
|
||||
def log_error(message):
|
||||
"""输出错误日志"""
|
||||
print(f"[ERROR] ✗ {message}", file=sys.stderr)
|
||||
|
||||
|
||||
def log_progress(current, total, message=""):
|
||||
"""输出进度日志"""
|
||||
print(f"[PROGRESS] {current}/{total} {message}")
|
||||
|
||||
|
||||
# ============= 颜色转换函数 =============
|
||||
|
||||
def hex_to_rgb(hex_color):
|
||||
"""
|
||||
将十六进制颜色转换为 RGB 元组
|
||||
|
||||
Args:
|
||||
hex_color: 十六进制颜色字符串,如 "#4a90e2" 或 "#fff"
|
||||
|
||||
Returns:
|
||||
tuple: (R, G, B) 元组
|
||||
"""
|
||||
hex_color = hex_color.lstrip('#')
|
||||
|
||||
# 处理短格式 #RGB -> #RRGGBB
|
||||
if len(hex_color) == 3:
|
||||
hex_color = ''.join([c*2 for c in hex_color])
|
||||
|
||||
if len(hex_color) != 6:
|
||||
raise ValueError(f"无效的颜色格式: #{hex_color}")
|
||||
|
||||
try:
|
||||
return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
|
||||
except ValueError:
|
||||
raise ValueError(f"无效的颜色格式: #{hex_color}")
|
||||
|
||||
|
||||
def validate_color(color_value):
|
||||
"""
|
||||
验证颜色值格式(十六进制 #RRGGBB 或 #RGB)
|
||||
|
||||
Args:
|
||||
color_value: 颜色字符串
|
||||
|
||||
Returns:
|
||||
bool: 是否有效
|
||||
"""
|
||||
import re
|
||||
if not isinstance(color_value, str):
|
||||
return False
|
||||
# 匹配 #RRGGBB 或 #RGB 格式
|
||||
pattern = r'^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$'
|
||||
return re.match(pattern, color_value) is not None
|
||||
Reference in New Issue
Block a user