File size: 11,570 Bytes
7c1b343
 
57eccf2
 
7c1b343
57eccf2
7c1b343
57eccf2
 
 
 
 
7c1b343
57eccf2
 
 
 
 
7c1b343
57eccf2
 
 
7c1b343
57eccf2
 
7c1b343
57eccf2
 
 
 
7c1b343
57eccf2
7c1b343
 
57eccf2
7c1b343
 
 
 
57eccf2
 
 
 
 
7c1b343
57eccf2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7c1b343
57eccf2
 
 
 
7c1b343
 
57eccf2
7c1b343
57eccf2
7c1b343
 
 
 
 
57eccf2
 
7c1b343
57eccf2
 
 
 
7c1b343
 
57eccf2
 
7c1b343
57eccf2
 
7c1b343
 
 
 
57eccf2
 
7c1b343
57eccf2
 
 
 
7c1b343
 
 
57eccf2
 
 
7c1b343
 
 
 
 
57eccf2
 
 
 
 
 
 
 
 
 
7c1b343
57eccf2
7c1b343
 
 
57eccf2
 
 
7c1b343
 
 
57eccf2
 
 
 
 
 
 
7c1b343
57eccf2
7c1b343
57eccf2
 
 
 
7c1b343
57eccf2
 
 
 
 
 
 
7c1b343
57eccf2
 
 
7c1b343
57eccf2
 
 
7c1b343
57eccf2
 
 
 
 
 
 
7c1b343
 
 
 
57eccf2
 
 
 
 
 
 
 
 
 
 
 
7c1b343
57eccf2
7c1b343
57eccf2
7c1b343
 
 
 
57eccf2
 
 
 
 
 
 
 
 
 
 
 
 
7c1b343
57eccf2
 
 
 
7c1b343
 
 
 
 
 
 
 
57eccf2
 
 
 
 
 
 
 
 
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
import streamlit as st
import os
from PIL import Image
from io import BytesIO
import zipfile
from dotenv import load_dotenv

# Import from helper_utilities.py
from utils.helper_utilities import (
    get_next_largest_aspect_ratio, draw_crop_preview, 
    add_custom_message, generate_flux_image
)

# Import from configuration.py
from utils.configuration import (
    default_guidance_scale, default_num_inference_steps, 
    default_seed, holiday_border_prompts, example_holiday_messages, fonts
)

# Streamlit app starts here
st.image("img/fireworksai_logo.png")
st.title("πŸŽ„ Holiday Card Customizer πŸŽ…")

st.markdown("""
✨ Welcome to the **Holiday Card Generator**! Get ready to sprinkle some holiday magic onto your custom card with a festive border and a heartfelt message. Here's how you can spread the holiday cheer: 

1. 🎁 **Upload your image** – Select a photo or design to be the star of your holiday card.
2. ✨ **Design your holiday card border** – Choose from seasonal prompts or create your own unique design.
3. πŸ’Œ **Add your personal holiday message** – Make it meaningful, funny, or warm-hearted!
4. πŸ“¦ **Download your finished card** – Ready to send to friends and family.

Let’s bring your holiday greetings to life! πŸŽ‰
""")

# Initialize session state variables
if 'uploaded_file' not in st.session_state:
    st.session_state.uploaded_file = None
if 'generated_image' not in st.session_state:
    st.session_state.generated_image = None
if 'metadata' not in st.session_state:
    st.session_state.metadata = {}

st.divider()
st.subheader("πŸŽ… Step 1: Load Your Fireworks API Key πŸŽ„")

# Load API Key
# Define and ensure the .env directory and file exist
dotenv_path = os.path.join(os.path.dirname(__file__), '..', 'env', '.env')
os.makedirs(os.path.dirname(dotenv_path), exist_ok=True)

# Create the .env file if it doesn't exist
if not os.path.exists(dotenv_path):
    with open(dotenv_path, "w") as f:
        st.success(f"Created {dotenv_path}")

# Load environment variables from the .env file
load_dotenv(dotenv_path, override=True)

# Check if the Fireworks API key is set or blank
fireworks_api_key = os.getenv("FIREWORKS_API_KEY")

# Show the entire app but disable running parts if no API key
if not fireworks_api_key or fireworks_api_key.strip() == "":
    fireworks_api_key = st.text_input("Enter Fireworks API Key", type="password")

    # Optionally, allow the user to save the API key to the .env file
    if fireworks_api_key and st.checkbox("Save API key for future use"):
        with open(dotenv_path, "a") as f:
            f.write(f"FIREWORKS_API_KEY={fireworks_api_key}\n")
        st.success("API key saved to .env file.")
else:
    st.success(f"API key loaded successfully: partial preview {fireworks_api_key[:5]}")

# Step 1: Upload Image
st.subheader("🎁 Step 2: Upload Your Festive Picture 🎨")
st.markdown("""
It's time to pick your image! This will be the centerpiece of your holiday card.  
- **Pro Tip**: Choose something that brings out the warmth and joy of the season! πŸŽ„πŸŽ…  
Upload a **PNG** or **JPEG** image to get started.
""")
uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
if uploaded_file is not None:
    st.session_state.uploaded_file = uploaded_file

# Process uploaded image
if st.session_state.uploaded_file is not None:
    try:
        original_image = Image.open(st.session_state.uploaded_file)
        st.image(original_image, caption="Uploaded Image", use_column_width=True)

        # Step 2: Crop Image
        st.subheader("βœ‚οΈ Step 3: Trim Your Image Just Right! πŸŽ„")
        st.markdown("""
        Adjust the crop sliders to capture the most festive part of your image.  
        A preview will show you how your holiday card is shaping up! ✨
        """)
        img_width, img_height = original_image.size
        col1, col2 = st.columns(2)
        with col1:
            x_pos = st.slider("X position (Left-Right)", 0, img_width, img_width // 4)
            crop_width = st.slider("Width", 10, img_width - x_pos, min(img_width // 2, img_width - x_pos))
        with col2:
            y_pos = st.slider("Y position (Up-Down)", 0, img_height, img_height // 4)
            crop_height = st.slider("Height", 10, img_height - y_pos, min(img_height // 2, img_height - y_pos))

        preview_image = draw_crop_preview(original_image.copy(), x_pos, y_pos, crop_width, crop_height)
        st.image(preview_image, caption="Crop Preview", use_column_width=True)

        # Step 3: Set Border Parameters and Generate Image
        st.subheader("🎨 Step 4: Design Your Holiday Border! πŸŽ…")
        st.markdown("""
        Choose from a range of holiday themes like snowflakes, cozy fireplaces, or fireworks!  
        Want to create your own magical scene? Enter a **custom prompt** to make it truly unique! πŸŽ„
        """)
        selected_prompt = st.selectbox("Choose a holiday-themed prompt or enter your own", options=["Custom"] + holiday_border_prompts)
        custom_prompt = st.text_input("Enter your custom prompt") if selected_prompt == "Custom" else ""
        prompt = custom_prompt if selected_prompt == "Custom" else selected_prompt

        guidance_scale = st.slider("Guidance Scale", min_value=0.0, max_value=20.0, value=default_guidance_scale, step=0.1)
        num_inference_steps = st.slider("Number of Inference Steps", min_value=1, max_value=100, value=default_num_inference_steps, step=1)
        seed = st.slider("Random Seed", min_value=0, max_value=1000, value=default_seed)

        if st.button("Generate Holiday Card"):
            if not prompt.strip():
                st.error("Please enter a prompt.")
            else:
                with st.spinner("Adding holiday magic..."):
                    aspect_ratio = get_next_largest_aspect_ratio(img_width, img_height)
                    generated_image = generate_flux_image(
                        model_path="flux-1-schnell-fp8",
                        api_key=fireworks_api_key,
                        prompt=prompt,
                        steps=num_inference_steps,
                        guidance_scale=guidance_scale,
                        seed=seed,
                        aspect_ratio=f"{aspect_ratio[0]}:{aspect_ratio[1]}"
                    )
                    
                    if generated_image is not None:
                        generated_image = generated_image.resize(original_image.size)
                        cropped_original = original_image.crop((x_pos, y_pos, x_pos + crop_width, y_pos + crop_height))
                        center_x = (generated_image.width - crop_width) // 2
                        center_y = (generated_image.height - crop_height) // 2
                        final_image = generated_image.copy()
                        final_image.paste(cropped_original, (center_x, center_y))
                        st.session_state.generated_image = final_image

                        # Save metadata
                        st.session_state.metadata = {
                            "Prompt": prompt,
                            "Guidance Scale": guidance_scale,
                            "Inference Steps": num_inference_steps,
                            "Seed": seed
                        }

                        st.image(final_image, caption="🎁 Final Holiday Card 🎁", use_column_width=True)

                        # Print the metadata below the image
                        st.markdown("### ✨ Card Metadata")
                        for key, value in st.session_state.metadata.items():
                            st.write(f"**{key}:** {value}")

        # Step 4: Add Custom Message
        if 'generated_image' in st.session_state and st.session_state.generated_image is not None:
            st.subheader("πŸ’Œ Step 5: Add Your Heartfelt Holiday Message! πŸŽ…")
            st.markdown("""
            Select a pre-written festive message or craft your own!  
            Customize the font, size, and color to make it pop! 🌟
            """)

            selected_message = st.selectbox("Choose an example holiday message or write your own", options=["Custom"] + example_holiday_messages)
            custom_message = st.text_input("Enter your holiday message") if selected_message == "Custom" else selected_message
            
            selected_font = st.selectbox("Choose a font for your message", options=list(fonts.keys()))
            font_size = st.slider("Adjust font size", min_value=1, max_value=500, value=100, step=5)
            # Slider to choose the max characters per line for text wrapping
            max_chars = st.slider("Max characters per line:", min_value=20, max_value=100, value=40)
            font_path = fonts[selected_font]
            bg_color = st.color_picker("Pick a background color for the text", "#FFFFFF")
            font_color = st.color_picker("Pick a font color", "#000000")
            alpha = st.slider("Background transparency (0: fully transparent, 255: fully opaque)", 0, 255, 200)
            position_vertical = st.radio("Vertical position", ["Top", "Center", "Bottom"])
            position_horizontal = st.radio("Horizontal position", ["Left", "Center", "Right"])

            

            if st.button("Generate Holiday Card with Message"):
                final_image_with_message = st.session_state.generated_image.copy()

                final_image_with_message = add_custom_message(
                    final_image_with_message,
                    custom_message,
                    font_path,
                    font_size,
                    position_vertical,
                    position_horizontal,
                    max_chars=max_chars,
                    bg_color=bg_color,
                    font_color=font_color,
                    alpha=alpha
                )

                st.image(final_image_with_message, caption="πŸŽ„ Holiday Card with Custom Message πŸŽ„", use_column_width=True)

                # Save image and metadata to zip
                img_byte_arr = BytesIO()
                final_image_with_message.save(img_byte_arr, format="PNG")
                img_byte_arr.seek(0)

                # Create a zip file containing the image and metadata
                zip_buffer = BytesIO()
                with zipfile.ZipFile(zip_buffer, "w") as zf:
                    # Add the image to the zip
                    zf.writestr("holiday_card_with_message.png", img_byte_arr.getvalue())

                    # Add the metadata as a text file to the zip
                    metadata_str = "\n".join([f"{key}: {value}" for key, value in st.session_state.metadata.items()])
                    zf.writestr("metadata.txt", metadata_str)

                zip_buffer.seek(0)

                # Step 5: Download as zip
                st.download_button(
                    label="🎁 Download Holiday Card and Metadata as ZIP 🎁",
                    data=zip_buffer,
                    file_name="holiday_card_with_message.zip",
                    mime="application/zip"
                )

    except OSError:
        st.error("The uploaded image seems to be truncated or corrupted. Please try with a different image.")
else:
    st.warning("Please upload an image to get started.")


    # Footer Section
st.divider()
st.markdown(
    """
    Thank you for using the Holiday Card Generator powered by **Fireworks**! πŸŽ‰  
    Share your creations with the world and spread the holiday cheer!  
    Happy Holidays from the **Fireworks Team**. πŸ’₯  
    """
)