scripts/pptx_from_template.py
scripts/pptx_from_template.pyBrowse 8 files
809 tokens
3,431 bytes
Token encoding: o200k_base
Snapshot 24fd22b
← Back to SKILL.md
1#!/usr/bin/env python32"""Build a deck from a .pptx template (brand deck) and fill placeholders.3 4Two modes:5 1) Token fill (default): open TEMPLATE, replace every {{token}} across6 slides, tables, and notes using --values JSON ({"token": "value"}),7 save to OUTPUT. Formatting of the token's run is preserved.8 2) --add-slides SPEC.json: additionally append slides built from the9 template's own layouts (referenced by layout name or index), so new10 slides inherit the brand master. Spec:11 {"slides": [{"layout": "Title and Content", "title": "New",12 "bullets": ["a", {"text": "b", "level": 1}],13 "notes": "presenter text"}]}14"""15import argparse16import json17import sys18 19from pptx import Presentation20 21 22def fill_tokens(prs, values):23 from pptx_edit import replace_text # same scripts/ directory24 total = 025 for token, value in values.items():26 total += replace_text(prs, "{{%s}}" % token, str(value))27 return total28 29 30def find_layout(prs, ref):31 if isinstance(ref, int):32 return prs.slide_layouts[ref]33 for layout in prs.slide_layouts:34 if layout.name == ref:35 return layout36 raise SystemExit(f"layout {ref!r} not found; available: "37 f"{[la.name for la in prs.slide_layouts]}")38 39 40def add_slides(prs, spec):41 from pptx_create import add_bullets42 for slide_spec in spec.get("slides", []):43 layout = find_layout(prs, slide_spec.get("layout", 1))44 slide = prs.slides.add_slide(layout)45 if slide_spec.get("title") is not None and slide.shapes.title:46 slide.shapes.title.text = slide_spec["title"]47 if slide_spec.get("bullets"):48 body = next((ph for ph in slide.placeholders49 if ph.placeholder_format.idx != 0), None)50 if body is not None:51 add_bullets(body.text_frame, slide_spec["bullets"])52 if slide_spec.get("notes"):53 slide.notes_slide.notes_text_frame.text = slide_spec["notes"]54 55 56def main(argv=None):57 if hasattr(sys.stdout, "reconfigure"):58 sys.stdout.reconfigure(encoding="utf-8", errors="replace")59 parser = argparse.ArgumentParser(60 description="Fill {{tokens}} in a .pptx template and optionally "61 "append slides using the template's own layouts.",62 epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)63 parser.add_argument("template", help="path to the template .pptx")64 parser.add_argument("output", help="output .pptx path")65 parser.add_argument("--values", metavar="JSON",66 help="JSON file mapping token -> replacement value")67 parser.add_argument("--add-slides", metavar="SPEC_JSON",68 help="JSON spec of slides to append")69 args = parser.parse_args(argv)70 71 prs = Presentation(args.template)72 filled = 073 if args.values:74 with open(args.values, encoding="utf-8") as fh:75 filled = fill_tokens(prs, json.load(fh))76 if args.add_slides:77 with open(args.add_slides, encoding="utf-8") as fh:78 add_slides(prs, json.load(fh))79 prs.save(args.output)80 print(json.dumps({"ok": True, "output": args.output,81 "tokens_filled": filled}))82 return 083 84 85if __name__ == "__main__":86 import os87 sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))88 sys.exit(main())89