cryogenic22 commited on
Commit
b954154
·
verified ·
1 Parent(s): 7166956

Create enhanced_pptx.py

Browse files
Files changed (1) hide show
  1. enhanced_pptx.py +364 -0
enhanced_pptx.py ADDED
@@ -0,0 +1,364 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ from pptx import Presentation
3
+ from pptx.enum.shapes import MSO_SHAPE
4
+ from pptx.enum.shapes import MSO_SHAPE_TYPE
5
+ from pptx.dml.color import RGBColor
6
+ from pptx.util import Inches, Pt
7
+ from pptx.enum.chart import XL_CHART_TYPE
8
+ from io import BytesIO
9
+ import base64
10
+ import os
11
+ import requests
12
+ from PIL import Image
13
+ import tempfile
14
+ from visual_elements import (
15
+ add_shape_to_slide,
16
+ add_image_to_slide,
17
+ analyze_slide_for_visuals,
18
+ apply_visuals_to_pptx_slide,
19
+ download_image,
20
+ get_random_placeholder_image,
21
+ STANDARD_SHAPES,
22
+ ICON_CATEGORIES
23
+ )
24
+
25
+ def enhanced_create_ppt(slides_content, template_name):
26
+ """Create an enhanced PowerPoint presentation with visual elements"""
27
+ from utils import TEMPLATES
28
+
29
+ # Get template info
30
+ template = TEMPLATES.get(template_name, TEMPLATES["professional"])
31
+
32
+ # Check if it's a custom template
33
+ if template_name == "custom" and "custom_template" in st.session_state:
34
+ # Use the uploaded template
35
+ prs = load_custom_template()
36
+ else:
37
+ # Create a basic presentation
38
+ prs = Presentation()
39
+
40
+ # Parse template colors for use in slides
41
+ colors = template["colors"]
42
+ primary_color = colors.get("primary", "#0F52BA")
43
+ secondary_color = colors.get("secondary", "#E6E6E6")
44
+ accent_color = colors.get("accent", "#D4AF37")
45
+ text_color = colors.get("text", "#333333")
46
+
47
+ # Title slide
48
+ slide_layout = prs.slide_layouts[0] # Title Slide layout
49
+ slide = prs.slides.add_slide(slide_layout)
50
+
51
+ # Add title text
52
+ title = slide.shapes.title
53
+ if title:
54
+ title.text = slides_content[0]["title"]
55
+
56
+ # Find subtitle placeholder
57
+ subtitle = None
58
+ for shape in slide.placeholders:
59
+ if shape.placeholder_format.type == 2: # subtitle
60
+ subtitle = shape
61
+ break
62
+
63
+ if subtitle:
64
+ subtitle.text = "Created with SlideGator.AI"
65
+
66
+ # Add logo and branding to title slide
67
+ logo_shape = slide.shapes.add_shape(
68
+ MSO_SHAPE.ROUNDED_RECTANGLE,
69
+ Inches(8.5),
70
+ Inches(6.5),
71
+ Inches(1.5),
72
+ Inches(0.6)
73
+ )
74
+ logo_shape.fill.solid()
75
+
76
+ # Convert hex color to RGB
77
+ if primary_color.startswith('#'):
78
+ r = int(primary_color[1:3], 16)
79
+ g = int(primary_color[3:5], 16)
80
+ b = int(primary_color[5:7], 16)
81
+ logo_shape.fill.fore_color.rgb = RGBColor(r, g, b)
82
+
83
+ # Add text to logo shape
84
+ text_frame = logo_shape.text_frame
85
+ text_frame.text = "SlideGator.AI"
86
+ text_frame.paragraphs[0].font.color.rgb = RGBColor(255, 255, 255)
87
+ text_frame.paragraphs[0].font.size = Pt(14)
88
+ text_frame.paragraphs[0].font.bold = True
89
+
90
+ # Process each content slide
91
+ for i, slide_content in enumerate(slides_content[1:], 1):
92
+ # Determine best layout based on content or explicit design
93
+ layout_type = "standard"
94
+ if "design" in slide_content and "layout" in slide_content["design"]:
95
+ layout_type = slide_content["design"]["layout"].lower()
96
+
97
+ # Select appropriate slide layout
98
+ if "two column" in layout_type or "comparison" in layout_type:
99
+ slide_layout = prs.slide_layouts[3] if len(prs.slide_layouts) > 3 else prs.slide_layouts[1]
100
+ elif "title only" in layout_type or "quote" in layout_type:
101
+ slide_layout = prs.slide_layouts[5] if len(prs.slide_layouts) > 5 else prs.slide_layouts[0]
102
+ elif "picture" in layout_type:
103
+ slide_layout = prs.slide_layouts[6] if len(prs.slide_layouts) > 6 else prs.slide_layouts[1]
104
+ else:
105
+ slide_layout = prs.slide_layouts[1] # Default: Title and Content
106
+
107
+ # Create the slide
108
+ slide = prs.slides.add_slide(slide_layout)
109
+
110
+ # Add title
111
+ title_shape = slide.shapes.title
112
+ if title_shape:
113
+ title_shape.text = slide_content["title"]
114
+
115
+ # Apply template styling to title
116
+ for paragraph in title_shape.text_frame.paragraphs:
117
+ paragraph.font.size = Pt(28)
118
+
119
+ # Apply accent color to title if specified
120
+ if "design" in slide_content and "accent_color" in slide_content["design"]:
121
+ custom_color = slide_content["design"]["accent_color"]
122
+ if custom_color.startswith('#'):
123
+ r = int(custom_color[1:3], 16)
124
+ g = int(custom_color[3:5], 16)
125
+ b = int(custom_color[5:7], 16)
126
+ paragraph.font.color.rgb = RGBColor(r, g, b)
127
+ else:
128
+ # Use template accent color
129
+ if accent_color.startswith('#'):
130
+ r = int(accent_color[1:3], 16)
131
+ g = int(accent_color[3:5], 16)
132
+ b = int(accent_color[5:7], 16)
133
+ paragraph.font.color.rgb = RGBColor(r, g, b)
134
+
135
+ # Get content placeholders
136
+ content_placeholders = [shape for shape in slide.placeholders
137
+ if shape.placeholder_format.type != 1] # 1 is title
138
+
139
+ # Add content based on layout and available placeholders
140
+ if content_placeholders:
141
+ content_placeholder = content_placeholders[0]
142
+
143
+ # Format content based on what's available and layout type
144
+ if "content" in slide_content:
145
+ if isinstance(slide_content["content"], list):
146
+ if "two column" in layout_type and len(content_placeholders) > 1:
147
+ # Split content for two columns
148
+ left_placeholder = content_placeholders[0]
149
+ right_placeholder = content_placeholders[1]
150
+
151
+ mid_point = len(slide_content["content"]) // 2
152
+ left_content = slide_content["content"][:mid_point]
153
+ right_content = slide_content["content"][mid_point:]
154
+
155
+ # Add content to left column
156
+ tf = left_placeholder.text_frame
157
+ tf.clear()
158
+ for point in left_content:
159
+ p = tf.add_paragraph()
160
+ p.text = point
161
+ p.level = 0
162
+
163
+ # Add content to right column
164
+ tf = right_placeholder.text_frame
165
+ tf.clear()
166
+ for point in right_content:
167
+ p = tf.add_paragraph()
168
+ p.text = point
169
+ p.level = 0
170
+ else:
171
+ # Standard bullet points
172
+ tf = content_placeholder.text_frame
173
+ tf.clear()
174
+ for point in slide_content["content"]:
175
+ p = tf.add_paragraph()
176
+ p.text = point
177
+ p.level = 0
178
+ else:
179
+ # Plain text
180
+ content_placeholder.text = slide_content["content"]
181
+ else:
182
+ content_placeholder.text = "Content to be added"
183
+
184
+ # Add visual elements
185
+ if "visuals" in slide_content:
186
+ visuals = slide_content["visuals"]
187
+
188
+ # Add chart if specified
189
+ if "chart" in visuals:
190
+ chart_info = visuals["chart"]
191
+ chart_type = chart_info.get("type", "column")
192
+
193
+ # Map chart type to XL_CHART_TYPE enum
194
+ chart_types = {
195
+ "column": XL_CHART_TYPE.COLUMN_CLUSTERED,
196
+ "bar": XL_CHART_TYPE.BAR_CLUSTERED,
197
+ "line": XL_CHART_TYPE.LINE,
198
+ "pie": XL_CHART_TYPE.PIE,
199
+ "area": XL_CHART_TYPE.AREA,
200
+ "scatter": XL_CHART_TYPE.SCATTER
201
+ }
202
+
203
+ xl_chart_type = chart_types.get(chart_type, XL_CHART_TYPE.COLUMN_CLUSTERED)
204
+
205
+ # Position chart
206
+ chart_left = Inches(1)
207
+ chart_top = Inches(2.5)
208
+ chart_width = Inches(8)
209
+ chart_height = Inches(3)
210
+
211
+ # Create chart on slide
212
+ chart = slide.shapes.add_chart(
213
+ xl_chart_type,
214
+ chart_left, chart_top, chart_width, chart_height
215
+ ).chart
216
+
217
+ # Sample data (normally would come from actual data)
218
+ chart.has_legend = True
219
+ chart.has_title = True
220
+ chart.chart_title.text_frame.text = f"{chart_type.capitalize()} Chart"
221
+
222
+ # Set up chart data
223
+ chart_data = chart.chart_data
224
+
225
+ # Sample data
226
+ if chart_type == "pie":
227
+ chart_data.categories = ["Segment 1", "Segment 2", "Segment 3", "Segment 4"]
228
+ chart_data.series[0].name = "Series 1"
229
+ chart_data.series[0].values = [4.2, 2.8, 3.7, 5.4]
230
+ else:
231
+ chart_data.categories = ["Q1", "Q2", "Q3", "Q4"]
232
+ chart_data.series[0].name = "2023"
233
+ chart_data.series[0].values = [4.2, 2.8, 3.7, 5.4]
234
+
235
+ # Add second series
236
+ series2 = chart_data.series.add()
237
+ series2.name = "2024"
238
+ series2.values = [2.7, 3.2, 4.1, 5.0]
239
+
240
+ # Add image if specified
241
+ if "image" in visuals:
242
+ image_info = visuals["image"]
243
+ image_source = image_info.get("source", "")
244
+
245
+ if image_source == "stock" and "url" in image_info:
246
+ # Download stock image
247
+ image_url = image_info["url"]
248
+ try:
249
+ image_data = download_image(image_url)
250
+
251
+ if image_data:
252
+ # Position image
253
+ img_left = Inches(2)
254
+ img_top = Inches(3)
255
+ img_width = Inches(6)
256
+ img_height = Inches(3.5)
257
+
258
+ # Add image to slide
259
+ slide.shapes.add_picture(
260
+ image_data,
261
+ img_left, img_top,
262
+ img_width, img_height
263
+ )
264
+ except Exception as e:
265
+ st.error(f"Error adding stock image: {str(e)}")
266
+
267
+ elif image_source == "upload" and "data" in image_info:
268
+ # Use uploaded image
269
+ try:
270
+ # Convert base64 to image
271
+ img_data = base64.b64decode(image_info["data"])
272
+ img_stream = BytesIO(img_data)
273
+
274
+ # Position image
275
+ img_left = Inches(2)
276
+ img_top = Inches(3)
277
+ img_width = Inches(6)
278
+ img_height = Inches(3.5)
279
+
280
+ # Add image to slide
281
+ slide.shapes.add_picture(
282
+ img_stream,
283
+ img_left, img_top,
284
+ img_width, img_height
285
+ )
286
+ except Exception as e:
287
+ st.error(f"Error adding uploaded image: {str(e)}")
288
+
289
+ # Add AI-generated image if specified
290
+ if "ai_image" in visuals:
291
+ # In a real implementation, this would use the generated image
292
+ # For now, use a placeholder
293
+ try:
294
+ placeholder_image = get_random_placeholder_image()
295
+
296
+ # Position image
297
+ img_left = Inches(2)
298
+ img_top = Inches(3)
299
+ img_width = Inches(6)
300
+ img_height = Inches(3.5)
301
+
302
+ # Add image to slide
303
+ slide.shapes.add_picture(
304
+ placeholder_image,
305
+ img_left, img_top,
306
+ img_width, img_height
307
+ )
308
+ except Exception as e:
309
+ st.error(f"Error adding AI image placeholder: {str(e)}")
310
+
311
+ # Add icons if specified
312
+ if "icons" in visuals:
313
+ icons = visuals["icons"]
314
+
315
+ for i, icon_name in enumerate(icons):
316
+ # Skip if not a valid shape
317
+ if icon_name not in STANDARD_SHAPES:
318
+ continue
319
+
320
+ # Position icons in a row
321
+ icon_left = Inches(1 + (i * 1.5))
322
+ icon_top = Inches(5.5)
323
+ icon_width = Inches(1)
324
+ icon_height = Inches(1)
325
+
326
+ # Add icon shape
327
+ add_shape_to_slide(
328
+ slide,
329
+ icon_name,
330
+ left=icon_left,
331
+ top=icon_top,
332
+ width=icon_width,
333
+ height=icon_height,
334
+ fill_color=accent_color
335
+ )
336
+
337
+ # Apply intelligent design if no explicit visuals are defined
338
+ if "visuals" not in slide_content:
339
+ apply_visuals_to_pptx_slide(slide, slide_content, colors)
340
+
341
+ # Add notes if available
342
+ if "notes" in slide_content and slide_content["notes"]:
343
+ notes_slide = slide.notes_slide
344
+ notes_slide.notes_text_frame.text = slide_content["notes"]
345
+
346
+ # Save to BytesIO
347
+ output = BytesIO()
348
+ prs.save(output)
349
+ output.seek(0)
350
+ return output
351
+
352
+ def load_custom_template():
353
+ """Load a custom template from session state"""
354
+ try:
355
+ # Read the template from session state
356
+ template_data = st.session_state.custom_template
357
+
358
+ # Create a BytesIO object
359
+ template_stream = BytesIO(template_data)
360
+
361
+ # Load the presentation
362
+ prs = Presentation(template_stream)
363
+
364
+ return prs