|
from typing import Dict, Optional, Type |
|
|
|
from asyncer import asyncify |
|
|
|
from lagent.actions.base_action import AsyncActionMixin, BaseAction, tool_api |
|
from lagent.actions.parser import BaseParser, JsonParser |
|
|
|
THEME_MAPPING = { |
|
'Default': { |
|
'template': None, |
|
'title': 'Title Slide', |
|
'single': 'Title and Content', |
|
'two': 'Two Content', |
|
} |
|
} |
|
|
|
|
|
class PPT(BaseAction): |
|
"""Plugin to create ppt slides with text, paragraph, images in good looking styles.""" |
|
|
|
def __init__( |
|
self, |
|
theme_mapping: Optional[Dict[str, dict]] = None, |
|
description: Optional[dict] = None, |
|
parser: Type[BaseParser] = JsonParser, |
|
): |
|
super().__init__(description, parser) |
|
self.theme_mapping = theme_mapping or THEME_MAPPING |
|
self.pointer = None |
|
self.location = None |
|
|
|
@tool_api(explode_return=True) |
|
def create_file(self, theme: str, abs_location: str) -> dict: |
|
"""Create a pptx file with specific themes. |
|
|
|
Args: |
|
theme (:class:`str`): the theme used. The value should be one of ['Default']. |
|
abs_location (:class:`str`): the ppt file's absolute location |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
from pptx import Presentation |
|
|
|
self.location = abs_location |
|
try: |
|
self.pointer = Presentation(self.theme_mapping[theme]['template']) |
|
self.pointer.slide_master.name = theme |
|
|
|
except Exception as e: |
|
print(e) |
|
return dict(status='created a ppt file.') |
|
|
|
@tool_api(explode_return=True) |
|
def add_first_page(self, title: str, subtitle: str) -> dict: |
|
"""Add the first page of ppt. |
|
|
|
Args: |
|
title (:class:`str`): the title of ppt |
|
subtitle (:class:`str`): the subtitle of ppt |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
layout_name = self.theme_mapping[self.pointer.slide_master.name]['title'] |
|
layout = next(i for i in self.pointer.slide_master.slide_layouts if i.name == layout_name) |
|
slide = self.pointer.slides.add_slide(layout) |
|
ph_title, ph_subtitle = slide.placeholders |
|
ph_title.text = title |
|
if subtitle: |
|
ph_subtitle.text = subtitle |
|
return dict(status='added page') |
|
|
|
@tool_api(explode_return=True) |
|
def add_text_page(self, title: str, bullet_items: str) -> dict: |
|
"""Add text page of ppt. |
|
|
|
Args: |
|
title (:class:`str`): the title of the page |
|
bullet_items (:class:`str`): bullet_items should be string, for multiple bullet items, please use [SPAN] to separate them. |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
layout_name = self.theme_mapping[self.pointer.slide_master.name]['single'] |
|
layout = next(i for i in self.pointer.slide_master.slide_layouts if i.name == layout_name) |
|
slide = self.pointer.slides.add_slide(layout) |
|
ph_title, ph_body = slide.placeholders |
|
ph_title.text = title |
|
ph = ph_body |
|
tf = ph.text_frame |
|
for i, item in enumerate(bullet_items.split('[SPAN]')): |
|
if i == 0: |
|
p = tf.paragraphs[0] |
|
else: |
|
p = tf.add_paragraph() |
|
p.text = item.strip() |
|
p.level = 0 |
|
return dict(status='added page') |
|
|
|
@tool_api(explode_return=True) |
|
def add_text_image_page(self, title: str, bullet_items: str, image: str) -> dict: |
|
"""Add a text page with one image. Image should be a path. |
|
|
|
Args: |
|
title (:class:`str`): the title of the page |
|
bullet_items (:class:`str`): bullet_items should be string, for multiple bullet items, please use [SPAN] to separate them. |
|
image (:class:`str`): the path of the image |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
from PIL import Image |
|
|
|
layout_name = self.theme_mapping[self.pointer.slide_master.name]['two'] |
|
layout = next(i for i in self.pointer.slide_master.slide_layouts if i.name == layout_name) |
|
slide = self.pointer.slides.add_slide(layout) |
|
ph_title, ph_body1, ph_body2 = slide.placeholders |
|
ph_title.text = title |
|
ph = ph_body2 |
|
image = Image.open(image) |
|
image_pil = image.to_pil() |
|
left = ph.left |
|
width = ph.width |
|
height = int(width / image_pil.width * image_pil.height) |
|
top = (ph.top + (ph.top + ph.height)) // 2 - height // 2 |
|
slide.shapes.add_picture(image.to_path(), left, top, width, height) |
|
|
|
ph = ph_body1 |
|
tf = ph.text_frame |
|
for i, item in enumerate(bullet_items.split('[SPAN]')): |
|
if i == 0: |
|
p = tf.paragraphs[0] |
|
else: |
|
p = tf.add_paragraph() |
|
p.text = item.strip() |
|
p.level = 0 |
|
|
|
return dict(status='added page') |
|
|
|
@tool_api(explode_return=True) |
|
def submit_file(self) -> dict: |
|
"""When all steps done, YOU MUST use submit_file() to submit your work. |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
|
|
|
|
|
|
self.pointer.save(self.location) |
|
return dict(status=f'submitted. view ppt at {self.location}') |
|
|
|
|
|
class AsyncPPT(AsyncActionMixin, PPT): |
|
"""Plugin to create ppt slides with text, paragraph, images in good looking styles.""" |
|
|
|
@tool_api(explode_return=True) |
|
@asyncify |
|
def create_file(self, theme: str, abs_location: str) -> dict: |
|
"""Create a pptx file with specific themes. |
|
|
|
Args: |
|
theme (:class:`str`): the theme used. The value should be one of ['Default']. |
|
abs_location (:class:`str`): the ppt file's absolute location |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
return super().create_file(theme, abs_location) |
|
|
|
@tool_api(explode_return=True) |
|
@asyncify |
|
def add_first_page(self, title: str, subtitle: str) -> dict: |
|
"""Add the first page of ppt. |
|
|
|
Args: |
|
title (:class:`str`): the title of ppt |
|
subtitle (:class:`str`): the subtitle of ppt |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
return super().add_first_page(title, subtitle) |
|
|
|
@tool_api(explode_return=True) |
|
@asyncify |
|
def add_text_page(self, title: str, bullet_items: str) -> dict: |
|
"""Add text page of ppt. |
|
|
|
Args: |
|
title (:class:`str`): the title of the page |
|
bullet_items (:class:`str`): bullet_items should be string, for multiple bullet items, please use [SPAN] to separate them. |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
return super().add_text_page(title, bullet_items) |
|
|
|
@tool_api(explode_return=True) |
|
@asyncify |
|
def add_text_image_page(self, title: str, bullet_items: str, image: str) -> dict: |
|
"""Add a text page with one image. Image should be a path. |
|
|
|
Args: |
|
title (:class:`str`): the title of the page |
|
bullet_items (:class:`str`): bullet_items should be string, for multiple bullet items, please use [SPAN] to separate them. |
|
image (:class:`str`): the path of the image |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
return super().add_text_image_page(title, bullet_items, image) |
|
|
|
@tool_api(explode_return=True) |
|
@asyncify |
|
def submit_file(self) -> dict: |
|
"""When all steps done, YOU MUST use submit_file() to submit your work. |
|
|
|
Returns: |
|
:class:`dict`: operation status |
|
* status: the result of the execution |
|
""" |
|
return super().submit_file() |
|
|