Skip to content

Commit

Permalink
Add Support for Manual pptx Modifications
Browse files Browse the repository at this point in the history
- Added a new feature that allows odin-slides adopt manual modifications done by the user to the pptx text. This includes manually modified text in the title or the content of the slides.

Changes to be committed:
	modified:   odin_slides/main.py
	modified:   odin_slides/presentation.py
	modified:   setup.py

Fixes #1
  • Loading branch information
leonid20000 committed Sep 27, 2023
1 parent cb57f89 commit 9690391
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 23 deletions.
7 changes: 7 additions & 0 deletions odin_slides/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,13 @@ def main():
print(format_error("Something went wrong: ")+f"{e}"+"\n")
except KeyboardInterrupt:
print("\n"+format_info("Exiting..."))
print("Enjoying this project? Your support means a lot!")
print("If you find this open-source effort helpful, please consider giving it a star on GitHub.")
print("GitHub Repository: https://github.com/leonid20000/odin-slides")
print("Have ideas, found a bug, or need assistance?")
print("Feel free to create issues or submit pull requests on GitHub.")
print("\n"+format_info("Thank you for being part of the open-source community. See you next time!"))

finally:
# Remember to close the log handler when done
for handler in logger.handlers:
Expand Down
114 changes: 93 additions & 21 deletions odin_slides/presentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
- build_slides_with_llm(template_file, word_content, output_file, session_file, logger):
Build slides using a language model (LLM) based on user input.
- get_latest_slide_deck(pptx_file_path, current_slide_deck, logger):
Retrieves information from the latest PowerPoint slide deck in the specified file.
Dependencies:
- difflib
- json
Expand Down Expand Up @@ -145,7 +149,7 @@ def create_presentation(template_file, slide_content, output_file,logger):
prs.save(output_file)
break
except PermissionError:
print(f"Action Required: The file '{output_file}' is open in PowerPoint or another application. Please close it and press Enter to retry.")
print(format_warning("Action Required:")+ f" The file {output_file} is open in PowerPoint or another application." +format_prompt("Please close it and press Enter to retry. "))
logger.error(f"Error: The file '{output_file}' is open in PowerPoint or another application. Please close it and press Enter to retry.")
input() # Wait for the user to close the file
except Exception as e:
Expand All @@ -161,6 +165,62 @@ def create_presentation(template_file, slide_content, output_file,logger):
logger.debug(f"Can not preview the presentation using os default viewer: {e}")


def get_latest_slide_deck(pptx_file_path, current_slide_deck, logger):
"""
Retrieves information from the latest PowerPoint slide deck in the specified file.
Args:
pptx_file_path (str): The path to the PowerPoint file.
current_slide_deck (list): The current list of slide information.
logger (Logger): The logger object for error reporting.
Returns:
list: A list of dictionaries containing slide information, including slide number,
title, content, and narration.
Note:
This function attempts to load the PowerPoint presentation and extract slide
information. If the file is open in another application with a read lock (rare), it will prompt the user
to close it and retry. If the file does not exist, it returns the current slide deck.
"""
presentation = None
while True:
try:
presentation = Presentation(pptx_file_path)
break
except PermissionError:
print(format_warning("Action Required:")+ f" The file {output_file} is open in PowerPoint or another application." +format_prompt("Please close it and press Enter to retry. "))
logger.error(f"Error: The file '{output_file}' is open in PowerPoint or another application. Please close it and press Enter to retry.")
input() # Wait for the user to close the file
except FileNotFoundError:
return current_slide_deck
except Exception as e:
logger.error(f"An unexpected error occurred while loading the presentation: {e}")
return current_slide_deck

updated_slide_deck = []

for slide_number, slide in enumerate(presentation.slides, start=1):
slide_info = {"slide_number": float(slide_number), "title": "", "content": "", "narration": ""}

for shape in slide.shapes:
if shape.has_text_frame:
if shape == slide.shapes[0]: # Assuming the first shape is the title
slide_info["title"] = shape.text
else:
slide_info["content"] += shape.text + "\n"
# Extract notes from the notes slide
notes_slide = slide.notes_slide
for shape in notes_slide.shapes:
if shape.has_text_frame:
slide_info["narration"] += shape.text + "\n"

updated_slide_deck.append(slide_info)

return updated_slide_deck


def build_slides_with_llm(template_file,word_content, output_file, session_file, logger):
"""Build slides using a language model (LLM) based on user input.
Expand All @@ -175,23 +235,30 @@ def build_slides_with_llm(template_file,word_content, output_file, session_file,
slide_deck_history=[[]]
try:
if not session_file:
# Ask the user for prompt
prompt = input(format_prompt("\nWhat slides shall I make for you? "))
print(format_info("OK, please wait. This might take a while...")+"\n")
slide_deck=get_chat_response(word_content,[], prompt,logger)
logger.debug(slide_deck)
while True:
try:
slide_deck=ensure_list(json.loads(slide_deck))
slide_deck_history=[slide_deck]
break
except Exception as e:
logger.debug("Not neccessarily an error but Invalid JSON string")
logger.debug(e)
# Ask the user for prompt
prompt = input(format_prompt("Hmm, not sure what you want so I did not make any changes. Try differently: "))
print(format_info("OK, please wait. This might take a while...")+"\n")
slide_deck=get_chat_response(word_content,[], prompt,logger)
initial_slide_deck = get_latest_slide_deck(output_file, [], logger)
if initial_slide_deck != []:
print(format_warning("The output file is not empty but no session file is supplied. If you have the session file, consider continuing from the previously saved session.")+"\n")
print(format_info("Loading the existing text content of the file into a new session...")+"\n")
slide_deck = initial_slide_deck
slide_deck_history=[slide_deck]
else:
# Ask the user for prompt
prompt = input(format_prompt("\nWhat shall I do for you? "))
print(format_info("OK, please wait. This might take a while...")+"\n")
slide_deck=get_chat_response(word_content, initial_slide_deck, prompt,logger)
logger.debug(slide_deck)
while True:
try:
slide_deck=ensure_list(json.loads(slide_deck))
slide_deck_history=[slide_deck]
break
except Exception as e:
logger.debug("Not neccessarily an error but Invalid JSON string")
logger.debug(e)
# Ask the user for prompt
prompt = input(format_prompt("Hmm, not sure what you want so I did not make any changes. Try differently: "))
print(format_info("OK, please wait. This might take a while...")+"\n")
slide_deck=get_chat_response(word_content,[], prompt,logger)



Expand All @@ -204,7 +271,8 @@ def build_slides_with_llm(template_file,word_content, output_file, session_file,
logger.debug(loaded_data)
# Access slide_deck_history variable from the loaded data
slide_deck_history = loaded_data['slide_deck_history']
slide_deck=slide_deck_history[-1]
slide_deck = get_latest_slide_deck(output_file, slide_deck_history[-1], logger)
slide_deck_history[-1] = slide_deck
logger.debug(slide_deck)

while True:
Expand All @@ -216,6 +284,7 @@ def build_slides_with_llm(template_file,word_content, output_file, session_file,
slide_deck_history.pop() if len(slide_deck_history) > 1 else None
slide_deck = slide_deck_history[-1]
continue
slide_deck = get_latest_slide_deck(output_file, slide_deck, logger)
result=get_chat_response(word_content,slide_deck, prompt,logger)
try:
result=ensure_list(json.loads(result))
Expand Down Expand Up @@ -265,9 +334,12 @@ def build_slides_with_llm(template_file,word_content, output_file, session_file,
logger.error("Something went wrong while making presentation:")
logger.error(e)
finally:
print("\nSaving the session to "+output_file.replace(".", "_")+'_session.pkl')
file_name=output_file.replace(".", "_")+'_session.pkl'
if os.path.exists(file_name) and not session_file:
file_name = file_name.replace(".pkl", f"_new.pkl")
print("\nSaving the session to "+file_name)
# Saving variables to a file
with open(output_file.replace(".", "_")+'_session.pkl', 'wb') as file:
with open(file_name, 'wb') as file:
session_data = {
'slide_deck_history': slide_deck_history,
'word_content': word_content
Expand Down
11 changes: 9 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name="odin-slides",
version="0.5",
version="0.6",
packages=find_packages(),
install_requires=[
'python-pptx',
Expand Down Expand Up @@ -43,7 +43,14 @@
6. **Extensibility:**
odin-slides is designed for extensibility, accommodating additional Language Models and file types in forthcoming updates. Anticipate enhanced functionality and new features as the tool evolves.
Stay ahead in the world of presentations with odin-slides — your versatile and intelligent partner in creating impactful content.
### Latest Updates
#### Version 0.6 (September 27, 2023)
- Added a new feature that allows odin-slides adopt manual modifications done by the user to the pptx text. This includes manually modified text in the title or the content of the slides. ([Issue #1](https://github.com/leonid20000/odin-slides/issues/1))
Stay ahead in the world of presentations with odin-slides — your versatile and intelligent helper in creating impactful content.
""",
description="An advanced Python tool that empowers you to effortlessly draft impressive PowerPoint presentations from Word documents using generative AI.",
url="https://github.com/leonid20000/odin-slides",
Expand Down

0 comments on commit 9690391

Please sign in to comment.