Mikiko Bazeley commited on
Commit
158efc9
·
1 Parent(s): 5938dae

Added different variants of card generation

Browse files
pages/1_Generate_Holiday_Postcard.py ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ from dotenv import load_dotenv
4
+ from PIL import Image, ImageDraw, ImageFont
5
+ from io import BytesIO
6
+ import streamlit as st
7
+ import textwrap
8
+
9
+ # Set page configuration
10
+ st.set_page_config(page_title="FLUX Image Generation Tool", page_icon="🎇")
11
+
12
+ # Correct the path to the .env file to reflect its location
13
+ dotenv_path = os.path.join(os.path.dirname(__file__), '../env/.env')
14
+
15
+ # Load environment variables from the .env file
16
+ load_dotenv(dotenv_path, override=True)
17
+
18
+ # Get the Fireworks API key from the .env file
19
+ fireworks_api_key = os.getenv("FIREWORKS_API_KEY")
20
+
21
+ if not fireworks_api_key:
22
+ st.error("API key not found. Make sure FIREWORKS_API_KEY is set in the .env file.")
23
+
24
+ # Define the fonts you want to allow
25
+ fonts = {
26
+ "DejaVu Sans Bold": "./fonts/dejavu-sans-bold.ttf",
27
+ "Covered By You": "./fonts/CoveredByYourGrace-Regular.ttf",
28
+ "Julee Regular": "./fonts/Julee-Regular.ttf",
29
+ "Kalam Regular": "./fonts/Kalam-Regular.ttf",
30
+ "Knewave Regular": "./fonts/Knewave-Regular.ttf",
31
+ "Sancreek Regular": "./fonts/Sancreek-Regular.ttf",
32
+ "Vast Shadow Regular": "./fonts/VastShadow-Regular.ttf",
33
+ }
34
+
35
+ # Holiday-themed prompts list
36
+ holiday_prompts = [
37
+ "A peaceful winter landscape covered in fresh snow, with delicate snowflakes drifting through the air and soft, frosty patterns along the edges, creating a serene holiday card",
38
+ "A cozy Christmas scene featuring a warmly lit cabin in the woods, surrounded by snow-covered trees and twinkling holiday lights, with a sky glowing softly in the background",
39
+ "A fireplace with stockings, garlands, and a glowing hearth, set in a cozy room decorated for the holidays, capturing the warmth and tranquility of the season",
40
+ "A colorful Hanukkah celebration with glowing menorahs, dreidels, and shimmering holiday lights illuminating the night, set against a rich, deep blue backdrop for a festive scene",
41
+ "A vibrant New Year's Eve cityscape with bright fireworks exploding in the sky, colorful confetti drifting through the air, and stars twinkling above the skyline, radiating excitement",
42
+ "A mystical Samhain forest scene, with pumpkins glowing softly among tall trees, and a full moon casting light over an ancient Celtic stone circle, evoking an air of magic and mystery",
43
+ "A lively Día de Muertos altar adorned with colorful calaveras, bright marigold flowers, and glowing candles, set against a traditional Mexican backdrop, celebrating the holiday’s joy",
44
+ "A wintery Yule forest scene under a starry sky, with snow-covered pine trees, holly bushes, and traditional Norse winter symbols decorating the landscape, capturing the warmth of the season",
45
+ "A bright and vibrant Diwali celebration with glowing diyas lining a courtyard, intricate rangoli patterns on the ground, and colorful fireworks lighting up the night sky",
46
+ "A serene Kwanzaa scene featuring a kinara with glowing candles, surrounded by decorations in red, black, and green, set in a peaceful and reflective atmosphere",
47
+ "A bountiful Thanksgiving table scene set outdoors, surrounded by autumn leaves, pumpkins, and a golden sunset, capturing the essence of gratitude and togetherness",
48
+ "A tranquil Winter Solstice night with a glowing full moon above, bare trees, stars twinkling in the sky, and a peaceful blanket of snow covering the quiet landscape",
49
+ "A festive St. Patrick's Day scene featuring a green countryside, with shamrocks covering the rolling hills, a rainbow stretching across the sky, and a pot of gold in the distance",
50
+ "A colorful Lunar New Year street scene with red lanterns hanging from the rooftops, dragon dancers parading down the street, and vibrant fireworks lighting up the night",
51
+ "A peaceful Easter garden filled with blooming spring flowers, pastel-colored eggs hidden among the grass, and soft sunlight streaming through the trees",
52
+ "A romantic Valentine's Day scene with glowing candles, heart-shaped decorations hanging from tree branches, and a soft pink and red sunset in the sky",
53
+ "A lively Holi celebration in an open field, with bursts of vibrant color powder filling the air, and people joyfully celebrating under a bright blue sky",
54
+ "A tranquil Ramadan evening scene with a crescent moon and stars hanging in the night sky, glowing lanterns decorating the streets, and peaceful reflections along a quiet river",
55
+ "A lively Independence Day celebration with colorful fireworks lighting up the night sky, flags waving in the breeze, and a peaceful lakeside reflecting the celebration"
56
+ ]
57
+
58
+
59
+
60
+ # Function to make requests to the FLUX models
61
+ def generate_flux_image(model_path, prompt, steps):
62
+ url = f"https://api.fireworks.ai/inference/v1/workflows/accounts/fireworks/models/{model_path}/text_to_image"
63
+ headers = {
64
+ "Authorization": f"Bearer {fireworks_api_key}",
65
+ "Content-Type": "application/json",
66
+ "Accept": "image/jpeg"
67
+ }
68
+ data = {
69
+ "prompt": prompt,
70
+ "aspect_ratio": "16:9",
71
+ "guidance_scale": 3.5,
72
+ "num_inference_steps": steps,
73
+ "seed": 0
74
+ }
75
+
76
+ # Send the request
77
+ response = requests.post(url, headers=headers, json=data)
78
+
79
+ if response.status_code == 200:
80
+ # Convert the response to an image
81
+ img_data = response.content
82
+ img = Image.open(BytesIO(img_data))
83
+ return img
84
+ else:
85
+ raise RuntimeError(f"Error with FLUX model {model_path}: {response.text}")
86
+
87
+ # Function to wrap text to a specified number of characters
88
+ def wrap_text(text, max_chars):
89
+ """Wrap text to a specified number of characters per line."""
90
+ return "\n".join(textwrap.fill(line, width=max_chars) for line in text.split("\n"))
91
+
92
+ # Function to add the holiday message to the image
93
+ def add_custom_message(image, message, font_path, font_size, position_vertical, position_horizontal, max_chars, bg_color, font_color):
94
+ try:
95
+ font = ImageFont.truetype(font_path, font_size)
96
+ except IOError:
97
+ font = ImageFont.load_default()
98
+
99
+ draw = ImageDraw.Draw(image)
100
+
101
+ # Wrap the text based on the max_chars input
102
+ message = wrap_text(message, max_chars)
103
+
104
+ img_width, img_height = image.size
105
+
106
+ # Calculate the text bounding box dynamically
107
+ text_lines = message.split("\n")
108
+ line_height = draw.textbbox((0, 0), "A", font=font)[3] # Get height of one line of text (bbox returns top, left, bottom, right)
109
+ total_text_height = line_height * len(text_lines)
110
+ text_width = max([draw.textbbox((0, 0), line, font=font)[2] for line in text_lines])
111
+
112
+ # Horizontal positioning
113
+ if position_horizontal == "Left":
114
+ x_pos = 10 # Padding from the left
115
+ elif position_horizontal == "Center":
116
+ x_pos = (img_width - text_width) // 2
117
+ else: # "Right"
118
+ x_pos = img_width - text_width - 10 # Padding from the right
119
+
120
+ # Vertical positioning
121
+ if position_vertical == "Top":
122
+ y_pos = 10 # Padding from the top
123
+ elif position_vertical == "Center":
124
+ y_pos = (img_height - total_text_height) // 2
125
+ else: # "Bottom"
126
+ y_pos = img_height - total_text_height - 10 # Padding from the bottom
127
+
128
+ # Define the padding for the background box behind the text
129
+ padding = 10
130
+
131
+ # Draw the background rectangle (the text box) with user-specified background color
132
+ draw.rectangle([x_pos - padding, y_pos - padding, x_pos + text_width + padding, y_pos + total_text_height + padding], fill=bg_color)
133
+
134
+ # Draw the text line by line with the user-specified font color
135
+ for i, line in enumerate(text_lines):
136
+ draw.text((x_pos, y_pos + i * line_height), line, font=font, fill=font_color)
137
+
138
+ return image
139
+
140
+ # Streamlit UI
141
+ st.title("FLUX Image Generation")
142
+ st.write("Generate images using the FLUX models and customize them with a holiday message.")
143
+
144
+ # Dropdown to select a holiday-themed prompt or enter a custom prompt
145
+ selected_prompt = st.selectbox("Choose a holiday-themed prompt or enter your own", options=["Custom"] + holiday_prompts)
146
+ custom_prompt = st.text_input("Enter your custom prompt") if selected_prompt == "Custom" else ""
147
+ prompt = custom_prompt if selected_prompt == "Custom" else selected_prompt
148
+
149
+ # Dropdown to select the model
150
+ model_choice = st.selectbox("Select the model:", ["flux-1-dev", "flux-1-schnell"])
151
+
152
+ # Additional inputs for customizing the message
153
+ message = st.text_input("Enter a holiday message to add:")
154
+ font_choice = st.selectbox("Select a font:", list(fonts.keys()))
155
+ font_size = st.slider("Select font size:", 10, 100, 40)
156
+ max_chars = st.slider("Max characters per line:", 10, 100, 40) # Slider to select character wrap limit
157
+
158
+ # Background color and font color pickers
159
+ bg_color = st.color_picker("Pick a background color for the text box:", "#FFFFFF")
160
+ font_color = st.color_picker("Pick a font color:", "#000000")
161
+
162
+ # Position options for the message (vertical and horizontal)
163
+ position_vertical = st.radio("Select message vertical position:", ["Top", "Center", "Bottom"])
164
+ position_horizontal = st.radio("Select message horizontal position:", ["Left", "Center", "Right"])
165
+
166
+ # Button to generate images
167
+ if st.button("Generate Image"):
168
+ if not prompt.strip():
169
+ st.error("Please provide a prompt.")
170
+ else:
171
+ try:
172
+ with st.spinner("Generating image..."):
173
+ # Determine steps based on model
174
+ steps = 30 if model_choice == "flux-1-dev" else 4
175
+
176
+ # Generate image
177
+ generated_image = generate_flux_image(model_choice, prompt, steps)
178
+
179
+ # Get the selected font path
180
+ font_path = fonts[font_choice]
181
+
182
+ # Add the holiday message to the generated image
183
+ image_with_message = add_custom_message(
184
+ generated_image.copy(), message, font_path, font_size,
185
+ position_vertical, position_horizontal, max_chars, bg_color, font_color
186
+ )
187
+
188
+ # Display the image with the message
189
+ st.image(image_with_message, caption=f"Generated using {model_choice} with custom message", use_column_width=True)
190
+
191
+ # Preview the placement
192
+ st.write(f"Message preview (vertical position: {position_vertical}, horizontal position: {position_horizontal}, font: {font_choice}, size: {font_size}, max chars: {max_chars}, bg color: {bg_color}, font color: {font_color})")
193
+
194
+ except Exception as e:
195
+ st.error(f"An error occurred: {e}")
pages/{1_Part_A_-_Experimentation_Station.py → 2_Generate_Holiday_Borders.py} RENAMED
@@ -368,15 +368,4 @@ if any(st.session_state.generated_cards):
368
 
369
  # Add metadata to the ZIP file
370
  metadata_str = "\n\n".join([f"{m['Card']}:\nPrompt: {m['Prompt']}\nGuidance Scale: {m['Guidance Scale']}\nInference Steps: {m['Inference Steps']}\nSeed: {m['Seed']}\nControlNet Conditioning Scale: {m['ControlNet Conditioning Scale']}\nControl Mode: {m['Control Mode']}" for m in metadata])
371
- zf.writestr("metadata.txt", metadata_str)
372
-
373
- # """ zip_buffer.seek(0)
374
- # st.divider()
375
- # st.subheader("Save images & metadata")
376
- # st.download_button(
377
- # label="Download all previously generated images and metadata as ZIP",
378
- # data=zip_buffer,
379
- # file_name="holiday_cards.zip",
380
- # mime="application/zip"
381
- # )
382
- # """
 
368
 
369
  # Add metadata to the ZIP file
370
  metadata_str = "\n\n".join([f"{m['Card']}:\nPrompt: {m['Prompt']}\nGuidance Scale: {m['Guidance Scale']}\nInference Steps: {m['Inference Steps']}\nSeed: {m['Seed']}\nControlNet Conditioning Scale: {m['ControlNet Conditioning Scale']}\nControl Mode: {m['Control Mode']}" for m in metadata])
371
+ zf.writestr("metadata.txt", metadata_str)
 
 
 
 
 
 
 
 
 
 
 
pages/{2_Part_B_-_Card_Generator.py → 3_Customize_Holiday_Borders.py} RENAMED
@@ -220,7 +220,7 @@ if st.session_state.uploaded_file is not None:
220
  "A border of Soyal dancers, sun symbols, and traditional Zuni and Hopi winter motifs to welcome the sun's return",
221
  "A border of Winter Solstice symbols with bare trees, stars, and the moon against a cold winter night",
222
  "A border of spooky Halloween elements like pumpkins, bats, ghosts, and cobwebs for a haunted theme",
223
- "A border of Thanksgiving harvest items like pumpkins, cornucopias, autumn leaves, and turkeys",
224
  "A border of Christmas ornaments, wreaths, and lights for a joyful, festive holiday look"
225
  ]
226
  st.subheader("⚙️ Step 3: Design Your Festive Border with Flux + Fireworks!")
 
220
  "A border of Soyal dancers, sun symbols, and traditional Zuni and Hopi winter motifs to welcome the sun's return",
221
  "A border of Winter Solstice symbols with bare trees, stars, and the moon against a cold winter night",
222
  "A border of spooky Halloween elements like pumpkins, bats, ghosts, and cobwebs for a haunted theme",
223
+ "A border of fall harvest items like pumpkins, cornucopias, autumn leaves, and turkeys",
224
  "A border of Christmas ornaments, wreaths, and lights for a joyful, festive holiday look"
225
  ]
226
  st.subheader("⚙️ Step 3: Design Your Festive Border with Flux + Fireworks!")
pages/4_Morph_Holiday_Card.py ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import cv2
3
+ import requests
4
+ from io import BytesIO
5
+ from PIL import Image, ImageDraw, ImageFont, ImageFilter
6
+ import numpy as np
7
+ import os
8
+ from dotenv import load_dotenv
9
+
10
+ # Load environment variables
11
+ dotenv_path = os.path.join(os.path.dirname(__file__), '../env/.env')
12
+ load_dotenv(dotenv_path, override=True)
13
+ api_key = os.getenv("FIREWORKS_API_KEY")
14
+
15
+ if not api_key:
16
+ st.error("API key not found. Make sure FIREWORKS_API_KEY is set in the .env file.")
17
+ st.stop()
18
+
19
+ # Initialize session state variables if they don't exist
20
+ if 'uploaded_file' not in st.session_state:
21
+ st.session_state.uploaded_file = None
22
+ if 'generated_image' not in st.session_state:
23
+ st.session_state.generated_image = None
24
+ if 'control_image' not in st.session_state:
25
+ st.session_state.control_image = None
26
+
27
+ VALID_ASPECT_RATIOS = {
28
+ (1, 1): "1:1", (21, 9): "21:9", (16, 9): "16:9", (3, 2): "3:2", (5, 4): "5:4",
29
+ (4, 5): "4:5", (2, 3): "2:3", (9, 16): "9:16", (9, 21): "9:21",
30
+ }
31
+
32
+ def get_closest_aspect_ratio(width, height):
33
+ aspect_ratio = width / height
34
+ closest_ratio = min(VALID_ASPECT_RATIOS.keys(), key=lambda x: abs((x[0] / x[1]) - aspect_ratio))
35
+ return closest_ratio, VALID_ASPECT_RATIOS[closest_ratio]
36
+
37
+ def add_padding_to_aspect_ratio(image, target_aspect_ratio):
38
+ width, height = image.size
39
+ target_width, target_height = target_aspect_ratio
40
+
41
+ if width / height > target_width / target_height:
42
+ new_height = int(width * target_height / target_width)
43
+ new_width = width
44
+ else:
45
+ new_width = int(height * target_width / target_height)
46
+ new_height = height
47
+
48
+ # Create a new image with the target aspect ratio and paste the original image in the center
49
+ padded_image = Image.new('RGB', (new_width, new_height), (128, 128, 128)) # Grey padding
50
+ paste_x = (new_width - width) // 2
51
+ paste_y = (new_height - height) // 2
52
+ padded_image.paste(image, (paste_x, paste_y))
53
+
54
+ return padded_image
55
+
56
+ def create_control_image(original_image, x_pos, y_pos, crop_width, crop_height):
57
+ # Crop the selected area
58
+ cropped_area = original_image.crop((x_pos, y_pos, x_pos + crop_width, y_pos + crop_height))
59
+
60
+ # Add 20% padding around the cropped area
61
+ pad_width = int(crop_width * 0.2)
62
+ pad_height = int(crop_height * 0.2)
63
+ padded_width = crop_width + 2 * pad_width
64
+ padded_height = crop_height + 2 * pad_height
65
+ padded_image = Image.new('RGB', (padded_width, padded_height), (128, 128, 128)) # Grey padding
66
+ padded_image.paste(cropped_area, (pad_width, pad_height))
67
+
68
+ # Adjust the padded image to match the closest valid aspect ratio
69
+ closest_aspect_ratio, _ = get_closest_aspect_ratio(padded_width, padded_height)
70
+ control_image = add_padding_to_aspect_ratio(padded_image, closest_aspect_ratio)
71
+
72
+ return control_image
73
+
74
+ def process_image(image):
75
+ gray_image = image.convert('L')
76
+ np_image = np.array(gray_image)
77
+ edges = cv2.Canny(np_image, 100, 200)
78
+ edges_rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
79
+ edge_image = Image.fromarray(edges_rgb)
80
+ byte_arr = BytesIO()
81
+ edge_image.save(byte_arr, format='JPEG')
82
+ byte_arr.seek(0)
83
+ return byte_arr, edge_image
84
+
85
+ def call_control_net_api(control_image, prompt, control_mode=0, guidance_scale=3.5, num_inference_steps=30, seed=0, controlnet_conditioning_scale=1.0):
86
+ processed_image_bytes, processed_image = process_image(control_image)
87
+ files = {'control_image': ('control_image.jpg', processed_image_bytes, 'image/jpeg')}
88
+
89
+ width, height = control_image.size
90
+ aspect_ratio = get_closest_aspect_ratio(width, height)[1]
91
+
92
+ data = {
93
+ 'prompt': prompt,
94
+ 'control_mode': control_mode,
95
+ 'aspect_ratio': aspect_ratio,
96
+ 'guidance_scale': guidance_scale,
97
+ 'num_inference_steps': num_inference_steps,
98
+ 'seed': seed,
99
+ 'controlnet_conditioning_scale': controlnet_conditioning_scale
100
+ }
101
+
102
+ headers = {
103
+ 'accept': 'image/jpeg',
104
+ 'authorization': f'Bearer {api_key}',
105
+ }
106
+
107
+ response = requests.post(
108
+ 'https://api.fireworks.ai/inference/v1/workflows/accounts/fireworks/models/flux-1-dev-controlnet-union/control_net',
109
+ files=files, data=data, headers=headers
110
+ )
111
+
112
+ if response.status_code == 200:
113
+ return Image.open(BytesIO(response.content)), processed_image
114
+ else:
115
+ st.error(f"Request failed with status code: {response.status_code}, Response: {response.text}")
116
+ return None, None
117
+
118
+ def draw_crop_preview(image, x, y, width, height):
119
+ draw = ImageDraw.Draw(image)
120
+ for i in range(5): # Draw multiple rectangles for thickness
121
+ draw.rectangle([x+i, y+i, x+width-i, y+height-i], outline="red")
122
+ return image
123
+
124
+ def smooth_edges(image, crop_box, blur_radius=5):
125
+ # Create a mask for the cropped area
126
+ mask = Image.new("L", image.size, 0)
127
+ draw = ImageDraw.Draw(mask)
128
+ draw.rectangle(crop_box, fill=255)
129
+ mask = mask.filter(ImageFilter.GaussianBlur(blur_radius))
130
+
131
+ # Create a new image for blending
132
+ blended_image = Image.composite(image, Image.new("RGB", image.size, (0, 0, 0)), mask)
133
+ return blended_image
134
+
135
+ def add_custom_message(image, message, font_path, font_size):
136
+ # Load a font
137
+ try:
138
+ font = ImageFont.truetype(font_path, font_size)
139
+ except IOError:
140
+ font = ImageFont.load_default()
141
+
142
+ draw = ImageDraw.Draw(image)
143
+
144
+ # Calculate the text bounding box dynamically
145
+ text_bbox = draw.textbbox((0, 0), message, font=font)
146
+ text_width = text_bbox[2] - text_bbox[0]
147
+ text_height = text_bbox[3] - text_bbox[1]
148
+ img_width, img_height = image.size
149
+
150
+ # Center the text
151
+ x_pos = (img_width - text_width) // 2
152
+ y_pos = img_height - text_height - 10 # 10 px padding from the bottom
153
+
154
+ # Define the padding for the white box
155
+ padding = 10
156
+
157
+ # Draw a white rectangle (the background box) behind the text
158
+ draw.rectangle([x_pos - padding, y_pos - padding, x_pos + text_width + padding, y_pos + text_height + padding], fill="white")
159
+
160
+ # Draw the black text on top of the white box
161
+ draw.text((x_pos, y_pos), message, font=font, fill="black")
162
+
163
+ return image
164
+
165
+
166
+ # Define available fonts
167
+ fonts = {
168
+ "DejaVu Sans Bold": "./fonts/dejavu-sans-bold.ttf",
169
+ "Covered By You": "./fonts/CoveredByYourGrace-Regular.ttf", # Update this path to your actual font paths
170
+ "Julee Regular": "./fonts/Julee-Regular.ttf", # Example font
171
+ "Kalam Regular": "./fonts/Kalam-Regular.ttf",
172
+ "Knewave Regular": "./fonts/Knewave-Regular.ttf",
173
+ "Sancreek Regular": "./fonts/Sancreek-Regular.ttf",
174
+ "Vast Shadow Regular": "./fonts/VastShadow-Regular.ttf",
175
+ }
176
+
177
+ # Streamlit UI
178
+ st.title("Holiday Card Generator with ControlNet")
179
+
180
+ uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
181
+
182
+ if uploaded_file is not None:
183
+ st.session_state.uploaded_file = uploaded_file # Save the file to session state
184
+ original_image = Image.open(st.session_state.uploaded_file)
185
+ st.image(original_image, caption="Uploaded Image", use_column_width=True)
186
+
187
+ img_width, img_height = original_image.size
188
+
189
+ st.subheader("Crop Selection")
190
+ col1, col2 = st.columns(2)
191
+ with col1:
192
+ x_pos = st.slider("X position", 0, img_width, img_width // 4)
193
+ crop_width = st.slider("Width", 10, img_width - x_pos, min(img_width // 2, img_width - x_pos))
194
+ with col2:
195
+ y_pos = st.slider("Y position", 0, img_height, img_height // 4)
196
+ crop_height = st.slider("Height", 10, img_height - y_pos, min(img_height // 2, img_height - y_pos))
197
+
198
+ preview_image = draw_crop_preview(original_image.copy(), x_pos, y_pos, crop_width, crop_height)
199
+ st.image(preview_image, caption="Crop Preview", use_column_width=True)
200
+
201
+ holiday_prompts = [
202
+ "A portrait of a person framed by festive snowflakes and winter patterns, with soft, frosty details along the edges for a holiday card",
203
+ "A joyful portrait with Christmas ornaments and twinkling lights decorating the borders, framing the person in a warm, festive glow",
204
+ "A cozy portrait with a fireplace scene, stockings, and garlands along the edges, enhancing the warmth of the person in the center",
205
+ "A colorful Hanukkah-themed portrait with menorahs, dreidels, and holiday lights framing the person against a rich backdrop",
206
+ "A New Year's Eve portrait with celebratory fireworks, stars, and confetti surrounding the person, giving an energetic, celebratory vibe",
207
+ "A mystical portrait framed by Samhain symbols like Celtic knots, pumpkins, and candles, creating an enchanting October atmosphere",
208
+ "A vibrant Día de Muertos portrait with colorful skulls (calaveras), marigold flowers, and candles framing the subject with traditional flair",
209
+ "A Yule-themed portrait framed by holly, pine trees, and Norse winter symbols under a starry sky, bringing out the warmth of the subject",
210
+ "A bright and joyful Diwali portrait with lamps (diyas), intricate rangoli patterns, and lotus flowers framing the person for a festive look",
211
+ "A cozy winter portrait with Dongzhi Festival glutinous rice balls and family gathering symbols along the edges, giving a homely, warm feeling",
212
+ "A spiritual portrait framed by Zuni and Hopi winter motifs, including Soyal dancers and sun symbols, welcoming the return of the sun",
213
+ "A winter solstice portrait with bare trees, stars, and the moon softly framing the person in a serene, cold night atmosphere",
214
+ "A spooky Halloween-themed portrait framed by pumpkins, bats, ghosts, and cobwebs, adding a playful, haunting edge to the subject",
215
+ "A harvest-themed portrait surrounded by pumpkins, cornucopias, autumn leaves, and turkeys, capturing the essence of Thanksgiving",
216
+ "A joyful Christmas portrait framed by ornaments, wreaths, and glowing lights, creating a festive and heartwarming holiday look"
217
+ ]
218
+
219
+ selected_prompt = st.selectbox("Choose a holiday-themed prompt or enter your own", options=["Custom"] + holiday_prompts)
220
+ custom_prompt = st.text_input("Enter your custom prompt") if selected_prompt == "Custom" else ""
221
+ prompt = custom_prompt if selected_prompt == "Custom" else selected_prompt
222
+
223
+ with st.expander("Advanced Parameters"):
224
+ control_mode = st.slider("Control Mode", min_value=0, max_value=2, value=0)
225
+ controlnet_conditioning_scale = st.slider("ControlNet Conditioning Scale", min_value=0.0, max_value=1.0, value=0.5, step=0.1)
226
+ guidance_scale = st.slider("Guidance Scale", min_value=0.0, max_value=20.0, value=3.5, step=0.1)
227
+ num_inference_steps = st.slider("Number of Inference Steps", min_value=1, max_value=100, value=30, step=1)
228
+ seed = st.slider("Random Seed", min_value=0, max_value=1000, value=0)
229
+
230
+ custom_message = st.text_input("Enter a custom holiday message to add to the card")
231
+
232
+ # Font selection dropdown and font size slider
233
+ selected_font = st.selectbox("Choose a font for your message", options=list(fonts.keys()))
234
+ font_size = st.slider("Font size", 10, 100, 40)
235
+
236
+ if st.button("Generate Flux Image"):
237
+ if not prompt.strip():
238
+ st.error("Please enter a prompt.")
239
+ else:
240
+ with st.spinner("Generating Flux image..."):
241
+ control_image = create_control_image(original_image, x_pos, y_pos, crop_width, crop_height)
242
+ st.image(control_image, caption="Control Image (Cropped and Padded)", use_column_width=True)
243
+
244
+ generated_image, processed_image = call_control_net_api(
245
+ control_image, prompt, control_mode=control_mode,
246
+ guidance_scale=guidance_scale, num_inference_steps=num_inference_steps,
247
+ seed=seed, controlnet_conditioning_scale=controlnet_conditioning_scale
248
+ )
249
+
250
+ if generated_image is not None:
251
+ st.session_state.generated_image = generated_image
252
+ st.session_state.control_image = control_image
253
+
254
+ # Add custom message if provided
255
+ if custom_message:
256
+ font_path = fonts[selected_font]
257
+ generated_image_with_message = add_custom_message(generated_image.copy(), custom_message, font_path, font_size)
258
+ st.image(generated_image_with_message, caption="Generated Flux Image with Message", use_column_width=True)
259
+ else:
260
+ st.image(generated_image, caption="Generated Flux Image", use_column_width=True)
261
+
262
+ st.success("Flux image generated successfully!")
263
+ else:
264
+ st.error("Failed to generate image. Please try again.")
265
+
266
+ else:
267
+ st.warning("Please upload an image to get started.")
268
+