md2star.pptx_layout module
Template-intelligent PPTX layout catalog and per-slide AI selection.
Pandoc’s PPTX writer only ever reaches the ~7 named layouts its bundled
template.pptx ships (Title Slide, Section Header, Title and
Content, …); it has no notion of a designer template’s much richer
layout vocabulary (a real marketing deck template routinely ships 20-40 named
layouts: covers, section dividers, big-statement slides, photo heroes,
multi-column splits, …). This module is the missing primitive: given any
designer PPTX template, it builds a layout catalog (every distinct named
layout, its placeholder geometry, and — when a vision model is available — a
short caption of what kind of slide it is), then selects the best-fitting
catalog layout for each slide of an authored Markdown deck.
Selection is two-staged, mirroring how a human designer would actually work:
Text reasoning (LLM): read each slide’s Markdown content plus the catalog (names + captions) and choose the layout whose role best fits — a cover, a section divider, a photo hero, bulleted content, … This stage alone is cheap and works from captions only, never looking at a candidate render.
Visual confirmation (VLM): the text stage never actually looks at the candidate layouts, so it can pick a layout whose caption sounds right but whose actual composition does not suit the slide (a “photo-hero” caption on a layout whose picture placeholder is tiny, say). This stage shows the vision model the slide’s short-listed candidate thumbnails (the text pick plus a couple of archetype-diverse alternates) side by side and asks which one actually carries the content best, overriding the text pick on disagreement. This is the dimension a pure-LLM, caption-only selector cannot provide.
Both stages, and the template-page renderer they rely on, are threaded
through injectable seams (chat / render) so the whole pipeline is
unit-testable offline with fakes, exactly like md2star.reverse_diagrams.
Every call degrades gracefully: with no reachable engine the catalog still
builds (deterministic layout/placeholder extraction never needs AI) and
selection falls back to a safe, rule-based default layout per slide.
- class md2star.pptx_layout.LayoutInfo(name, example_pages=<factory>, placeholders=<factory>, archetype='bulleted-content', background='', caption='', is_content_layout=True)[source]
Bases:
objectOne distinct named layout the designer template exposes.
- Parameters:
- placeholders: list[Placeholder]
- class md2star.pptx_layout.Placeholder(idx, kind, emu=None)[source]
Bases:
objectOne placeholder shape on a layout: its role and its box in EMU.
- class md2star.pptx_layout.Slide(index, title, body='', features=<factory>, chosen_layout=None, chosen_confidence=None, chosen_why='', overrides=<factory>)[source]
Bases:
objectOne Markdown slide plus the cheap structural cues a selector keys on.
- Parameters:
- md2star.pptx_layout.build_catalog(template, *, chat=None, render=None, use_vision=True, cache_path=None, refresh=False)[source]
Build the full layout catalog for template: geometry + (optional) captions.
- Parameters:
template (Path) – The designer PPTX template to catalog.
chat (ChatFn, optional) – Vision transport for captioning; defaults to the real engine-backed one. Ignored when use_vision is
False.render (RenderFn, optional) – Template-page renderer; defaults to the real LibreOffice+poppler one.
use_vision (bool, default True) – When
False(or when rendering/chat is unavailable), every layout gets a rule-based caption instead of a VLM one — the catalog still builds, just without visual captions.cache_path (Path, optional) – Where to persist/read the catalog JSON. Defaults to a content-hashed path under md2star’s cache dir, so re-running on the same template is free.
refresh (bool, default False) – Force a rebuild even if a cache file exists.
- Returns:
One entry per distinct designer layout name.
- Return type:
- md2star.pptx_layout.default_chat(*, kind, model=None)[source]
Build the real engine-backed transport for kind (
"llm"or"vlm").Routes through
best_engine_ai_helper.llm.chatusing md2star’s resolved brief -> engine descriptor, exactly likemd2star.reverse_diagrams. ReturnsNoneon any failure so callers degrade gracefully.
- md2star.pptx_layout.default_render()[source]
Build the real page renderer, caching all pages per template (by hash).
- md2star.pptx_layout.extract_layouts(template)[source]
Deterministically extract every distinct layout name and its geometry.
No AI, no rendering: pure
zipfile+ElementTreeover the template’s OOXML parts. Always available, and the first stage ofbuild_catalog().Enumerates every
ppt/slideLayouts/slideLayoutN.xmlpart directly (not only the layouts some slide happens to use) so a template distributed with no example slides at all — just its layouts, e.g. python-pptx’s own bundled default template — still yields a full catalog;example_pagesis simply empty for a layout no slide currently demonstrates (no thumbnail/caption for it, but its geometry is still extracted and it can still be selected).- Parameters:
template (Path)
- Return type:
- md2star.pptx_layout.layout_pages(template)[source]
Public wrapper over
_layout_example_pages()(used by callers/tests).
- md2star.pptx_layout.render_deck_pages(path, *, dpi=110)[source]
Render every page of a PPTX/PDF path to PNG bytes, keyed by 1-based page.
Public wrapper over
_render_all_pages(), used bymd2star.pptx_assemble’s eyeball loop to render its own assembled output (as opposed todefault_render(), which caches per template page and is meant for the catalog/tie-break stages).
- md2star.pptx_layout.segment(markdown)[source]
Split markdown into slides.
Prefers explicit horizontal-rule slide breaks (
***/---/___on their own line, the common reveal.js/Marp/this-project convention); when the document has none, falls back to splitting on every H1/H2 heading, mirroring Pandoc’s own default slide-level behaviour.
- md2star.pptx_layout.select_layouts(slides, catalog, *, chat=None, batch=12)[source]
Fill
slide.chosen_layoutfor every slide via batched LLM text calls.Only content layouts are offered (brand-reference pages are dropped), each tagged with its archetype so the model matches by role. On any transport failure, slides in that batch fall back to the best archetype-matching content layout (never left unassigned).
- md2star.pptx_layout.smart_layout_available()[source]
Return
Truewhen the full AI-assisted pipeline (LLM + VLM) can run.Mirrors
md2star.reverse_diagrams.diagrams_available(): a light “does the engine resolve and expose both model kinds?” probe, cheap enough to call before offering--smart-layoutin the CLI. The deterministic catalog extraction and a rule-based selection fallback work regardless.- Return type:
- md2star.pptx_layout.visual_confirm(slides, catalog, *, chat=None, render=None, template=None, k=3, only_low_confidence=False, confidence_threshold=0.7)[source]
Visually confirm (or override) each slide’s text-stage layout pick.
This is the VLM dimension the pure-text
select_layouts()cannot provide: it renders each candidate’s example page, shows the vision model the actual thumbnails side by side with the slide’s content, and asks which one genuinely carries that content best. Disagreements overrideslide.chosen_layout; any transport/render failure leaves the text stage’s pick untouched (best-effort, never load-bearing).- Parameters:
only_low_confidence (bool, default False) – When
True, only re-check slides whose text-stage confidence is missing or below confidence_threshold (cheaper, fewer VLM calls); whenFalse(default) every slide gets a visual check.catalog (list[LayoutInfo])
chat (Callable[[str, list[bytes] | None, dict | None], dict | str | None] | None)
template (Path | None)
k (int)
confidence_threshold (float)
- Return type:
None