| from __future__ import annotations |
|
|
| from pathlib import Path |
|
|
| from pptx import Presentation |
|
|
| from src.utils.validators import validate_template |
|
|
|
|
| class PlaceholderMapper: |
| def __init__(self, template_path: str | Path | None = None): |
| self.template_path = Path(template_path) if template_path else None |
| self.presentation = None |
| if self.template_path: |
| self.load_template(self.template_path) |
|
|
| def load_template(self, template_path: str | Path): |
| validated_path = validate_template(template_path) |
| self.template_path = validated_path |
| self.presentation = Presentation(str(validated_path)) |
| return self.presentation |
|
|
| def map_layout_types(self) -> list[str]: |
| if not self.presentation: |
| raise ValueError("Template not loaded.") |
| return [layout.name for layout in self.presentation.slide_layouts] |
|
|
| def map_placeholders(self, layout_index: int = 0) -> dict[str, str]: |
| if not self.presentation: |
| raise ValueError("Template not loaded.") |
|
|
| layout = self.presentation.slide_layouts[layout_index] |
| mapped = {} |
| for placeholder in layout.placeholders: |
| placeholder_name = getattr(placeholder, "name", None) |
| placeholder_type = getattr(placeholder.placeholder_format, "type", None) |
| if placeholder_name: |
| mapped[str(placeholder_type).lower()] = placeholder_name |
| return mapped |
|
|
|
|
| def choose_layout_index( |
| layout_type: str, |
| style_profile: dict, |
| total_layouts: int, |
| ) -> int: |
| preferred = style_profile.get("preferred_layout_indices", {}) if style_profile else {} |
| idx = preferred.get(layout_type, 1) |
| if total_layouts <= 0: |
| return 0 |
| return max(0, min(int(idx), total_layouts - 1)) |
|
|
|
|
| def map_placeholders(template_placeholders: list[dict]) -> dict[str, list[str]]: |
| """Backward-compatible helper.""" |
| mapped_placeholders: dict[str, list[str]] = {} |
| for placeholder in template_placeholders: |
| layout_type = placeholder.get("layout_type", "unknown") |
| placeholder_name = placeholder.get("name", "") |
| mapped_placeholders.setdefault(layout_type, []).append(placeholder_name) |
| return mapped_placeholders |
|
|
|
|
| def get_placeholder_mapping(template: str | Path) -> list[dict[str, str]]: |
| mapper = PlaceholderMapper(template) |
| placeholders = mapper.map_placeholders(0) |
| return [ |
| {"layout_type": "title", "name": placeholders.get("center title", "Title Placeholder")}, |
| {"layout_type": "content", "name": placeholders.get("object", "Content Placeholder")}, |
| ] |