bluenevus commited on
Commit
9f2504e
·
verified ·
1 Parent(s): 7b60ebd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -15
app.py CHANGED
@@ -36,13 +36,6 @@ app.config.suppress_callback_exceptions = True
36
  log_messages = []
37
  generated_pptx = None
38
 
39
- # Add the missing add_log function
40
- def add_log(message):
41
- global log_messages
42
- logger.info(message)
43
- log_messages.insert(0, f"{time.strftime('%H:%M:%S')} - {message}") # Insert at the beginning
44
-
45
-
46
  app.layout = html.Div([
47
  dbc.Container([
48
  dbc.Row([
@@ -101,12 +94,146 @@ app.layout = html.Div([
101
  dcc.Interval(id='interval-component', interval=1*1000, n_intervals=0) # Updates every 1 second
102
  ])
103
 
104
- # ... (keep all other functions unchanged)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
 
106
  @app.callback(
107
  Output('slides-content', 'value'),
108
  Output('download-ppt-button', 'disabled'),
109
- Output('download-ppt-button', 'color'),
110
  Input('generate-button', 'n_clicks'),
111
  State('upload-file', 'contents'),
112
  State('document-text', 'value')
@@ -120,21 +247,20 @@ def generate_slides(n_clicks, file_contents, document_text):
120
  decoded = base64.b64decode(content_string)
121
  document_text = decoded.decode('utf-8')
122
  elif not document_text:
123
- return "Please upload a file or enter text.", True, "secondary"
124
 
125
  try:
126
  add_log("Starting slide generation...")
127
  slides_markdown = process_document(document_text)
128
  add_log("Slide generation completed.")
129
- return slides_markdown, True, "secondary" # Keep download button disabled
130
  except Exception as e:
131
  add_log(f"An error occurred during slide generation: {str(e)}")
132
- return f"An error occurred: {str(e)}", True, "secondary"
133
 
134
  @app.callback(
135
  Output('log-output', 'children'),
136
  Output('download-ppt-button', 'disabled', allow_duplicate=True),
137
- Output('download-ppt-button', 'color', allow_duplicate=True),
138
  Input('generate-ppt-button', 'n_clicks'),
139
  State('slides-content', 'value'),
140
  prevent_initial_call=True
@@ -148,11 +274,11 @@ def generate_powerpoint(n_clicks, slides_content):
148
  add_log("Starting PowerPoint generation...")
149
  generated_pptx = markdown_to_pptx(slides_content)
150
  add_log("PowerPoint generation completed.")
151
- return '\n'.join(log_messages[:100]), False, "primary" # Enable download button and change color
152
  except Exception as e:
153
  error_message = f"An error occurred during PowerPoint generation: {str(e)}"
154
  add_log(error_message)
155
- return '\n'.join(log_messages[:100]), True, "secondary"
156
 
157
  @app.callback(
158
  Output("download-pptx", "data"),
 
36
  log_messages = []
37
  generated_pptx = None
38
 
 
 
 
 
 
 
 
39
  app.layout = html.Div([
40
  dbc.Container([
41
  dbc.Row([
 
94
  dcc.Interval(id='interval-component', interval=1*1000, n_intervals=0) # Updates every 1 second
95
  ])
96
 
97
+ def add_log(message):
98
+ global log_messages
99
+ logger.info(message)
100
+ log_messages.insert(0, f"{time.strftime('%H:%M:%S')} - {message}") # Insert at the beginning
101
+
102
+ def process_document(text):
103
+ add_log("Starting document processing...")
104
+ prompt = f"""
105
+ Create a PowerPoint presentation based on the following document.
106
+ Generate slides with titles and content. Format the output as markdown,
107
+ with each slide starting with '# Slide X:' where X is the slide number.
108
+ Use '##' for subtitles and '-' for bullet points. Provide only the
109
+ slides in markdown and nothing else, to intro, no acknowlegements, no outro, no summary, just the powerpoint.
110
+ do not use any other markdown like * or **
111
+ There can only be one slide heading # and one sub heading ## and no more than 5 bullets with "-" per slide
112
+ Document:
113
+ {text}
114
+ """
115
+ add_log("Sending request to Gemini model...")
116
+ response = model.generate_content(prompt)
117
+ add_log("Received response from Gemini model.")
118
+ return response.text
119
+
120
+ def generate_image_prompt(slide_content):
121
+ add_log(f"Generating image prompt for slide: {slide_content[:30]}...")
122
+ prompt = f"""
123
+ Based on the following slide content, create a detailed prompt for generating
124
+ an image that represents the main idea of the slide. The image should be
125
+ suitable for a professional presentation.
126
+ Slide content:
127
+ {slide_content}
128
+ Image prompt:
129
+ """
130
+ response = model.generate_content(prompt)
131
+ add_log("Image prompt generated.")
132
+ return response.text
133
+
134
+ def generate_image(prompt):
135
+ add_log(f"Generating image for prompt: {prompt[:30]}...")
136
+ url = "https://api.stability.ai/v2beta/stable-image/generate/sd3"
137
+ headers = {
138
+ "Authorization": f"Bearer {STABILITY_API_KEY}",
139
+ "Accept": "image/*"
140
+ }
141
+ data = {
142
+ "prompt": prompt,
143
+ "output_format": "png"
144
+ }
145
+ files = {"none": ''}
146
+
147
+ try:
148
+ response = requests.post(url, headers=headers, data=data, files=files)
149
+ response.raise_for_status()
150
+ add_log("Image generated successfully.")
151
+ return response.content
152
+ except requests.exceptions.RequestException as e:
153
+ add_log(f"Error generating image: {str(e)}")
154
+ return None
155
+
156
+ def markdown_to_pptx(md_text):
157
+ add_log("Starting PowerPoint generation...")
158
+ prs = Presentation()
159
+ slides = re.split(r'# Slide \d+:', md_text)
160
+ slides = [slide.strip() for slide in slides if slide.strip()]
161
+
162
+ with ThreadPoolExecutor() as executor:
163
+ futures = []
164
+ for i, slide_content in enumerate(slides):
165
+ add_log(f"Processing slide {i+1}/{len(slides)}...")
166
+ image_prompt = generate_image_prompt(slide_content)
167
+ futures.append(executor.submit(generate_image, image_prompt))
168
+
169
+ for i, (slide_content, future) in enumerate(zip(slides, futures)):
170
+ add_log(f"Creating slide {i+1}/{len(slides)}...")
171
+ lines = slide_content.split('\n')
172
+ title = lines[0].strip()
173
+ current_slide = prs.slides.add_slide(prs.slide_layouts[6]) # Blank layout
174
+
175
+ # Add title
176
+ title_box = current_slide.shapes.add_textbox(Inches(0.5), Inches(0.5), Inches(9), Inches(1))
177
+ title_box.text_frame.text = title
178
+ title_box.text_frame.paragraphs[0].font.size = Pt(32)
179
+ title_box.text_frame.paragraphs[0].font.bold = True
180
+
181
+ # Add content (left side)
182
+ content_box = current_slide.shapes.add_textbox(Inches(0.5), Inches(1.5), Inches(4.5), Inches(6))
183
+ text_frame = content_box.text_frame
184
+ text_frame.word_wrap = True
185
+ for line in lines[1:]:
186
+ if line.startswith('## '):
187
+ p = text_frame.add_paragraph()
188
+ p.text = line[3:].strip()
189
+ p.font.size = Pt(24)
190
+ p.font.bold = True
191
+ elif line.startswith('- '):
192
+ p = text_frame.add_paragraph()
193
+ p.text = line[2:].strip()
194
+ p.font.size = Pt(18)
195
+ p.level = 1
196
+ p.bullet = True
197
+
198
+ # Add image (right side)
199
+ add_log(f"Adding image to slide {i+1}...")
200
+ image_data = future.result()
201
+ if image_data:
202
+ image_stream = io.BytesIO(image_data)
203
+ try:
204
+ img = Image.open(image_stream)
205
+ aspect_ratio = img.width / img.height
206
+ img_width = Inches(4)
207
+ img_height = img_width / aspect_ratio
208
+ current_slide.shapes.add_picture(image_stream, Inches(5.5), Inches(1.5), width=img_width, height=img_height)
209
+ add_log(f"Image added successfully to slide {i+1}.")
210
+ except Exception as e:
211
+ add_log(f"Error adding image to slide {i+1}: {str(e)}")
212
+ placeholder = current_slide.shapes.add_textbox(Inches(5.5), Inches(1.5), Inches(4), Inches(6))
213
+ placeholder.text_frame.text = "Image addition failed"
214
+ else:
215
+ add_log(f"Failed to generate image for slide {i+1}: {title}")
216
+ placeholder = current_slide.shapes.add_textbox(Inches(5.5), Inches(1.5), Inches(4), Inches(6))
217
+ placeholder.text_frame.text = "Image generation failed"
218
+
219
+ add_log("PowerPoint generation completed.")
220
+ output = io.BytesIO()
221
+ prs.save(output)
222
+ return output.getvalue()
223
+
224
+ @app.callback(
225
+ Output('upload-file-name', 'children'),
226
+ Input('upload-file', 'filename')
227
+ )
228
+ def update_filename(filename):
229
+ if filename:
230
+ return html.Div(f"Selected file: {filename}")
231
+ return ""
232
+
233
 
234
  @app.callback(
235
  Output('slides-content', 'value'),
236
  Output('download-ppt-button', 'disabled'),
 
237
  Input('generate-button', 'n_clicks'),
238
  State('upload-file', 'contents'),
239
  State('document-text', 'value')
 
247
  decoded = base64.b64decode(content_string)
248
  document_text = decoded.decode('utf-8')
249
  elif not document_text:
250
+ return "Please upload a file or enter text.", True
251
 
252
  try:
253
  add_log("Starting slide generation...")
254
  slides_markdown = process_document(document_text)
255
  add_log("Slide generation completed.")
256
+ return slides_markdown, False # Enable download button
257
  except Exception as e:
258
  add_log(f"An error occurred during slide generation: {str(e)}")
259
+ return f"An error occurred: {str(e)}", True
260
 
261
  @app.callback(
262
  Output('log-output', 'children'),
263
  Output('download-ppt-button', 'disabled', allow_duplicate=True),
 
264
  Input('generate-ppt-button', 'n_clicks'),
265
  State('slides-content', 'value'),
266
  prevent_initial_call=True
 
274
  add_log("Starting PowerPoint generation...")
275
  generated_pptx = markdown_to_pptx(slides_content)
276
  add_log("PowerPoint generation completed.")
277
+ return '\n'.join(log_messages[:100]), False # Enable download button
278
  except Exception as e:
279
  error_message = f"An error occurred during PowerPoint generation: {str(e)}"
280
  add_log(error_message)
281
+ return '\n'.join(log_messages[:100]), True
282
 
283
  @app.callback(
284
  Output("download-pptx", "data"),