Spaces:
Running
Running
File size: 8,356 Bytes
ee87229 60626c2 ee87229 e67bae6 ee87229 dfeff36 ee87229 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
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() |