YashMK89 commited on
Commit
019e28e
Β·
verified Β·
1 Parent(s): 65cdbf5

update code with QA

Browse files
Files changed (1) hide show
  1. pages/1_πŸ“Š_Text_to_PPT.py +591 -18
pages/1_πŸ“Š_Text_to_PPT.py CHANGED
@@ -1,3 +1,441 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import google.generativeai as genai
3
  from pptx import Presentation
@@ -13,6 +451,9 @@ import os
13
 
14
  # Load the API key securely from environment variable
15
  api_key = os.getenv("GOOGLE_API_KEY")
 
 
 
16
  genai.configure(api_key=api_key)
17
 
18
  # Default theme configurations
@@ -86,7 +527,7 @@ def extract_theme_from_pptx(uploaded_file):
86
  for shape in slide_master.shapes:
87
  if shape.has_text_frame and shape.text.strip():
88
  try:
89
- if shape.name.lower() == 'title':
90
  theme["title_color"] = shape.text_frame.paragraphs[0].font.color.rgb
91
  theme["title_font"] = shape.text_frame.paragraphs[0].font.name
92
  else:
@@ -148,16 +589,26 @@ def generate_slide_content(topic, slide_count):
148
  - Challenges
149
  - Future Trends
150
  - Conclusion
151
- - Questionnaire
152
-
153
- After generating the content for the above presentation sections,titled [Title:], generate a Questionnaire Slide containing:
154
- - 10 multiple-choice questions testing the user’s understanding of the presentation
155
- - Each question should have 4 options (A, B, C, D)
156
- - Clearly indicate the correct answer after each question using the format: [Correct Answer: C]
157
- - Make the questions relevant and cover all key areas: introduction, concepts, analysis, case studies, applications, challenges, and future trends.
158
- - Make sure the questions test the user's comprehension of the previous slides' content and are well-distributed across different topics in the presentation.
159
-
160
- Please ensure the presentation content is presented first, followed by a clear separator, and then the questionnaire.
 
 
 
 
 
 
 
 
 
 
161
 
162
  Begin the content generation now.
163
  """
@@ -168,8 +619,15 @@ def generate_slide_content(topic, slide_count):
168
  def parse_slide_content(slide_text):
169
  slides = []
170
  current_slide = {}
 
 
 
 
 
 
171
 
172
- for line in slide_text.split('\n'):
 
173
  line = line.strip()
174
  if not line:
175
  continue
@@ -203,9 +661,104 @@ def parse_slide_content(slide_text):
203
  if current_slide:
204
  slides.append(current_slide)
205
 
206
- return slides
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
- def create_detailed_pptx(slides_data, theme, branding_options=None):
 
 
 
 
 
 
 
 
 
209
  """Create PowerPoint using the uploaded template"""
210
  # Use the template if one was uploaded
211
  if "template_path" in theme and os.path.exists(theme["template_path"]):
@@ -232,6 +785,7 @@ def create_detailed_pptx(slides_data, theme, branding_options=None):
232
 
233
  default_layout_idx = available_layouts.get('title-content', 0)
234
 
 
235
  for slide_info in slides_data:
236
  layout = slide_info.get('layout', 'title-content').lower()
237
  layout_idx = available_layouts.get(layout, default_layout_idx)
@@ -316,6 +870,10 @@ def create_detailed_pptx(slides_data, theme, branding_options=None):
316
  notes_slide = slide.notes_slide
317
  notes_slide.notes_text_frame.text = slide_info['notes']
318
 
 
 
 
 
319
  pptx_io = io.BytesIO()
320
  prs.save(pptx_io)
321
  pptx_io.seek(0)
@@ -352,6 +910,7 @@ def main():
352
  ["Predefined Theme", "Custom Theme", "Example-Based Theme"])
353
 
354
  theme = DEFAULT_THEMES["Professional Blue"] # Default theme
 
355
 
356
  if theme_option == "Predefined Theme":
357
  theme_name = st.selectbox("Select Theme:", list(DEFAULT_THEMES.keys()))
@@ -395,9 +954,13 @@ def main():
395
  st.info("Please upload a PowerPoint file to extract its theme")
396
 
397
  with col2:
398
- # st.image("https://huggingface.co/spaces/YashMK89/PPTX_generativeai/resolve/main/SVNIT_IS_DS_Projects.png", width=150)
 
 
 
 
399
 
400
- if st.button("Generate Presentation", type="primary"):
401
  if not topic:
402
  st.warning("Please enter a topic first!")
403
  elif theme_option == "Example-Based Theme" and not uploaded_file:
@@ -406,7 +969,7 @@ def main():
406
  with st.spinner(f"Creating {slide_count}-slide presentation about '{topic}'..."):
407
  try:
408
  slide_text = generate_slide_content(topic, slide_count)
409
- slides_data = parse_slide_content(slide_text)
410
 
411
  # Show slide overview with detailed content
412
  with st.expander("Slide Overview (Detailed)"):
@@ -418,8 +981,17 @@ def main():
418
  if slide.get('notes'):
419
  st.markdown(f"**Notes:** {slide['notes']}")
420
  st.markdown("---")
 
 
 
 
 
 
 
 
 
421
 
422
- pptx_file = create_detailed_pptx(slides_data, theme)
423
 
424
  st.success("Presentation generated successfully!")
425
 
@@ -432,5 +1004,6 @@ def main():
432
 
433
  except Exception as e:
434
  st.error(f"An error occurred: {str(e)}")
 
435
  if __name__ == "__main__":
436
  main()
 
1
+ # import streamlit as st
2
+ # import google.generativeai as genai
3
+ # from pptx import Presentation
4
+ # from pptx.util import Inches, Pt
5
+ # from pptx.dml.color import RGBColor
6
+ # from pptx.enum.text import PP_ALIGN, PP_PARAGRAPH_ALIGNMENT
7
+ # from pptx.enum.text import MSO_AUTO_SIZE
8
+ # from pptx.oxml.xmlchemy import OxmlElement
9
+ # import io
10
+ # import re
11
+ # import tempfile
12
+ # import os
13
+
14
+ # # Load the API key securely from environment variable
15
+ # api_key = os.getenv("GOOGLE_API_KEY")
16
+ # genai.configure(api_key=api_key)
17
+
18
+ # # Default theme configurations
19
+ # DEFAULT_THEMES = {
20
+ # "Professional Blue": {
21
+ # "background": RGBColor(12, 35, 64),
22
+ # "title_color": RGBColor(255, 255, 255),
23
+ # "text_color": RGBColor(200, 200, 200),
24
+ # "accent": RGBColor(0, 112, 192),
25
+ # "title_font": "Calibri",
26
+ # "text_font": "Calibri"
27
+ # },
28
+ # "Modern Green": {
29
+ # "background": RGBColor(22, 82, 66),
30
+ # "title_color": RGBColor(255, 255, 255),
31
+ # "text_color": RGBColor(220, 220, 220),
32
+ # "accent": RGBColor(76, 175, 80),
33
+ # "title_font": "Arial",
34
+ # "text_font": "Arial"
35
+ # },
36
+ # "Light Corporate": {
37
+ # "background": RGBColor(255, 255, 255),
38
+ # "title_color": RGBColor(13, 71, 161),
39
+ # "text_color": RGBColor(33, 33, 33),
40
+ # "accent": RGBColor(25, 118, 210),
41
+ # "title_font": "Segoe UI",
42
+ # "text_font": "Segoe UI"
43
+ # },
44
+ # "Dark Tech": {
45
+ # "background": RGBColor(33, 33, 33),
46
+ # "title_color": RGBColor(0, 200, 255),
47
+ # "text_color": RGBColor(200, 200, 200),
48
+ # "accent": RGBColor(0, 150, 255),
49
+ # "title_font": "Consolas",
50
+ # "text_font": "Consolas"
51
+ # }
52
+ # }
53
+
54
+ # def hex_to_rgb(hex_color):
55
+ # """Convert hex color to RGBColor"""
56
+ # hex_color = hex_color.lstrip('#')
57
+ # return RGBColor(*tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4)))
58
+
59
+ # def extract_theme_from_pptx(uploaded_file):
60
+ # """Extract theme colors and fonts from an uploaded PowerPoint file"""
61
+ # with tempfile.NamedTemporaryFile(delete=False) as tmp_file:
62
+ # tmp_file.write(uploaded_file.read())
63
+ # tmp_file_path = tmp_file.name
64
+
65
+ # prs = Presentation(tmp_file_path)
66
+ # theme = {
67
+ # "background": RGBColor(255, 255, 255), # Default white if not found
68
+ # "title_color": RGBColor(0, 0, 0), # Default black
69
+ # "text_color": RGBColor(0, 0, 0), # Default black
70
+ # "accent": RGBColor(79, 129, 189), # Default blue
71
+ # "title_font": "Calibri",
72
+ # "text_font": "Calibri",
73
+ # "template_path": tmp_file_path # Store the template path for later use
74
+ # }
75
+
76
+ # try:
77
+ # # Get colors from master slide
78
+ # slide_master = prs.slide_master
79
+
80
+ # # Handle background color
81
+ # if hasattr(slide_master.background, 'fill'):
82
+ # if slide_master.background.fill.type == 1: # Solid fill
83
+ # theme["background"] = slide_master.background.fill.fore_color.rgb
84
+
85
+ # # Try to get title and text colors from placeholders
86
+ # for shape in slide_master.shapes:
87
+ # if shape.has_text_frame and shape.text.strip():
88
+ # try:
89
+ # if shape.name.lower() == 'title':
90
+ # theme["title_color"] = shape.text_frame.paragraphs[0].font.color.rgb
91
+ # theme["title_font"] = shape.text_frame.paragraphs[0].font.name
92
+ # else:
93
+ # theme["text_color"] = shape.text_frame.paragraphs[0].font.color.rgb
94
+ # theme["text_font"] = shape.text_frame.paragraphs[0].font.name
95
+ # except:
96
+ # continue
97
+
98
+ # # Try to get accent color from first shape with fill
99
+ # for shape in slide_master.shapes:
100
+ # if hasattr(shape, 'fill'):
101
+ # try:
102
+ # if shape.fill.type == 1: # Solid fill
103
+ # theme["accent"] = shape.fill.fore_color.rgb
104
+ # break
105
+ # except:
106
+ # continue
107
+
108
+ # except Exception as e:
109
+ # st.warning(f"Couldn't fully extract theme: {str(e)}. Using default colors where needed.")
110
+
111
+ # return theme
112
+
113
+ # def generate_slide_content(topic, slide_count):
114
+ # model = genai.GenerativeModel('gemini-2.0-flash')
115
+ # prompt = f"""Create a comprehensive presentation on '{topic}' with exactly {slide_count} slides.
116
+ # For each slide, provide:
117
+ # 1. A clear title in [Title:] format
118
+ # 2. 3-5 detailed bullet points in [Content:] format (each point should be 2-3 lines/40-60 words)
119
+ # 3. Optional speaker notes in [Notes:] format
120
+ # 4. Layout suggestion in [Layout:] format (title-only, title-content, two-column, section-header)
121
+
122
+ # Structure your response like this:
123
+ # [Title:] Slide Title
124
+ # [Layout:] title-content
125
+ # [Content:]
126
+ # - Main Point 1: Detailed explanation spanning 1-2 lines with supporting information that provides context and value to the audience. This makes each point substantial.
127
+ # - Main Point 2: Another complete thought with sufficient detail to stand alone as a mini-paragraph, giving the audience concrete information they can use.
128
+ # - Main Point 3: Final point with enough depth to be meaningful, typically consisting of 2-3 sentences that develop a complete idea.
129
+ # [Notes:] Additional notes here
130
+
131
+ # Important guidelines:
132
+ # - Do not give only placeholders or labels. Write full, rich content for each bullet point.
133
+ # - Apply the same for the Questionnaire slide too, don't just keep placeholders, generate 10 questions.
134
+ # - Avoid general outlines β€” generate fully written content as if it's going directly into a slide.
135
+ # - Each bullet point should be 2-3 lines (30-50 words)
136
+ # - Provide complete thoughts with supporting details
137
+ # - Maintain parallel structure across points
138
+ # - Avoid single-sentence bullet points
139
+ # - Focus on substance over brevity
140
+
141
+ # Include these sections (adjust based on requested slide count):
142
+ # - Title slide
143
+ # - Introduction/Overview
144
+ # - Key Concepts
145
+ # - Detailed Analysis
146
+ # - Case Studies/Examples
147
+ # - Applications
148
+ # - Challenges
149
+ # - Future Trends
150
+ # - Conclusion
151
+ # - Questionnaire
152
+
153
+ # After generating the content for the above presentation sections,titled [Title:], generate a Questionnaire Slide containing:
154
+ # - 10 multiple-choice questions testing the user’s understanding of the presentation
155
+ # - Each question should have 4 options (A, B, C, D)
156
+ # - Clearly indicate the correct answer after each question using the format: [Correct Answer: C]
157
+ # - Make the questions relevant and cover all key areas: introduction, concepts, analysis, case studies, applications, challenges, and future trends.
158
+ # - Make sure the questions test the user's comprehension of the previous slides' content and are well-distributed across different topics in the presentation.
159
+
160
+ # Please ensure the presentation content is presented first, followed by a clear separator, and then the questionnaire.
161
+
162
+ # Begin the content generation now.
163
+ # """
164
+
165
+ # response = model.generate_content(prompt)
166
+ # return response.text
167
+
168
+ # def parse_slide_content(slide_text):
169
+ # slides = []
170
+ # current_slide = {}
171
+
172
+ # for line in slide_text.split('\n'):
173
+ # line = line.strip()
174
+ # if not line:
175
+ # continue
176
+
177
+ # if line.startswith('[Title:]'):
178
+ # if current_slide:
179
+ # slides.append(current_slide)
180
+ # current_slide = {
181
+ # 'title': line.replace('[Title:]', '').strip(),
182
+ # 'content': [],
183
+ # 'notes': '',
184
+ # 'layout': 'title-content'
185
+ # }
186
+ # elif line.startswith('[Content:]'):
187
+ # content = line.replace('[Content:]', '').strip()
188
+ # if content:
189
+ # current_slide['content'].append(content)
190
+ # elif line.startswith('[Notes:]'):
191
+ # current_slide['notes'] = line.replace('[Notes:]', '').strip()
192
+ # elif line.startswith('[Layout:]'):
193
+ # layout = line.replace('[Layout:]', '').strip().lower()
194
+ # valid_layouts = ['title-only', 'title-content', 'two-column', 'section-header']
195
+ # current_slide['layout'] = layout if layout in valid_layouts else 'title-content'
196
+ # elif current_slide.get('content') is not None and line.startswith('-'):
197
+ # # Simplify bullet points - remove any explanations after colons
198
+ # point = line[1:].strip()
199
+ # if ':' in point:
200
+ # point = point.split(':')[0].strip()
201
+ # current_slide['content'].append(point)
202
+
203
+ # if current_slide:
204
+ # slides.append(current_slide)
205
+
206
+ # return slides
207
+
208
+ # def create_detailed_pptx(slides_data, theme, branding_options=None):
209
+ # """Create PowerPoint using the uploaded template"""
210
+ # # Use the template if one was uploaded
211
+ # if "template_path" in theme and os.path.exists(theme["template_path"]):
212
+ # prs = Presentation(theme["template_path"])
213
+ # else:
214
+ # prs = Presentation()
215
+
216
+ # # Set widescreen layout (16:9 aspect ratio)
217
+ # prs.slide_width = Inches(13.33)
218
+ # prs.slide_height = Inches(7.5)
219
+
220
+ # # Layout mapping
221
+ # layout_indices = {
222
+ # 'title-only': 0,
223
+ # 'title-content': 1,
224
+ # 'section-header': 2,
225
+ # 'two-column': 3
226
+ # }
227
+
228
+ # available_layouts = {}
229
+ # for name, idx in layout_indices.items():
230
+ # if idx < len(prs.slide_layouts):
231
+ # available_layouts[name] = idx
232
+
233
+ # default_layout_idx = available_layouts.get('title-content', 0)
234
+
235
+ # for slide_info in slides_data:
236
+ # layout = slide_info.get('layout', 'title-content').lower()
237
+ # layout_idx = available_layouts.get(layout, default_layout_idx)
238
+
239
+ # try:
240
+ # slide = prs.slides.add_slide(prs.slide_layouts[layout_idx])
241
+ # except IndexError:
242
+ # slide = prs.slides.add_slide(prs.slide_layouts[default_layout_idx])
243
+
244
+ # # Set title
245
+ # title = slide.shapes.title
246
+ # title.text = slide_info['title']
247
+ # title.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
248
+
249
+ # # Only apply custom formatting if not using a template
250
+ # if "template_path" not in theme:
251
+ # # Apply background
252
+ # background = slide.background
253
+ # fill = background.fill
254
+ # fill.solid()
255
+ # fill.fore_color.rgb = theme["background"]
256
+
257
+ # # Format title
258
+ # title.text_frame.paragraphs[0].font.color.rgb = theme["title_color"]
259
+ # title.text_frame.paragraphs[0].font.size = Pt(36)
260
+ # title.text_frame.paragraphs[0].font.bold = True
261
+ # if "title_font" in theme:
262
+ # title.text_frame.paragraphs[0].font.name = theme["title_font"]
263
+
264
+ # # Add logo if provided
265
+ # if branding_options and branding_options.get('logo_path'):
266
+ # add_logo_to_slide(slide, branding_options['logo_path'],
267
+ # branding_options.get('logo_position', 'top-right'))
268
+
269
+ # # Set content based on layout
270
+ # if layout_idx == 3: # Two column layout
271
+ # content = slide_info.get('content', [])
272
+ # mid_point = len(content) // 2
273
+ # left_content = content[:mid_point]
274
+ # right_content = content[mid_point:]
275
+
276
+ # left_body = slide.placeholders[1]
277
+ # left_tf = left_body.text_frame
278
+ # left_tf.clear()
279
+
280
+ # right_body = slide.placeholders[2]
281
+ # right_tf = right_body.text_frame
282
+ # right_tf.clear()
283
+
284
+ # for content_part, tf in [(left_content, left_tf), (right_content, right_tf)]:
285
+ # for point in content_part:
286
+ # p = tf.add_paragraph()
287
+ # point_text = point.replace('- ', '').strip()
288
+ # p.text = point_text
289
+ # p.level = 0
290
+ # p.alignment = PP_ALIGN.JUSTIFY
291
+ # if "template_path" not in theme: # Only apply custom formatting if no template
292
+ # p.font.color.rgb = theme["text_color"]
293
+ # p.font.size = Pt(18)
294
+ # if "text_font" in theme:
295
+ # p.font.name = theme["text_font"]
296
+
297
+ # elif layout_idx != 0: # Not title-only
298
+ # body = slide.placeholders[1]
299
+ # tf = body.text_frame
300
+ # tf.clear()
301
+
302
+ # for point in slide_info.get('content', []):
303
+ # p = tf.add_paragraph()
304
+ # point_text = point.replace('- ', '').strip()
305
+ # p.text = point_text
306
+ # p.level = 0
307
+ # p.alignment = PP_ALIGN.JUSTIFY
308
+ # if "template_path" not in theme: # Only apply custom formatting if no template
309
+ # p.font.color.rgb = theme["text_color"]
310
+ # p.font.size = Pt(18)
311
+ # if "text_font" in theme:
312
+ # p.font.name = theme["text_font"]
313
+
314
+ # # Add notes if available
315
+ # if slide_info.get('notes'):
316
+ # notes_slide = slide.notes_slide
317
+ # notes_slide.notes_text_frame.text = slide_info['notes']
318
+
319
+ # pptx_io = io.BytesIO()
320
+ # prs.save(pptx_io)
321
+ # pptx_io.seek(0)
322
+
323
+ # # Clean up temporary template file
324
+ # if "template_path" in theme and os.path.exists(theme["template_path"]):
325
+ # os.unlink(theme["template_path"])
326
+
327
+ # return pptx_io
328
+
329
+ # def main():
330
+ # st.set_page_config(page_title="Advanced PPTX Generator", layout="wide")
331
+
332
+ # st.title("Advanced PowerPoint Generator")
333
+ # st.markdown("Create professional presentations with AI")
334
+
335
+ # # Initialize session state for custom themes if not exists
336
+ # if 'custom_themes' not in st.session_state:
337
+ # st.session_state.custom_themes = {}
338
+
339
+ # # Combine default and custom themes
340
+ # ALL_THEMES = {**DEFAULT_THEMES, **st.session_state.custom_themes}
341
+ # col1, col2 = st.columns([3, 1])
342
+
343
+ # with col1:
344
+ # topic = st.text_input("Presentation Topic:",
345
+ # placeholder="Enter your topic (e.g., 'AI in Healthcare')")
346
+
347
+ # with st.expander("Advanced Options"):
348
+ # slide_count = st.slider("Number of Slides:", 5, 20, 10)
349
+
350
+ # # Theme selection with example-based option
351
+ # theme_option = st.radio("Theme Selection Method:",
352
+ # ["Predefined Theme", "Custom Theme", "Example-Based Theme"])
353
+
354
+ # theme = DEFAULT_THEMES["Professional Blue"] # Default theme
355
+
356
+ # if theme_option == "Predefined Theme":
357
+ # theme_name = st.selectbox("Select Theme:", list(DEFAULT_THEMES.keys()))
358
+ # theme = DEFAULT_THEMES[theme_name]
359
+ # elif theme_option == "Custom Theme":
360
+ # theme_name = st.selectbox("Select Custom Theme:",
361
+ # ["Create New..."] + list(st.session_state.custom_themes.keys()))
362
+
363
+ # if theme_name == "Create New...":
364
+ # with st.form("custom_theme_form"):
365
+ # new_theme_name = st.text_input("Theme Name")
366
+ # bg_color = st.color_picker("Background Color", "#0C2340")
367
+ # title_color = st.color_picker("Title Color", "#FFFFFF")
368
+ # text_color = st.color_picker("Text Color", "#C8C8C8")
369
+ # accent_color = st.color_picker("Accent Color", "#0070C0")
370
+ # title_font = st.text_input("Title Font", "Calibri")
371
+ # text_font = st.text_input("Text Font", "Calibri")
372
+
373
+ # if st.form_submit_button("Save Custom Theme"):
374
+ # if new_theme_name:
375
+ # st.session_state.custom_themes[new_theme_name] = {
376
+ # "background": hex_to_rgb(bg_color),
377
+ # "title_color": hex_to_rgb(title_color),
378
+ # "text_color": hex_to_rgb(text_color),
379
+ # "accent": hex_to_rgb(accent_color),
380
+ # "title_font": title_font,
381
+ # "text_font": text_font
382
+ # }
383
+ # st.success(f"Theme '{new_theme_name}' saved successfully!")
384
+ # else:
385
+ # st.warning("Please enter a theme name")
386
+ # elif theme_name in st.session_state.custom_themes:
387
+ # theme = st.session_state.custom_themes[theme_name]
388
+ # else: # Example-Based Theme
389
+ # uploaded_file = st.file_uploader("Upload PowerPoint Template", type=["pptx"])
390
+ # if uploaded_file:
391
+ # with st.spinner("Extracting theme from template..."):
392
+ # theme = extract_theme_from_pptx(uploaded_file)
393
+ # st.success("Theme extracted from template!")
394
+ # else:
395
+ # st.info("Please upload a PowerPoint file to extract its theme")
396
+
397
+ # with col2:
398
+ # # st.image("https://huggingface.co/spaces/YashMK89/PPTX_generativeai/resolve/main/SVNIT_IS_DS_Projects.png", width=150)
399
+
400
+ # if st.button("Generate Presentation", type="primary"):
401
+ # if not topic:
402
+ # st.warning("Please enter a topic first!")
403
+ # elif theme_option == "Example-Based Theme" and not uploaded_file:
404
+ # st.warning("Please upload a PowerPoint template file first")
405
+ # else:
406
+ # with st.spinner(f"Creating {slide_count}-slide presentation about '{topic}'..."):
407
+ # try:
408
+ # slide_text = generate_slide_content(topic, slide_count)
409
+ # slides_data = parse_slide_content(slide_text)
410
+
411
+ # # Show slide overview with detailed content
412
+ # with st.expander("Slide Overview (Detailed)"):
413
+ # for i, slide in enumerate(slides_data, 1):
414
+ # st.subheader(f"Slide {i}: {slide['title']}")
415
+ # st.markdown("**Content:**")
416
+ # for point in slide.get('content', []):
417
+ # st.markdown(f"- {point}")
418
+ # if slide.get('notes'):
419
+ # st.markdown(f"**Notes:** {slide['notes']}")
420
+ # st.markdown("---")
421
+
422
+ # pptx_file = create_detailed_pptx(slides_data, theme)
423
+
424
+ # st.success("Presentation generated successfully!")
425
+
426
+ # st.download_button(
427
+ # label="Download PowerPoint",
428
+ # data=pptx_file,
429
+ # file_name=f"{topic.replace(' ', '_')}_presentation.pptx",
430
+ # mime="application/vnd.openxmlformats-officedocument.presentationml.presentation"
431
+ # )
432
+
433
+ # except Exception as e:
434
+ # st.error(f"An error occurred: {str(e)}")
435
+ # if __name__ == "__main__":
436
+ # main()
437
+
438
+
439
  import streamlit as st
440
  import google.generativeai as genai
441
  from pptx import Presentation
 
451
 
452
  # Load the API key securely from environment variable
453
  api_key = os.getenv("GOOGLE_API_KEY")
454
+ if not api_key:
455
+ st.error("GOOGLE_API_KEY environment variable not set!")
456
+ st.stop()
457
  genai.configure(api_key=api_key)
458
 
459
  # Default theme configurations
 
527
  for shape in slide_master.shapes:
528
  if shape.has_text_frame and shape.text.strip():
529
  try:
530
+ if 'title' in shape.name.lower():
531
  theme["title_color"] = shape.text_frame.paragraphs[0].font.color.rgb
532
  theme["title_font"] = shape.text_frame.paragraphs[0].font.name
533
  else:
 
589
  - Challenges
590
  - Future Trends
591
  - Conclusion
592
+
593
+ After generating the content for the above presentation sections, add a clear separator:
594
+ --- QUESTIONNAIRE ---
595
+
596
+ Then generate 10 multiple-choice questions testing the user's understanding of the presentation:
597
+ Format each question like:
598
+ [Question: Your question text here?]
599
+ - [A] Option A
600
+ - [B] Option B
601
+ - [C] Option C
602
+ - [D] Option D
603
+ [Correct: C]
604
+
605
+ Ensure:
606
+ - Questions cover all key areas: introduction, concepts, analysis, case studies, applications, challenges, and future trends
607
+ - Each question has exactly 4 options
608
+ - Clearly indicate the correct answer
609
+ - Questions test comprehension of the presentation content
610
+
611
+ Please ensure the presentation content is presented first, followed by the separator, and then the questionnaire.
612
 
613
  Begin the content generation now.
614
  """
 
619
  def parse_slide_content(slide_text):
620
  slides = []
621
  current_slide = {}
622
+ questionnaire = []
623
+
624
+ # Split into main content and questionnaire
625
+ parts = slide_text.split('--- QUESTIONNAIRE ---')
626
+ main_content = parts[0].strip()
627
+ questionnaire_content = parts[1].strip() if len(parts) > 1 else ""
628
 
629
+ # Parse main slides
630
+ for line in main_content.split('\n'):
631
  line = line.strip()
632
  if not line:
633
  continue
 
661
  if current_slide:
662
  slides.append(current_slide)
663
 
664
+ # Parse questionnaire if exists
665
+ if questionnaire_content:
666
+ current_question = {}
667
+ for line in questionnaire_content.split('\n'):
668
+ line = line.strip()
669
+ if not line:
670
+ continue
671
+
672
+ if line.startswith('[Question:'):
673
+ if current_question:
674
+ questionnaire.append(current_question)
675
+ question_text = line.replace('[Question:', '').replace(']', '').strip()
676
+ current_question = {
677
+ 'text': question_text,
678
+ 'options': [],
679
+ 'correct': ''
680
+ }
681
+ elif line.startswith('- [A]'):
682
+ current_question['options'].append(line.replace('- [A]', '').strip())
683
+ elif line.startswith('- [B]'):
684
+ current_question['options'].append(line.replace('- [B]', '').strip())
685
+ elif line.startswith('- [C]'):
686
+ current_question['options'].append(line.replace('- [C]', '').strip())
687
+ elif line.startswith('- [D]'):
688
+ current_question['options'].append(line.replace('- [D]', '').strip())
689
+ elif line.startswith('[Correct:'):
690
+ current_question['correct'] = line.replace('[Correct:', '').replace(']', '').strip()
691
+
692
+ if current_question:
693
+ questionnaire.append(current_question)
694
+
695
+ return slides, questionnaire
696
+
697
+ def create_questionnaire_slide(prs, questions, theme):
698
+ """Create dedicated questionnaire slide"""
699
+ slide = prs.slides.add_slide(prs.slide_layouts[1]) # Title + Content layout
700
+
701
+ # Set title
702
+ title = slide.shapes.title
703
+ title.text = "Knowledge Check"
704
+
705
+ # Only apply custom formatting if not using a template
706
+ if "template_path" not in theme:
707
+ title.text_frame.paragraphs[0].font.color.rgb = theme["accent"]
708
+ title.text_frame.paragraphs[0].font.size = Pt(36)
709
+ title.text_frame.paragraphs[0].font.bold = True
710
+ if "title_font" in theme:
711
+ title.text_frame.paragraphs[0].font.name = theme["title_font"]
712
+
713
+ # Create content
714
+ body = slide.placeholders[1]
715
+ tf = body.text_frame
716
+ tf.clear()
717
+
718
+ for i, q in enumerate(questions):
719
+ # Add question
720
+ p = tf.add_paragraph()
721
+ p.text = f"{i+1}. {q['text']}"
722
+ p.level = 0
723
+ p.font.bold = True
724
+ p.space_after = Pt(8)
725
+
726
+ # Only apply custom formatting if not using a template
727
+ if "template_path" not in theme:
728
+ p.font.color.rgb = theme["text_color"]
729
+ p.font.size = Pt(20)
730
+ if "text_font" in theme:
731
+ p.font.name = theme["text_font"]
732
+
733
+ # Add options
734
+ for j, opt in enumerate(q['options']):
735
+ p = tf.add_paragraph()
736
+ p.text = f" {chr(65+j)}. {opt}"
737
+ p.level = 1
738
+ p.space_after = Pt(4)
739
+
740
+ # Only apply custom formatting if not using a template
741
+ if "template_path" not in theme:
742
+ p.font.color.rgb = theme["text_color"]
743
+ p.font.size = Pt(18)
744
+ if "text_font" in theme:
745
+ p.font.name = theme["text_font"]
746
+
747
+ # Add space between questions
748
+ p = tf.add_paragraph()
749
+ p.text = ""
750
+ p.space_after = Pt(16)
751
 
752
+ # Add correct answers to speaker notes
753
+ notes_slide = slide.notes_slide
754
+ notes_text = "Correct Answers:\n\n"
755
+ for i, q in enumerate(questions):
756
+ notes_text += f"{i+1}. {q['correct']}\n"
757
+ notes_slide.notes_text_frame.text = notes_text
758
+
759
+ return slide
760
+
761
+ def create_detailed_pptx(slides_data, questions, theme, branding_options=None):
762
  """Create PowerPoint using the uploaded template"""
763
  # Use the template if one was uploaded
764
  if "template_path" in theme and os.path.exists(theme["template_path"]):
 
785
 
786
  default_layout_idx = available_layouts.get('title-content', 0)
787
 
788
+ # Create main slides
789
  for slide_info in slides_data:
790
  layout = slide_info.get('layout', 'title-content').lower()
791
  layout_idx = available_layouts.get(layout, default_layout_idx)
 
870
  notes_slide = slide.notes_slide
871
  notes_slide.notes_text_frame.text = slide_info['notes']
872
 
873
+ # Add questionnaire slide if questions exist
874
+ if questions:
875
+ create_questionnaire_slide(prs, questions, theme)
876
+
877
  pptx_io = io.BytesIO()
878
  prs.save(pptx_io)
879
  pptx_io.seek(0)
 
910
  ["Predefined Theme", "Custom Theme", "Example-Based Theme"])
911
 
912
  theme = DEFAULT_THEMES["Professional Blue"] # Default theme
913
+ uploaded_file = None
914
 
915
  if theme_option == "Predefined Theme":
916
  theme_name = st.selectbox("Select Theme:", list(DEFAULT_THEMES.keys()))
 
954
  st.info("Please upload a PowerPoint file to extract its theme")
955
 
956
  with col2:
957
+ st.markdown("### Instructions")
958
+ st.markdown("1. Enter your presentation topic")
959
+ st.markdown("2. Select slide count and theme")
960
+ st.markdown("3. Click 'Generate Presentation'")
961
+ st.markdown("4. Download your PowerPoint file")
962
 
963
+ if st.button("Generate Presentation", type="primary", key="generate_btn"):
964
  if not topic:
965
  st.warning("Please enter a topic first!")
966
  elif theme_option == "Example-Based Theme" and not uploaded_file:
 
969
  with st.spinner(f"Creating {slide_count}-slide presentation about '{topic}'..."):
970
  try:
971
  slide_text = generate_slide_content(topic, slide_count)
972
+ slides_data, questionnaire = parse_slide_content(slide_text)
973
 
974
  # Show slide overview with detailed content
975
  with st.expander("Slide Overview (Detailed)"):
 
981
  if slide.get('notes'):
982
  st.markdown(f"**Notes:** {slide['notes']}")
983
  st.markdown("---")
984
+
985
+ if questionnaire:
986
+ st.subheader("Questionnaire")
987
+ for i, q in enumerate(questionnaire, 1):
988
+ st.markdown(f"**{i}. {q['text']}**")
989
+ for j, opt in enumerate(q['options']):
990
+ st.markdown(f"- {chr(65+j)}. {opt}")
991
+ st.markdown(f"*Correct: {q['correct']}*")
992
+ st.markdown("---")
993
 
994
+ pptx_file = create_detailed_pptx(slides_data, questionnaire, theme)
995
 
996
  st.success("Presentation generated successfully!")
997
 
 
1004
 
1005
  except Exception as e:
1006
  st.error(f"An error occurred: {str(e)}")
1007
+
1008
  if __name__ == "__main__":
1009
  main()