Skip to content

Prompts Upgrade & Tool Use Capability #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
161 changes: 159 additions & 2 deletions powerpoint_generative_ai/domain/prompts.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,85 @@
TOOL_USE_PROMPT = """
YOU MUST ALWAYS OUTPUT IN THE GIVEN FORMAT. EVEN IF OTHER OUTPUTS ARE DIFFERENT.
You are an analyst and a masterful tool user. Your job right now is to determine whether to call a tool or not call a tool.

You must analyze the given context.

You can use the following tools:

- generate_chart(param): Identify if the user has passed data for a chart (different from a diagram). If user wants a specific chart, give him that. If not, give him the best chart for the data. The param should include chart type too.

Only return the value of the most applicable chart type:

{
"BAR_CLUSTERED": {"value": 57, "description": "Clustered Bar."},
"BAR_OF_PIE": {"value": 71, "description": "Bar of Pie."},
"BAR_STACKED": {"value": 58, "description": "Stacked Bar."},
"BAR_STACKED_100": {"value": 59, "description": "100% Stacked Bar."},
"COLUMN_CLUSTERED": {"value": 51, "description": "Clustered Column."},
"COLUMN_STACKED": {"value": 52, "description": "Stacked Column."},
"COLUMN_STACKED_100": {"value": 53, "description": "100% Stacked Column."},
"LINE": {"value": 4, "description": "Line."},
"LINE_MARKERS": {"value": 65, "description": "Line with Markers."},
"LINE_MARKERS_STACKED": {"value": 66, "description": "Stacked Line with Markers."},
"LINE_MARKERS_STACKED_100": {"value": 67, "description": "100% Stacked Line with Markers."},
"LINE_STACKED": {"value": 63, "description": "Stacked Line."},
"LINE_STACKED_100": {"value": 64, "description": "100% Stacked Line."}
}

Again, only return the value of the most applicable chart type. So for line chart you would use 4, etc.

- generate_mermaid_diagram(param): in here you can pass mermaid syntax text to generate a diagram (different from a chart). If user wants a diagram, give him one using this.

Pass the mermaid syntax text AND descriptive name of the diagram in the param. Analyze what the user wants, then convert it into a proper diagram. Then pass the diagram to the function.
param will look like: "<mermaid graph>" @,@ "Diagram name"

User does not need to pass any data for diagrams, make the diagram on your own. Unless user has passed some data for a diagram, then use that data to make the diagram.

You can make sophisticated diagrams and simple ones too. Try to explain the topics properly.

Yes, use @,@ to separate the mermaid syntax text and the name of the diagram.


====

All your outputs have to be in this format:

<THINK>
Think before your actual output, think:
- What is the user asking?
- Should we use a tool here?
- How should we use the tool here?
- Do we need a chart or a diagram?
---- How can we generate a creative diagram? Make sure to not just copy paste the format of the example.
- Analyze the data.

Plan ahead here.

DO NOT USE MORE THAN 5-7 sentences TO THINK.

</THINK>
<out>
IF you do not want to call a function, output- call:none:none

IF you want to call a function, output in this format:
call<|?|>func_name<|?|>param
example - call<|?|>generate_chart<|?|>51
example - call<|?|>generate_mermaid_diagram<|?|>graph TD; A-->B; A-->C; B-->D; C-->D;@,@Diagram name

Remember that these are just examples. Make your own diagrams and charts. Do not be limited to these.

Understand that you can call multiple functions at the same time. Every function call must be in a seperate line.

If you do not want to call a function, output- call<|?|>none<|?|>none

</out>

=====
YOU CAN ONLY DO ONE THING, either generate an output, or call a function. But always output in this given format. The output will be used in our program, so it has to be in this format. Otherwise the code will break.
Do not hallucinate.
"""


DECK_CREATION_SYSTEM_PROMPT = """Take the user input and create content for a slideshow related to the user's input. You will generate titles for the slides, content that tells a cohesive story throughout the slides. DO NOT title each slide like 'Slide X: ...'.

Data may be provided in the input, if it has been provided determine the best slide to include a chart. ONLY INSERT CHARTS when data is provided.
Expand Down Expand Up @@ -32,9 +114,14 @@
},
{
'title': 'Slide 3',
'content': 'This is some content for slide 3'
'content': 'This is some detailed content for slide 3 which goes well with the diagram.',
'diagram_name': 'Diagram name'
}
]
======

Note that the text you generate should be detailed and user should always learn something new. But do not write too much, short sentences with good information.


Note: Your output must be parsable, valid JSON. DO NOT summarize what each slide was about, the content on each slide should be meaningful information"""

Expand Down Expand Up @@ -62,4 +149,74 @@

TITLE_GEN_SYSTEM_PROMPT = """Generate a title for this powerpoint based on the content"""

FILENAME_SYSTEM_PROMPT = """Take the powerpoint title in the user text and create a short version to be used as a filename for a .pptx file"""
FILENAME_SYSTEM_PROMPT = """Take the powerpoint title in the user text and create a short version to be used as a filename for a .pptx file"""


SLIDE_CREATION_PROMPT = """
Take the user input and create content for a slide in a slide show. You are given description of a single slide. You will generate a title for the slide, content that tells a cohesive story throughout the slide. DO NOT title the slide like 'Slide X: ...'.
Make sure the content you write is informative and extensive. But it doesn't need to be too long. Short sentences with good information is the key.

You have to always output in a very specific format, here are some examples:

example 1:
{
"title": "Slide 1",
"content": "This is some content for slide 1"
}

example 2:

{
"title": "Slide 1",
"content": "This slide has a multi-line chart",
"chart_data": {
"categories": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"],
"series": [
{"name": "Series 1", "values": [1, 2, 3, 4, 5, 6, 7]},
{"name": "Series 2", "values": [2, 3, 4, 5, 6, 7, 8]},
{"name": "Series 3", "values": [3, 4, 5, 6, 7, 8, 9]}
]
},
"chart_type": 4
}

example 3:

{
"title": "Slide 1",
"content": "This is some detailed content for slide 1. Informative.",
"diagram_name": "Diagram name"
}

example 4:

{
"title": "Slide 1",
"content": "This is some detailed content for slide 1. Informative and detailed.",
"table_data": "Table data" // NOTE: This must be CSV data properly formatted. Must be parsable.
}



VERY IMPORTANT: CSV DATA MUST HAVE SAME NUMBER OF COLUMNS IN EACH ROW. IF NOT, THE CODE WILL BREAK. The CSV must be parsable. Format the data properly.

You will be provided diagram_name and chart_data and table_data when necessary.
If you see some csv data, generate a table. But if user has provided some data for a chart, use that data to generate a chart. If user asked for a chart, then generate a chart.

Note that you are an expert, you must write excellent content. You must always output in the given format. Even if other outputs are different.
Be engaging and always provide new information. Do not summarize what the slide is about, the content on each slide should be meaningful information.

But write short sentences with good information. Do not write too much.

DO NOT SAY THINGS LIKE "This slide has" or "This slide contains", just write the content.
Be informative, no need to mention what the slide contains, just write directly.

Note: Your output must be parsable, valid JSON. ALWAYS OUTPUT VALID JSON.

GENERATE PROPER CSV DATA FOR TABLES when required.
Again, if you see csv data, generate a table.

THERE CAN ONLY EITHER BE A CHART OR A DIAGRAM OR A TABLE. NOT MULTIPLE, ONLY ONE OF THEM. FOLLOW THE FORMAT.
Given CSV data, generate a table.

"""
50 changes: 47 additions & 3 deletions powerpoint_generative_ai/ppt/ppt_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from pptx.slide import Slide
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.util import Inches
from pptx.util import Inches, Pt
from powerpoint_generative_ai.utils.utils import setup_logger


Expand Down Expand Up @@ -46,26 +46,42 @@ def add_slide(self, content: dict):
"""Helper function to add slides to powerpoint"""
text_content = content.get('content', None)
chart_data = content.get('chart_data', None)
image_path = content.get('diagram_name', None)
table_data = content.get('table_data', None)

LAYOUT = SLIDE_LAYOUTS['Title Slide']
if chart_data and text_content:
if table_data:
LAYOUT = SLIDE_LAYOUTS['Title Only']
elif text_content and (chart_data or image_path):
LAYOUT = SLIDE_LAYOUTS['Two Content'] # Text column and blank right side
elif chart_data and not text_content:
LAYOUT = SLIDE_LAYOUTS['Title Only'] # Just a title for a big chart
elif text_content and not chart_data:
elif (text_content and not chart_data):
LAYOUT = SLIDE_LAYOUTS['Title and Content'] # Standard slide format

slide_layout = self.presentation.slide_layouts[LAYOUT]
slide = self.presentation.slides.add_slide(slide_layout)
title = slide.shapes.title
title.text = content.get('title', None)


if table_data:
title.text = text_content
title.text_frame.paragraphs[0].font.size = Pt(13)
self.add_table(slide=slide, csv_text=table_data)
return

if text_content:
content_shape = slide.shapes.placeholders[1]
content_shape.text = text_content

if chart_data:
self.add_chart(data=chart_data, slide=slide, chart_type=content.get('chart_type', XL_CHART_TYPE.COLUMN_CLUSTERED))

if image_path:
self.add_image(image_path=image_path, slide=slide)



def add_chart(self, data: dict, slide: Slide, x: Inches = Inches(4.75), y: Inches = Inches(2), cx: Inches=Inches(5.5), cy: Inches = Inches(4.5), chart_type: int = XL_CHART_TYPE.COLUMN_CLUSTERED):
"""Creates a chart and adds it to the current slide"""
Expand All @@ -75,12 +91,40 @@ def add_chart(self, data: dict, slide: Slide, x: Inches = Inches(4.75), y: Inche
chart_data.add_series(series['name'], series['values'])

chart = slide.shapes.add_chart(chart_type, x, y, cx, cy, chart_data).chart
chart.has_legend = True

for series in chart.series:
series.has_data_labels = True

def add_image(self, image_path: str, slide: Slide, x: Inches = Inches(4.75), y: Inches = Inches(2), cx: Inches=Inches(4), cy: Inches = Inches(3.5)):
"""Adds an image to the current slide"""
slide.shapes.add_picture(image_path, x, y, cx, cy)

def add_table(self, slide: Slide, csv_text: str):
"""Adds a table to the current slide"""

shapes = slide.shapes
self._csv_to_table(shapes, csv_text)

def save(self, file_name: str):
self.presentation.save(file_name)
self.logger.info(f"Presentation successfully created: {file_name}")

def _csv_to_table(self, shapes, csv_text):
rows = csv_text.split('\n')
data = [row.split(',') for row in rows]

row_count = len(data)
col_count = len(data[0])

left = top = Inches(2.0)
width = Inches(6.0)
height = Inches(0.8)


table = shapes.add_table(row_count, col_count, left, top, width, height).table

for r in range(row_count):
for c in range(col_count):
cell = table.cell(r, c)
cell.text = data[r][c]
Loading