from typing import List import json5 import pptx import re import yaml from global_config import GlobalConfig PATTERN = re.compile(r"^slide[ ]+\d+:", re.IGNORECASE) def remove_slide_number_from_heading(header: str) -> str: """ Remove the slide number from a given slide header. :param header: The header of a slide """ if PATTERN.match(header): idx = header.find(':') header = header[idx + 1:] return header def generate_powerpoint_presentation( structured_data: str, as_yaml: bool, slides_template: str, output_file_name: str ) -> List: """ Create and save a PowerPoint presentation file containing the contents in JSON or YAML format. :param structured_data: The presentation contents as "JSON" (may contain trailing commas) or YAML :param as_yaml: True if the input data is in YAML format; False if it is in JSON format :param slides_template: The PPTX template to use :param output_file_name: The name of the PPTX file to save as :return A list of presentation title and slides headers """ if as_yaml: # Avoid YAML mode: nested bullets can lead to incorrect YAML generation try: parsed_data = yaml.safe_load(structured_data) except yaml.parser.ParserError as ype: print(f'*** YAML parse error: {ype}') parsed_data = {'title': '', 'slides': []} else: # The structured "JSON" might contain trailing commas, so using json5 parsed_data = json5.loads(structured_data) print(f"*** Using PPTX template: {GlobalConfig.PPTX_TEMPLATE_FILES[slides_template]['file']}") presentation = pptx.Presentation(GlobalConfig.PPTX_TEMPLATE_FILES[slides_template]['file']) # The title slide title_slide_layout = presentation.slide_layouts[0] slide = presentation.slides.add_slide(title_slide_layout) title = slide.shapes.title subtitle = slide.placeholders[1] title.text = parsed_data['title'] print(f'Title is: {title.text}') subtitle.text = 'by Myself and SlideDeck AI :)' all_headers = [title.text, ] # background = slide.background # background.fill.solid() # background.fill.fore_color.rgb = RGBColor.from_string('C0C0C0') # Silver # title.text_frame.paragraphs[0].font.color.rgb = RGBColor(0, 0, 128) # Navy blue # Add contents in a loop for a_slide in parsed_data['slides']: bullet_slide_layout = presentation.slide_layouts[1] slide = presentation.slides.add_slide(bullet_slide_layout) shapes = slide.shapes title_shape = shapes.title body_shape = shapes.placeholders[1] title_shape.text = remove_slide_number_from_heading(a_slide['heading']) all_headers.append(title_shape.text) text_frame = body_shape.text_frame for an_item in a_slide['bullet_points']: item_type = type(an_item) # print('Bullet point type:', item_type) if item_type is str: paragraph = text_frame.add_paragraph() paragraph.text = an_item paragraph.level = 0 elif item_type is list: for sub_item in an_item: if type(sub_item) is str: paragraph = text_frame.add_paragraph() paragraph.text = sub_item paragraph.level = 1 # background = slide.background # background.fill.gradient() # background.fill.gradient_angle = -225.0 # The thank-you slide last_slide_layout = presentation.slide_layouts[0] slide = presentation.slides.add_slide(last_slide_layout) title = slide.shapes.title title.text = 'Thank you!' presentation.save(output_file_name) return all_headers if __name__ == '__main__': generate_powerpoint_presentation( json5.loads(open('examples/example_02_structured_output.json', 'r').read()), as_yaml=False, output_file_name='test.pptx' )