ash2203's picture
Update app.py
e67bae6 verified
import streamlit as st
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
from groq import Groq
import os
import json
from dotenv import load_dotenv
import tempfile
from tenacity import retry, stop_after_attempt, wait_fixed
import random
load_dotenv()
# Color palettes inspired by Shutterstock
COLOR_PALETTES = [
{
'primary': RGBColor(255, 87, 51), # Orange
'secondary': RGBColor(0, 115, 207), # Blue
'accent': RGBColor(255, 255, 255), # White
'text': RGBColor(51, 51, 51), # Dark Gray
'background': RGBColor(242, 242, 242) # Light Gray
},
{
'primary': RGBColor(102, 45, 145), # Purple
'secondary': RGBColor(255, 230, 0), # Yellow
'accent': RGBColor(0, 255, 255), # Cyan
'text': RGBColor(51, 51, 51), # Dark Gray
'background': RGBColor(230, 230, 250) # Lavender
},
{
'primary': RGBColor(0, 176, 80), # Green
'secondary': RGBColor(255, 192, 0), # Gold
'accent': RGBColor(0, 112, 192), # Blue
'text': RGBColor(51, 51, 51), # Dark Gray
'background': RGBColor(240, 255, 240) # Honeydew
},
{
'primary': RGBColor(192, 0, 0), # Red
'secondary': RGBColor(0, 176, 240), # Light Blue
'accent': RGBColor(255, 255, 255), # White
'text': RGBColor(51, 51, 51), # Dark Gray
'background': RGBColor(255, 240, 245) # Lavender Blush
},
{
'primary': RGBColor(0, 80, 115), # Dark Blue
'secondary': RGBColor(255, 140, 0), # Dark Orange
'accent': RGBColor(0, 176, 80), # Green
'text': RGBColor(51, 51, 51), # Dark Gray
'background': RGBColor(240, 248, 255) # Alice Blue
}
]
def get_random_color_palette():
return random.choice(COLOR_PALETTES)
def apply_theme(prs, color_scheme):
# Apply theme colors to the master slide
background = prs.slide_masters[0].background
background.fill.solid()
background.fill.fore_color.rgb = color_scheme['background']
# Apply theme colors to placeholders
for shape in prs.slide_masters[0].placeholders:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
run.font.color.rgb = color_scheme['text']
def create_title_slide(prs, title, color_scheme):
slide_layout = prs.slide_layouts[0] # Title Slide layout
slide = prs.slides.add_slide(slide_layout)
title_shape = slide.shapes.title
subtitle_shape = slide.placeholders[1]
title_shape.text = title
title_shape.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
title_shape.text_frame.paragraphs[0].font.color.rgb = color_scheme['primary']
title_shape.text_frame.paragraphs[0].font.size = Pt(44)
subtitle_shape.text = "Generated with AI"
subtitle_shape.text_frame.paragraphs[0].alignment = PP_ALIGN.CENTER
subtitle_shape.text_frame.paragraphs[0].font.color.rgb = color_scheme['secondary']
subtitle_shape.text_frame.paragraphs[0].font.size = Pt(24)
def create_content_slide(prs, title, content, color_scheme):
slide_layout = prs.slide_layouts[1] # Content with Caption layout
slide = prs.slides.add_slide(slide_layout)
title_shape = slide.shapes.title
title_shape.text = title
title_shape.text_frame.paragraphs[0].font.color.rgb = color_scheme['primary']
title_shape.text_frame.paragraphs[0].font.size = Pt(36)
content_shape = slide.placeholders[1]
tf = content_shape.text_frame
tf.clear() # Clear existing text
# Add main content
p = tf.paragraphs[0]
p.text = content['main']
p.font.size = Pt(18)
p.font.color.rgb = color_scheme['text']
# Add bullet points
for bullet in content['bullets']:
p = tf.add_paragraph()
p.text = bullet
p.level = 1
p.font.size = Pt(16)
p.font.color.rgb = color_scheme['text']
# Add a subtle accent to the slide
left = Inches(0)
top = Inches(6.5)
width = prs.slide_width
height = Inches(0.5)
shape = slide.shapes.add_shape(1, left, top, width, height)
shape.fill.solid()
shape.fill.fore_color.rgb = color_scheme['accent']
shape.line.color.rgb = color_scheme['accent']
@retry(stop=stop_after_attempt(5), wait=wait_fixed(2))
def generate_slides_content(user_input, num_slides):
client = Groq(
api_key=os.environ.get("GROQ_API_KEY"),)
prompt = f"""
Based on the following input, generate a PowerPoint presentation structure with exactly {num_slides} slides.
The output should be a JSON array of slides, where each slide is an object with a 'title', 'main' content, and 'bullets' (an array of bullet points).
Make sure the content is concise and suitable for a presentation.
User Input: {user_input}
Example output format:
[
{{
"title": "Slide Title",
"main": "Main content of the slide",
"bullets": ["Bullet point 1", "Bullet point 2", "Bullet point 3"]
}},
// ... more slides (total should be {num_slides})
]
"""
try:
chat_completion = client.chat.completions.create(
messages=[
{"role": "system", "content": "You are a helpful assistant that generates PowerPoint presentation content and return the content in JSON format."},
{"role": "user", "content": prompt}
],
model="mixtral-8x7b-32768",
temperature=1,
max_tokens=8000
)
return json.loads(chat_completion.choices[0].message.content)
except json.JSONDecodeError:
st.error("Error: Invalid JSON response from the AI. Retrying...")
raise
except Exception as e:
st.error(f"An error occurred: {str(e)}. Retrying...")
raise
def generate_presentation(user_input, num_slides):
try:
slides_content = generate_slides_content(user_input, num_slides)
prs = Presentation()
color_scheme = get_random_color_palette()
apply_theme(prs, color_scheme)
# Create title slide
create_title_slide(prs, slides_content[0]['title'], color_scheme)
# Create content slides
for slide in slides_content[1:]: # Skip the first slide as it's used for the title
create_content_slide(prs, slide['title'], {'main': slide['main'], 'bullets': slide['bullets']}, color_scheme)
with tempfile.NamedTemporaryFile(delete=False, suffix='.pptx') as tmp:
prs.save(tmp.name)
return tmp.name
except Exception as e:
st.error(f"Failed to generate presentation: {str(e)}")
return None
def main():
st.set_page_config(page_title="PowerPoint Generator", page_icon="📊", layout="wide")
st.title("🎨 AI-Powered PowerPoint Generator")
st.write("Enter your presentation idea and the number of slides you want, and we'll generate a stylish PowerPoint for you!")
user_input = st.text_area("Enter the content idea for your presentation:", height=150)
num_slides = st.number_input("Number of slides:", min_value=2, max_value=20, value=5)
if st.button("Generate Presentation", use_container_width=True, type="primary"):
if user_input and num_slides:
with st.spinner("Generating your stylish presentation... This may take a moment."):
ppt_file = generate_presentation(user_input, num_slides)
if ppt_file:
st.success("Presentation generated successfully!")
with open(ppt_file, "rb") as file:
st.download_button(
label="Download PowerPoint",
data=file,
file_name="generated_presentation.pptx",
mime="application/vnd.openxmlformats-officedocument.presentationml.presentation"
)
else:
st.error("Failed to generate the presentation. Please try again.")
else:
st.warning("Please enter content and specify the number of slides (minimum 2).")
if __name__ == "__main__":
main()