barunsaha commited on
Commit
c1acf68
1 Parent(s): 815286a

Fix #29: improve JSON handling and keys

Browse files
Files changed (2) hide show
  1. app.py +31 -20
  2. helpers/pptx_helper.py +32 -24
app.py CHANGED
@@ -7,7 +7,7 @@ import os
7
  import pathlib
8
  import random
9
  import tempfile
10
- from typing import List
11
 
12
  import json5
13
  import streamlit as st
@@ -240,7 +240,9 @@ def set_up_chat_ui():
240
  progress_bar.progress(1.0, text='Done!')
241
 
242
  st.chat_message('ai').code(response, language='json')
243
- _display_download_button(path)
 
 
244
 
245
  logger.info(
246
  '#messages in history / 2: %d',
@@ -248,15 +250,38 @@ def set_up_chat_ui():
248
  )
249
 
250
 
251
- def generate_slide_deck(json_str: str) -> pathlib.Path:
252
  """
253
  Create a slide deck and return the file path. In case there is any error creating the slide
254
  deck, the path may be to an empty file.
255
 
256
  :param json_str: The content in *valid* JSON format.
257
- :return: The file of the .pptx file.
258
  """
259
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
260
  if DOWNLOAD_FILE_KEY in st.session_state:
261
  path = pathlib.Path(st.session_state[DOWNLOAD_FILE_KEY])
262
  else:
@@ -267,24 +292,10 @@ def generate_slide_deck(json_str: str) -> pathlib.Path:
267
  if temp:
268
  temp.close()
269
 
270
- logger.debug('Creating PPTX file: %s...', st.session_state[DOWNLOAD_FILE_KEY])
271
-
272
  try:
 
273
  pptx_helper.generate_powerpoint_presentation(
274
- json_str,
275
- slides_template=pptx_template,
276
- output_file_path=path
277
- )
278
- except ValueError:
279
- st.error(
280
- 'Encountered error while parsing JSON...will fix it and retry'
281
- )
282
- logger.error(
283
- 'Caught ValueError: trying again after repairing JSON...'
284
- )
285
-
286
- pptx_helper.generate_powerpoint_presentation(
287
- text_helper.fix_malformed_json(json_str),
288
  slides_template=pptx_template,
289
  output_file_path=path
290
  )
 
7
  import pathlib
8
  import random
9
  import tempfile
10
+ from typing import List, Union
11
 
12
  import json5
13
  import streamlit as st
 
240
  progress_bar.progress(1.0, text='Done!')
241
 
242
  st.chat_message('ai').code(response, language='json')
243
+
244
+ if path:
245
+ _display_download_button(path)
246
 
247
  logger.info(
248
  '#messages in history / 2: %d',
 
250
  )
251
 
252
 
253
+ def generate_slide_deck(json_str: str) -> Union[pathlib.Path, None]:
254
  """
255
  Create a slide deck and return the file path. In case there is any error creating the slide
256
  deck, the path may be to an empty file.
257
 
258
  :param json_str: The content in *valid* JSON format.
259
+ :return: The path to the .pptx file or `None` in case of error.
260
  """
261
 
262
+ try:
263
+ parsed_data = json5.loads(json_str)
264
+ except ValueError:
265
+ st.error(
266
+ 'Encountered error while parsing JSON...will fix it and retry'
267
+ )
268
+ logger.error(
269
+ 'Caught ValueError: trying again after repairing JSON...'
270
+ )
271
+ try:
272
+ parsed_data = json5.loads(text_helper.fix_malformed_json(json_str))
273
+ except ValueError:
274
+ st.error(
275
+ 'Encountered an error again while fixing JSON...'
276
+ 'the slide deck cannot be created, unfortunately ☹'
277
+ '\nPlease try again later.'
278
+ )
279
+ logger.error(
280
+ 'Caught ValueError: failed to repair JSON!'
281
+ )
282
+
283
+ return None
284
+
285
  if DOWNLOAD_FILE_KEY in st.session_state:
286
  path = pathlib.Path(st.session_state[DOWNLOAD_FILE_KEY])
287
  else:
 
292
  if temp:
293
  temp.close()
294
 
 
 
295
  try:
296
+ logger.debug('Creating PPTX file: %s...', st.session_state[DOWNLOAD_FILE_KEY])
297
  pptx_helper.generate_powerpoint_presentation(
298
+ parsed_data,
 
 
 
 
 
 
 
 
 
 
 
 
 
299
  slides_template=pptx_template,
300
  output_file_path=path
301
  )
helpers/pptx_helper.py CHANGED
@@ -82,21 +82,19 @@ def remove_slide_number_from_heading(header: str) -> str:
82
 
83
 
84
  def generate_powerpoint_presentation(
85
- structured_data: str,
86
  slides_template: str,
87
  output_file_path: pathlib.Path
88
  ) -> List:
89
  """
90
  Create and save a PowerPoint presentation file containing the content in JSON format.
91
 
92
- :param structured_data: The presentation contents as "JSON" (may contain trailing commas).
93
  :param slides_template: The PPTX template to use.
94
  :param output_file_path: The path of the PPTX file to save as.
95
  :return: A list of presentation title and slides headers.
96
  """
97
 
98
- # The structured "JSON" might contain trailing commas, so using json5
99
- parsed_data = json5.loads(structured_data)
100
  presentation = pptx.Presentation(GlobalConfig.PPTX_TEMPLATE_FILES[slides_template]['file'])
101
  slide_width_inch, slide_height_inch = _get_slide_width_height_inches(presentation)
102
 
@@ -237,21 +235,22 @@ def _handle_default_display(
237
 
238
  status = False
239
 
240
- if random.random() < IMAGE_DISPLAY_PROBABILITY:
241
- if random.random() < FOREGROUND_IMAGE_PROBABILITY:
242
- status = _handle_display_image__in_foreground(
243
- presentation,
244
- slide_json,
245
- slide_width_inch,
246
- slide_height_inch
247
- )
248
- else:
249
- status = _handle_display_image__in_background(
250
- presentation,
251
- slide_json,
252
- slide_width_inch,
253
- slide_height_inch
254
- )
 
255
 
256
  if status:
257
  return
@@ -301,7 +300,8 @@ def _handle_display_image__in_foreground(
301
  slide_height_inch: float
302
  ) -> bool:
303
  """
304
- Create a slide with text and image using a picture placeholder layout.
 
305
 
306
  :param presentation: The presentation object.
307
  :param slide_json: The content of the slide as JSON data.
@@ -386,7 +386,8 @@ def _handle_display_image__in_background(
386
  ) -> bool:
387
  """
388
  Add a slide with text and an image in the background. It works just like
389
- `_handle_default_display()` but with a background image added.
 
390
 
391
  :param presentation: The presentation object.
392
  :param slide_json: The content of the slide as JSON data.
@@ -566,6 +567,14 @@ def _handle_icons_ideas(
566
  for run in paragraph.runs:
567
  run.font.color.theme_color = pptx.enum.dml.MSO_THEME_COLOR.TEXT_2
568
 
 
 
 
 
 
 
 
 
569
  return True
570
 
571
  return False
@@ -928,7 +937,6 @@ if __name__ == '__main__':
928
  "AI for predicting student performance and dropout rates"
929
  ],
930
  "key_message": "AI is personalizing education and improving student outcomes",
931
- "img_keywords": "education, personalized learning, intelligent tutoring, student performance"
932
  },
933
  {
934
  "heading": "Step-by-Step: AI Development Process",
@@ -940,7 +948,7 @@ if __name__ == '__main__':
940
  ">> Deploy and monitor the AI system"
941
  ],
942
  "key_message": "Developing AI involves a structured process from problem definition to deployment",
943
- "img_keywords": "AI development process, problem definition, data collection, model training"
944
  },
945
  {
946
  "heading": "AI Icons: Key Aspects",
@@ -974,7 +982,7 @@ if __name__ == '__main__':
974
  generate_powerpoint_presentation(
975
  json5.loads(_JSON_DATA),
976
  output_file_path=path,
977
- slides_template='Minimalist Sales Pitch'
978
  )
979
  print(f'File path: {path}')
980
 
 
82
 
83
 
84
  def generate_powerpoint_presentation(
85
+ parsed_data: dict,
86
  slides_template: str,
87
  output_file_path: pathlib.Path
88
  ) -> List:
89
  """
90
  Create and save a PowerPoint presentation file containing the content in JSON format.
91
 
92
+ :param parsed_data: The presentation content as parsed JSON data.
93
  :param slides_template: The PPTX template to use.
94
  :param output_file_path: The path of the PPTX file to save as.
95
  :return: A list of presentation title and slides headers.
96
  """
97
 
 
 
98
  presentation = pptx.Presentation(GlobalConfig.PPTX_TEMPLATE_FILES[slides_template]['file'])
99
  slide_width_inch, slide_height_inch = _get_slide_width_height_inches(presentation)
100
 
 
235
 
236
  status = False
237
 
238
+ if 'img_keywords' in slide_json:
239
+ if random.random() < IMAGE_DISPLAY_PROBABILITY:
240
+ if random.random() < FOREGROUND_IMAGE_PROBABILITY:
241
+ status = _handle_display_image__in_foreground(
242
+ presentation,
243
+ slide_json,
244
+ slide_width_inch,
245
+ slide_height_inch
246
+ )
247
+ else:
248
+ status = _handle_display_image__in_background(
249
+ presentation,
250
+ slide_json,
251
+ slide_width_inch,
252
+ slide_height_inch
253
+ )
254
 
255
  if status:
256
  return
 
300
  slide_height_inch: float
301
  ) -> bool:
302
  """
303
+ Create a slide with text and image using a picture placeholder layout. If not image keyword is
304
+ available, it will add only text to the slide.
305
 
306
  :param presentation: The presentation object.
307
  :param slide_json: The content of the slide as JSON data.
 
386
  ) -> bool:
387
  """
388
  Add a slide with text and an image in the background. It works just like
389
+ `_handle_default_display()` but with a background image added. If not image keyword is
390
+ available, it will add only text to the slide.
391
 
392
  :param presentation: The presentation object.
393
  :param slide_json: The content of the slide as JSON data.
 
567
  for run in paragraph.runs:
568
  run.font.color.theme_color = pptx.enum.dml.MSO_THEME_COLOR.TEXT_2
569
 
570
+ _add_text_at_bottom(
571
+ slide=slide,
572
+ slide_width_inch=slide_width_inch,
573
+ slide_height_inch=slide_height_inch,
574
+ text='More icons available in the SlideDeck AI repository',
575
+ hyperlink='https://github.com/barun-saha/slide-deck-ai/tree/main/icons/png128'
576
+ )
577
+
578
  return True
579
 
580
  return False
 
937
  "AI for predicting student performance and dropout rates"
938
  ],
939
  "key_message": "AI is personalizing education and improving student outcomes",
 
940
  },
941
  {
942
  "heading": "Step-by-Step: AI Development Process",
 
948
  ">> Deploy and monitor the AI system"
949
  ],
950
  "key_message": "Developing AI involves a structured process from problem definition to deployment",
951
+ "img_keywords": ""
952
  },
953
  {
954
  "heading": "AI Icons: Key Aspects",
 
982
  generate_powerpoint_presentation(
983
  json5.loads(_JSON_DATA),
984
  output_file_path=path,
985
+ slides_template='Basic'
986
  )
987
  print(f'File path: {path}')
988