Mikiko Bazeley commited on
Commit
7c1b343
·
1 Parent(s): be47fca

Wrapping up documentation, copy

Browse files
.gitignore CHANGED
@@ -261,7 +261,7 @@ venv.bak/
261
 
262
  # Assets and images generated
263
  run_*/
264
-
265
 
266
  # Spyder project settings
267
  .spyderproject
 
261
 
262
  # Assets and images generated
263
  run_*/
264
+ pages_draft/*
265
 
266
  # Spyder project settings
267
  .spyderproject
README.md CHANGED
@@ -11,128 +11,98 @@ license: mit
11
  short_description: Generate an ugly hold
12
  ---
13
 
14
- ## Project: Fireworks Model Comparison App
15
 
16
- ### Overview
17
- The **Fireworks Model Comparison App** is an interactive tool built using **Streamlit** that allows users to compare various Large Language Models (LLMs) hosted on **Fireworks AI**. Users can adjust key model parameters, provide custom prompts, and generate model outputs to compare their behavior and responses. Additionally, an LLM-as-a-Judge feature is available to evaluate the generated outputs and provide feedback on their quality.
18
 
 
19
 
20
- ### Objectives
21
- - **Compare Models**: Select different models from the Fireworks platform and compare their outputs based on a shared prompt.
22
- - **Modify Parameters**: Fine-tune parameters such as **Max Tokens**, **Temperature**, **Top-p**, and **Top-k** to observe how they influence model behavior.
23
- - **Evaluate Using LLM-as-a-Judge**: After generating responses, use a separate model to act as a judge and evaluate the outputs from the selected models.
24
-
25
 
26
- ![Home Page Screenshot](img/home_page_1.png)
27
- ![Home Page Screenshot](img/home_page_2.png)
28
 
 
 
 
 
 
29
 
30
- ### Features
31
- - **Streamlit UI**: A simple and intuitive interface where users can select models, input prompts, and adjust model parameters.
32
- - **LLM Comparison**: Select up to three different models, run a query with the same prompt, and view side-by-side responses.
33
- - **Parameter Exploration**: Explore and modify different parameters such as Max Tokens, Temperature, Top-p, and more to see how they affect the model's response.
34
- - **LLM-as-a-Judge**: Let another LLM compare the generated responses from the models and provide a comparison.
35
 
36
- ### App Structure
37
- The app consists of two main pages:
38
- 1. **Comparing LLMs**:
39
- - Compare the outputs of three selected LLMs from Fireworks AI by providing a prompt.
40
- - View the responses side-by-side for easy comparison.
41
- - A selected LLM acts as a judge to evaluate the generated responses.
42
 
 
 
 
43
 
44
- ![Home Page Screenshot](img/page_1_empty.png)
45
- ![Home Page Screenshot](img/page_1_a.png)
46
- ![Home Page Screenshot](img/page_1_b.png)
47
- ![Home Page Screenshot](img/page_1_c.png)
48
 
49
-
50
- 2. **Parameter Exploration**:
51
- - Modify various parameters for the LLMs (e.g., Max Tokens, Temperature, Top-p) and observe how they affect the outputs.
52
- - Compare three different outputs generated with varying parameter configurations.
53
- - Use LLM-as-a-Judge to provide a final evaluation of the outputs.
54
-
55
- ![Home Page Screenshot](img/page_2_empty.png)
56
- ![Home Page Screenshot](img/page_2_a.png)
57
- ![Home Page Screenshot](img/page_2_b.png)
58
- ![Home Page Screenshot](img/page_2_c.png)
59
-
60
- ### Setup and Installation
61
-
62
- #### Prerequisites
63
  - **Python 3.x** installed on your machine.
64
  - A **Fireworks AI** API key, which you can obtain by signing up at [Fireworks AI](https://fireworks.ai).
65
  - Install **Streamlit** and the **Fireworks Python Client**.
66
 
67
- #### Step-by-Step Setup
68
- ##### 1. Clone the Repository:
69
- First, clone the repository from GitHub:
70
 
 
71
  ```bash
72
  git clone https://github.com/fw-ai/examples.git
73
  ```
74
 
75
- ##### 2. Navigate to the Specific Project Sub-directory:
76
- After cloning the repository, navigate to the `project_llm-as-a-judge-streamlit-dashboard` sub-directory:
77
-
78
  ```bash
79
- cd learn/inference/project_llm-as-a-judge-streamlit-dashboard
80
  ```
81
 
82
- ##### 3. Set up a Virtual Environment (Optional but Recommended):
83
- Create and activate a Python virtual environment:
84
-
85
  ```bash
86
  python3 -m venv venv
87
  source venv/bin/activate # On macOS/Linux
88
  .\venv\Scripts\activate # On Windows
89
  ```
90
 
91
- ##### 4. Install Required Dependencies:
92
- Install the necessary Python dependencies using `pip3`:
93
-
94
  ```bash
95
- pip3 install -r requirements.txt
96
  ```
97
 
98
- ##### 5. Configure the `.env` File:
99
- Copy the `.env.template` file and rename it to `.env` in the same project directory:
100
-
101
  ```bash
102
- mkdir env/
103
  cp .env.template env/.env
104
  ```
105
-
106
- Open the `.env` file and add your **FIREWORKS_API_KEY**:
107
-
108
  ```bash
109
  FIREWORKS_API_KEY=<your_fireworks_api_key>
110
  ```
111
 
112
- ##### 6. Run the Streamlit App:
113
- Finally, run the Streamlit app:
114
-
115
  ```bash
116
- streamlit run home.py
117
  ```
118
 
 
 
 
119
 
120
- ##### 7. **Explore the app**:
121
- - Open the app in your browser via the URL provided by Streamlit (typically `http://localhost:8501`).
122
- - Navigate between the pages to compare models and adjust parameters.
 
 
123
 
124
- ### Example Prompts
125
- Here are some example prompts you can try in the app:
126
- - **Prompt 1**: "Describe the future of AI in 500 words."
127
- - **Prompt 2**: "Write a short story about a time traveler who visits ancient Rome."
128
- - **Prompt 3**: "Explain quantum computing in simple terms."
129
- - **Prompt 4**: "Generate a recipe for a healthy vegan dinner."
130
 
131
- ### Fireworks API Documentation
132
- To learn more about how to query models and interact with the Fireworks API, visit the [Fireworks API Documentation](https://docs.fireworks.ai/api-reference/post-chatcompletions).
133
 
134
- ### Contributing
135
- We welcome contributions to improve this app! To contribute, fork the repository, make your changes, and submit a pull request.
136
 
137
- ### License
138
- This project is licensed under the MIT License.
 
11
  short_description: Generate an ugly hold
12
  ---
13
 
14
+ 🎉 **Ugly Holiday Card Generator** 🎉
15
 
16
+ 👋 **Welcome to the Ugly Holiday Card Generator!** 🎄❄️
 
17
 
18
+ This fun and festive app allows you to create your own ugly holiday cards using AI-generated borders, custom messages, and creative controls to make your card as unique (and ugly!) as possible. Powered by Flux models on Fireworks AI, this app helps you get creative with your holiday greetings. 🎅🎁✨
19
 
20
+ ## 🎯 **Project: Ugly Holiday Card Generator**
 
 
 
 
21
 
22
+ ### 🛠️ **Overview**
23
+ The **Ugly Holiday Card Generator** is an interactive tool built with **Streamlit** that allows users to upload images, adjust parameters, and generate customized holiday cards with AI-generated borders. Whether you want to add snowflakes, Christmas lights, or even fireworks, this app lets you craft the perfect holiday card to share with your friends and family! 🌟
24
 
25
+ ### 🎨 **Features**
26
+ - **Custom Borders**: Choose from a variety of holiday-themed prompts like festive snowflakes, cozy fireplaces, and colorful fireworks! Or create your own custom border prompt! 🖼️🎆
27
+ - **Crop It**: Adjust your image’s crop to focus on the best part of your photo. ✂️
28
+ - **Personalized Message**: Add your own holiday message in different fonts and sizes to give it that final personal touch. ✏️💌
29
+ - **Save & Download**: Easily download your masterpiece with just a click and share it with the world! 🌍🎁
30
 
31
+ ### 📝 **App Structure**
32
+ The app is divided into two parts:
 
 
 
33
 
34
+ 1. **Prompt & Parameter Ideation**:
35
+ - Select or enter custom prompts for your holiday card's border.
36
+ - Adjust advanced parameters like **guidance scale** and **inference steps** to fine-tune your card.
37
+ - Crop your image and preview your card before moving to the final stage. 🎄📸
 
 
38
 
39
+ 2. **Personalization & Message Customization**:
40
+ - Add a custom holiday message with a variety of fonts and sizes.
41
+ - View the final card with your personalized message and download it in PNG format. 🖼️💌
42
 
43
+ ### 💻 **Setup and Installation**
 
 
 
44
 
45
+ #### 🚀 **Prerequisites**
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  - **Python 3.x** installed on your machine.
47
  - A **Fireworks AI** API key, which you can obtain by signing up at [Fireworks AI](https://fireworks.ai).
48
  - Install **Streamlit** and the **Fireworks Python Client**.
49
 
50
+ #### �� **Step-by-Step Setup**
 
 
51
 
52
+ 1. **Clone the Repository**:
53
  ```bash
54
  git clone https://github.com/fw-ai/examples.git
55
  ```
56
 
57
+ 2. **Navigate to the Specific Project Sub-directory**:
 
 
58
  ```bash
59
+ cd learn/inference/ugly-holiday-card-generator
60
  ```
61
 
62
+ 3. **Set up a Virtual Environment** (Optional but Recommended):
 
 
63
  ```bash
64
  python3 -m venv venv
65
  source venv/bin/activate # On macOS/Linux
66
  .\venv\Scripts\activate # On Windows
67
  ```
68
 
69
+ 4. **Install Required Dependencies**:
 
 
70
  ```bash
71
+ pip install -r requirements.txt
72
  ```
73
 
74
+ 5. **Configure the `.env` File**:
75
+ Copy the `.env.template` file and rename it to `.env` in the project directory:
 
76
  ```bash
 
77
  cp .env.template env/.env
78
  ```
79
+ Add your **FIREWORKS_API_KEY**:
 
 
80
  ```bash
81
  FIREWORKS_API_KEY=<your_fireworks_api_key>
82
  ```
83
 
84
+ 6. **Run the Streamlit App**:
 
 
85
  ```bash
86
+ streamlit run app.py
87
  ```
88
 
89
+ 7. **Explore the App**:
90
+ - Open the app in your browser via the URL provided by Streamlit (typically `http://localhost:8501`).
91
+ - Navigate between the prompt ideation and message customization stages. ✨🎨
92
 
93
+ ### 📝 **Example Prompts**
94
+ Here are some example holiday prompts to try in the app:
95
+ - "A border of festive snowflakes and winter patterns"
96
+ - "A border of cozy Christmas ornaments and lights"
97
+ - "A border of New Year's Eve fireworks with stars and confetti"
98
 
99
+ ### 🔗 **Fireworks API Documentation**
100
+ To learn more about querying models and interacting with the Fireworks API, check out the [Fireworks API Documentation](https://docs.fireworks.ai/api-reference).
 
 
 
 
101
 
102
+ ### 🤝 **Contributing**
103
+ Contributions are welcome! Feel free to fork the repository, make changes, and submit a pull request. 🎨🎄
104
 
105
+ ### 📝 **License**
106
+ This project is licensed under the MIT License.
107
 
108
+ 🎁 **Happy Holidays and Enjoy Creating Your Cards!** 🎁
 
app.py CHANGED
@@ -1,6 +1,71 @@
1
  import streamlit as st
2
  from PIL import Image
3
 
4
- # Streamlit UI
5
- st.title("To be filled in")
6
- st.write("Blank on purpose")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  from PIL import Image
3
 
4
+
5
+ # Load images
6
+ logo_image = Image.open("img/fireworksai_logo.png")
7
+ parameters_1_image = Image.open("img/parameters_1.png")
8
+ parameters_2_image = Image.open("img/parameters_2.png")
9
+ parameters_3_image = Image.open("img/parameters_3.png")
10
+ parameters_4_image = Image.open("img/parameters_4.png")
11
+ card_with_message_1_image = Image.open("img/card_with_message_1.png")
12
+ card_with_message_2_image = Image.open("img/card_with_message_2.png")
13
+
14
+
15
+
16
+ # Fireworks Logo at the top
17
+ st.image(logo_image)
18
+
19
+ # Title of the app
20
+ st.title("🎨 Flux Holiday Magic: Custom Card Creator")
21
+
22
+
23
+ # Description using Streamlit text and markdown
24
+ st.markdown("""
25
+ Welcome to the ultimate holiday card design experience! 🎄❄️
26
+
27
+ \n Powered by **Flux models** through **Fireworks API**, this app lets you effortlessly create stunning, personalized holiday cards with just a few clicks. Here’s what you can do:
28
+ """)
29
+
30
+ # Features list with emojis
31
+ st.markdown("""
32
+ - **Upload Your Image**: Choose any photo as the base for your holiday card.
33
+ - **Crop & Preview**: Fine-tune the area of your image to fit perfectly within the card.
34
+ - **Holiday Borders**: Choose from festive prompts like snowflakes, ornaments, and cozy fireplace scenes to frame your photo.
35
+ - **Add Custom Messages**: Personalize your card with a message, choosing from a variety of fonts and adjustable text sizes.
36
+ - **Advanced Customization**: Take control of parameters like ControlNet conditioning, guidance scale, inference steps, and more for tailored results.
37
+ - **Save & Share**: Download your final creations or save them for later in a handy ZIP file.
38
+
39
+ And be sure to share with us on social!
40
+
41
+ ![Holiday Vibes](https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExMXo5Y3RhOGNzaTkzZHFmandsZmF0MW9jNHN4M3VjMjdpOGhyYnRxMSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/637gfK5GJdv552H9ab/giphy.gif)
42
+ """)
43
+
44
+ # Call to action
45
+ st.markdown("""
46
+ Get started now and add a magical touch to your holiday greetings! 🎅🌟
47
+ """)
48
+
49
+ st.divider()
50
+ st.subheader("Experiment with Flux to figure out the perfect look for your holiday card")
51
+ st.markdown(""" ![For science!](https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExbGwwdGh4czc3bnU3czNzaWRhaXl4YXYzdm53Nmw1OXhpd2E4emFuYSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/RdJIM4Uesg37eN1ZNL/giphy.gif)""")
52
+ col1, col2 = st.columns(2)
53
+
54
+ with col1:
55
+ st.image(parameters_1_image)
56
+ st.image(parameters_3_image)
57
+
58
+ with col2:
59
+ st.image(parameters_2_image)
60
+ st.image(parameters_4_image)
61
+
62
+
63
+
64
+ st.divider()
65
+ st.subheader("Customize your holiday card with a special message")
66
+ st.markdown(""" ![Special message, so special](https://i.giphy.com/media/v1.Y2lkPTc5MGI3NjExenVkdmZzZTdxNjIxcDk2b2NrdXUxbDBneTNqdHUyamFxNTQzd2dleiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/qDJSK8oxEkBV0XJE7B/giphy.gif)""")
67
+ col3, col4 = st.columns(2)
68
+ with col3:
69
+ st.image(card_with_message_1_image)
70
+ with col4:
71
+ st.image(card_with_message_2_image)
fonts/CoveredByYourGrace-Regular.ttf ADDED
Binary file (50.1 kB). View file
 
fonts/Julee-Regular.ttf ADDED
Binary file (65.4 kB). View file
 
fonts/Kalam-Regular.ttf ADDED
Binary file (427 kB). View file
 
fonts/Knewave-Regular.ttf ADDED
Binary file (31.3 kB). View file
 
fonts/Sancreek-Regular.ttf ADDED
Binary file (47.6 kB). View file
 
fonts/VastShadow-Regular.ttf ADDED
Binary file (59.5 kB). View file
 
fonts/dejavu-sans-bold.ttf ADDED
Binary file (706 kB). View file
 
img/card_with_message_1.png ADDED
img/card_with_message_2.png ADDED
img/parameters_1.png ADDED
img/parameters_2.png ADDED
img/parameters_3.png ADDED
img/parameters_4.png ADDED
pages/1_Autocenter_HolidayCard.py DELETED
@@ -1,178 +0,0 @@
1
- import streamlit as st
2
- import cv2
3
- import requests
4
- from io import BytesIO
5
- from PIL import Image, ImageDraw
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
- VALID_ASPECT_RATIOS = {
20
- (1, 1): "1:1", (21, 9): "21:9", (16, 9): "16:9", (3, 2): "3:2", (5, 4): "5:4",
21
- (4, 5): "4:5", (2, 3): "2:3", (9, 16): "9:16", (9, 21): "9:21",
22
- }
23
-
24
- def get_closest_aspect_ratio(width, height):
25
- aspect_ratio = width / height
26
- closest_ratio = min(VALID_ASPECT_RATIOS.keys(), key=lambda x: abs((x[0] / x[1]) - aspect_ratio))
27
- return VALID_ASPECT_RATIOS[closest_ratio]
28
-
29
- def process_image(uploaded_image):
30
- image = np.array(Image.open(uploaded_image).convert('L'))
31
- edges = cv2.Canny(image, 100, 200)
32
- edges_rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
33
- pil_image = Image.fromarray(edges_rgb)
34
- byte_arr = BytesIO()
35
- pil_image.save(byte_arr, format='JPEG')
36
- byte_arr.seek(0)
37
- return byte_arr, pil_image
38
-
39
- def call_control_net_api(uploaded_image, prompt, control_mode=0, guidance_scale=3.5, num_inference_steps=30, seed=0, controlnet_conditioning_scale=1.0):
40
- control_image, processed_image = process_image(uploaded_image)
41
- files = {'control_image': ('control_image.jpg', control_image, 'image/jpeg')}
42
- original_image = Image.open(uploaded_image)
43
- width, height = original_image.size
44
- aspect_ratio = get_closest_aspect_ratio(width, height)
45
- data = {
46
- 'prompt': prompt,
47
- 'control_mode': control_mode,
48
- 'aspect_ratio': aspect_ratio,
49
- 'guidance_scale': guidance_scale,
50
- 'num_inference_steps': num_inference_steps,
51
- 'seed': seed,
52
- 'controlnet_conditioning_scale': controlnet_conditioning_scale
53
- }
54
- headers = {
55
- 'accept': 'image/jpeg',
56
- 'authorization': f'Bearer {api_key}',
57
- }
58
- response = requests.post('https://api.fireworks.ai/inference/v1/workflows/accounts/fireworks/models/flux-1-dev-controlnet-union/control_net',
59
- files=files, data=data, headers=headers)
60
- if response.status_code == 200:
61
- return Image.open(BytesIO(response.content)), processed_image, original_image
62
- else:
63
- st.error(f"Request failed with status code: {response.status_code}, Response: {response.text}")
64
- return None, None, None
65
-
66
- def draw_crop_preview(image, x, y, width, height):
67
- draw = ImageDraw.Draw(image)
68
- draw.rectangle([x, y, x + width, y + height], outline="red", width=2)
69
- return image
70
-
71
- st.title("Holiday Card Generator with ControlNet")
72
-
73
- uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
74
-
75
- if uploaded_file is not None:
76
- original_image = Image.open(uploaded_file)
77
- st.image(original_image, caption="Uploaded Image", use_column_width=True)
78
-
79
- img_width, img_height = original_image.size
80
-
81
- col1, col2 = st.columns(2)
82
- with col1:
83
- x_pos = st.slider("X position", 0, img_width, img_width // 4)
84
- crop_width = st.slider("Width", 10, img_width - x_pos, min(img_width // 2, img_width - x_pos))
85
- with col2:
86
- y_pos = st.slider("Y position", 0, img_height, img_height // 4)
87
- crop_height = st.slider("Height", 10, img_height - y_pos, min(img_height // 2, img_height - y_pos))
88
-
89
- preview_image = draw_crop_preview(original_image.copy(), x_pos, y_pos, crop_width, crop_height)
90
- st.image(preview_image, caption="Crop Preview", use_column_width=True)
91
-
92
- st.subheader("Set Parameters for Each Holiday Card")
93
-
94
- # Define the list of suggested holiday prompts
95
- holiday_prompts = [
96
- "A border of Festive snowflakes and winter patterns for a holiday card border",
97
- "A border of Joyful Christmas ornaments and lights decorating the edges",
98
- "A border of Warm and cozy fireplace scene with stockings and garlands",
99
- "A border of Colorful Hanukkah menorahs and dreidels along the border",
100
- "A border of New Year's Eve fireworks with stars and confetti framing the image"
101
- ]
102
-
103
- # Define input fields for each holiday card's parameters
104
- card_params = []
105
- for i in range(4):
106
- st.write(f"### Holiday Card {i + 1}")
107
-
108
- # Dropdown to choose a suggested holiday prompt or enter custom prompt
109
- selected_prompt = st.selectbox(f"Choose a holiday-themed prompt for Holiday Card {i + 1}", options=["Custom"] + holiday_prompts)
110
- custom_prompt = st.text_input(f"Enter custom prompt for Holiday Card {i + 1}", value=f"Custom Prompt {i + 1}") if selected_prompt == "Custom" else selected_prompt
111
-
112
- # Parameter sliders for each holiday card
113
- guidance_scale = st.slider(f"Guidance Scale for Holiday Card {i + 1}", min_value=0.0, max_value=20.0, value=3.5, step=0.1)
114
- num_inference_steps = st.slider(f"Number of Inference Steps for Holiday Card {i + 1}", min_value=1, max_value=100, value=30, step=1)
115
- seed = st.slider(f"Random Seed for Holiday Card {i + 1}", min_value=0, max_value=1000, value=i * 100)
116
- controlnet_conditioning_scale = st.slider(f"ControlNet Conditioning Scale for Holiday Card {i + 1}", min_value=0.0, max_value=1.0, value=0.5, step=0.1)
117
- control_mode = st.slider(f"Control Mode for Holiday Card {i + 1}", min_value=0, max_value=2, value=0, help="0: None, 1: Partial, 2: Full")
118
-
119
- # Save the parameters for each holiday card
120
- card_params.append({
121
- "prompt": custom_prompt,
122
- "guidance_scale": guidance_scale,
123
- "num_inference_steps": num_inference_steps,
124
- "seed": seed,
125
- "controlnet_conditioning_scale": controlnet_conditioning_scale,
126
- "control_mode": control_mode
127
- })
128
-
129
- # Generate the holiday cards
130
- if st.button("Generate Holiday Cards"):
131
- with st.spinner("Processing..."):
132
- # Create a column layout for displaying cards side by side
133
- col1, col2 = st.columns(2)
134
- col3, col4 = st.columns(2)
135
- columns = [col1, col2, col3, col4] # To display images in a 2x2 grid
136
-
137
- # Loop through each card's parameters and generate the holiday card
138
- for i, params in enumerate(card_params):
139
- prompt = params['prompt']
140
- guidance_scale = params['guidance_scale']
141
- num_inference_steps = params['num_inference_steps']
142
- seed = params['seed']
143
- controlnet_conditioning_scale = params['controlnet_conditioning_scale']
144
- control_mode = params['control_mode']
145
-
146
- # Generate the holiday card using the current parameters
147
- generated_image, processed_image, _ = call_control_net_api(
148
- uploaded_file, prompt, control_mode=control_mode,
149
- guidance_scale=guidance_scale, num_inference_steps=num_inference_steps,
150
- seed=seed, controlnet_conditioning_scale=controlnet_conditioning_scale
151
- )
152
-
153
- if generated_image is not None:
154
- # Resize generated_image to match original_image size
155
- generated_image = generated_image.resize(original_image.size)
156
-
157
- # Create a copy of the generated image
158
- final_image = generated_image.copy()
159
-
160
- # Crop the selected portion of the original image
161
- cropped_original = original_image.crop((x_pos, y_pos, x_pos + crop_width, y_pos + crop_height))
162
-
163
- # Get the size of the cropped image
164
- cropped_width, cropped_height = cropped_original.size
165
-
166
- # Calculate the center of the generated image
167
- center_x = (final_image.width - cropped_width) // 2
168
- center_y = (final_image.height - cropped_height) // 2
169
-
170
- # Paste the cropped portion of the original image onto the generated image at the calculated center
171
- final_image.paste(cropped_original, (center_x, center_y))
172
-
173
- # Display the final holiday card in one of the columns
174
- columns[i].image(final_image, caption=f"Holiday Card {i + 1}", use_column_width=True)
175
- else:
176
- st.error(f"Failed to generate holiday card {i + 1}. Please try again.")
177
- else:
178
- st.warning("Please upload an image to get started.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/{2_Multiple_HolidayCard.py → 1_Part_A_-_Experimentation_Station.py} RENAMED
@@ -6,6 +6,8 @@ from PIL import Image, ImageDraw
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')
@@ -68,28 +70,92 @@ def draw_crop_preview(image, x, y, width, height):
68
  draw.rectangle([x, y, x + width, y + height], outline="red", width=2)
69
  return image
70
 
71
- st.title("Holiday Card Generator with ControlNet")
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
 
74
 
75
  if uploaded_file is not None:
76
- original_image = Image.open(uploaded_file)
 
 
 
 
77
  st.image(original_image, caption="Uploaded Image", use_column_width=True)
78
 
79
  img_width, img_height = original_image.size
80
 
 
 
 
 
 
 
 
 
 
 
81
  col1, col2 = st.columns(2)
82
  with col1:
83
- x_pos = st.slider("X position", 0, img_width, img_width // 4)
84
- crop_width = st.slider("Width", 10, img_width - x_pos, min(img_width // 2, img_width - x_pos))
 
 
85
  with col2:
86
- y_pos = st.slider("Y position", 0, img_height, img_height // 4)
87
- crop_height = st.slider("Height", 10, img_height - y_pos, min(img_height // 2, img_height - y_pos))
 
 
88
 
89
  preview_image = draw_crop_preview(original_image.copy(), x_pos, y_pos, crop_width, crop_height)
90
  st.image(preview_image, caption="Crop Preview", use_column_width=True)
 
91
 
92
- st.subheader("Set Parameters for Each Holiday Card")
 
 
 
 
 
93
 
94
  # Define the list of suggested holiday prompts
95
  holiday_prompts = [
@@ -101,33 +167,49 @@ if uploaded_file is not None:
101
  ]
102
 
103
  # Define input fields for each holiday card's parameters in expanders
104
- card_params = []
105
  for i in range(4):
106
  with st.expander(f"Holiday Card {i + 1} Parameters"):
107
  st.write(f"### Holiday Card {i + 1}")
108
 
 
 
 
 
 
 
 
 
 
109
  # Dropdown to choose a suggested holiday prompt or enter custom prompt
110
  selected_prompt = st.selectbox(f"Choose a holiday-themed prompt for Holiday Card {i + 1}", options=["Custom"] + holiday_prompts)
111
- custom_prompt = st.text_input(f"Enter custom prompt for Holiday Card {i + 1}", value=f"Custom Prompt {i + 1}") if selected_prompt == "Custom" else selected_prompt
112
 
113
- # Parameter sliders for each holiday card
114
- guidance_scale = st.slider(f"Guidance Scale for Holiday Card {i + 1}", min_value=0.0, max_value=20.0, value=3.5, step=0.1)
115
- num_inference_steps = st.slider(f"Number of Inference Steps for Holiday Card {i + 1}", min_value=1, max_value=100, value=30, step=1)
116
- seed = st.slider(f"Random Seed for Holiday Card {i + 1}", min_value=0, max_value=1000, value=i * 100)
117
- controlnet_conditioning_scale = st.slider(f"ControlNet Conditioning Scale for Holiday Card {i + 1}", min_value=0.0, max_value=1.0, value=0.5, step=0.1)
118
- control_mode = st.slider(f"Control Mode for Holiday Card {i + 1}", min_value=0, max_value=2, value=0, help="0: None, 1: Partial, 2: Full")
 
 
 
 
 
119
 
120
- # Save the parameters for each holiday card
121
- card_params.append({
122
  "prompt": custom_prompt,
123
  "guidance_scale": guidance_scale,
124
  "num_inference_steps": num_inference_steps,
125
  "seed": seed,
126
  "controlnet_conditioning_scale": controlnet_conditioning_scale,
127
  "control_mode": control_mode
128
- })
 
 
129
 
130
  # Generate the holiday cards
 
131
  if st.button("Generate Holiday Cards"):
132
  with st.spinner("Processing..."):
133
  # Create a column layout for displaying cards side by side
@@ -135,8 +217,12 @@ if uploaded_file is not None:
135
  col3, col4 = st.columns(2)
136
  columns = [col1, col2, col3, col4] # To display images in a 2x2 grid
137
 
 
 
 
 
138
  # Loop through each card's parameters and generate the holiday card
139
- for i, params in enumerate(card_params):
140
  prompt = params['prompt']
141
  guidance_scale = params['guidance_scale']
142
  num_inference_steps = params['num_inference_steps']
@@ -146,7 +232,7 @@ if uploaded_file is not None:
146
 
147
  # Generate the holiday card using the current parameters
148
  generated_image, processed_image, _ = call_control_net_api(
149
- uploaded_file, prompt, control_mode=control_mode,
150
  guidance_scale=guidance_scale, num_inference_steps=num_inference_steps,
151
  seed=seed, controlnet_conditioning_scale=controlnet_conditioning_scale
152
  )
@@ -171,6 +257,29 @@ if uploaded_file is not None:
171
  # Paste the cropped portion of the original image onto the generated image at the calculated center
172
  final_image.paste(cropped_original, (center_x, center_y))
173
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  # Display the final holiday card in one of the columns
175
  columns[i].image(final_image, caption=f"Holiday Card {i + 1}", use_column_width=True)
176
 
@@ -183,6 +292,81 @@ if uploaded_file is not None:
183
  columns[i].write(f"**Control Mode:** {control_mode}")
184
  else:
185
  st.error(f"Failed to generate holiday card {i + 1}. Please try again.")
186
- else:
187
- st.warning("Please upload an image to get started.")
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  import numpy as np
7
  import os
8
  from dotenv import load_dotenv
9
+ import zipfile
10
+
11
 
12
  # Load environment variables
13
  dotenv_path = os.path.join(os.path.dirname(__file__), '../env/.env')
 
70
  draw.rectangle([x, y, x + width, y + height], outline="red", width=2)
71
  return image
72
 
 
73
 
74
+ # Fireworks Logo at the top
75
+ logo_image = Image.open("img/fireworksai_logo.png")
76
+ st.image(logo_image)
77
+
78
+ st.title("🎨 Holiday Card Generator - Part A: Design & Ideation 🎨")
79
+ st.markdown(
80
+ """Welcome to the first part of your holiday card creation journey! 🌟 Here, you’ll play around with different styles, prompts, and parameters to design the perfect card border before adding a personal message in Part B. Let your creativity flow! 🎉
81
+
82
+ ### How it works:
83
+
84
+ 1. **🖼️ Upload Your Image:** Choose the image that will be the center of your card.
85
+ 2. **✂️ Crop It:** Adjust the crop to highlight the most important part of your image.
86
+ 3. **💡 Choose Your Style:** Select from festive border themes or input your own custom prompt to design something unique.
87
+ 4. **⚙️ Fine-Tune Parameters:** Experiment with guidance scales, seeds, inference steps, and more for the perfect aesthetic.
88
+ 5. **👀 Preview & Download:** See your generated holiday cards, tweak them until they’re just right, and download the final designs and metadata in a neat ZIP file!
89
+
90
+ Once you’ve got the perfect look, head over to **Part B** to add your personal message and finalize your holiday card! 💌
91
+
92
+ """
93
+ )
94
+
95
+ # Add divider and subheader for uploading section
96
+ st.divider()
97
+ st.subheader("🖼️ Step 1: Upload Your Picture!")
98
+ st.markdown("""
99
+ - Click on the **Upload Image** button to select the image you want to feature on your holiday card.
100
+ - Accepted formats: **JPG** or **PNG**.
101
+ - Once uploaded, your image will appear on the screen—easy peasy!
102
+ """)
103
+ st.write("Upload the image that will be used for generating your holiday card.")
104
+
105
+ # Initialize session state variables if they don't exist
106
+ if 'uploaded_file' not in st.session_state:
107
+ st.session_state.uploaded_file = None
108
+ if 'card_params' not in st.session_state:
109
+ st.session_state.card_params = [{} for _ in range(4)] # Initialize for 4 cards
110
+ if 'generated_cards' not in st.session_state:
111
+ st.session_state.generated_cards = [None for _ in range(4)] # Store generated images and metadata
112
+
113
+ # File uploader - if a file is uploaded, save it in session_state
114
  uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
115
+ st.divider()
116
 
117
  if uploaded_file is not None:
118
+ st.session_state.uploaded_file = uploaded_file # Save to session state
119
+
120
+ # Load the image from session state
121
+ if st.session_state.uploaded_file is not None:
122
+ original_image = Image.open(st.session_state.uploaded_file)
123
  st.image(original_image, caption="Uploaded Image", use_column_width=True)
124
 
125
  img_width, img_height = original_image.size
126
 
127
+ # Add a divider and subheader for the crop section
128
+ st.divider()
129
+ st.subheader("✂️ Step 2: Crop It Like It's Hot!")
130
+ st.markdown("""
131
+ - Adjust the **crop** sliders to select the perfect area of your image.
132
+ - This cropped section will be the centerpiece of your festive card. 🎨
133
+ - A preview will show you exactly how your crop looks before moving to the next step!
134
+ """)
135
+ st.write("Select the area you want to crop from the original image. This cropped portion will be used in the final card.")
136
+
137
  col1, col2 = st.columns(2)
138
  with col1:
139
+ x_pos = st.slider("X position (Left-Right)", 0, img_width, img_width // 4,
140
+ help="Move the slider to adjust the crop's left-right position.")
141
+ crop_width = st.slider("Width", 10, img_width - x_pos, min(img_width // 2, img_width - x_pos),
142
+ help="Adjust the width of the crop.")
143
  with col2:
144
+ y_pos = st.slider("Y position (Up-Down)", 0, img_height, img_height // 4,
145
+ help="Move the slider to adjust the crop's up-down position.")
146
+ crop_height = st.slider("Height", 10, img_height - y_pos, min(img_height // 2, img_height - y_pos),
147
+ help="Adjust the height of the crop.")
148
 
149
  preview_image = draw_crop_preview(original_image.copy(), x_pos, y_pos, crop_width, crop_height)
150
  st.image(preview_image, caption="Crop Preview", use_column_width=True)
151
+ st.divider()
152
 
153
+ st.subheader("⚙️ Step 3: Set Your Festive Border Design with Flux + Fireworks!")
154
+ st.markdown("""
155
+ - Choose from a selection of holiday-themed borders like **snowflakes**, **Christmas lights**, or even **New Year's Eve fireworks**—all generated through **Flux models on Fireworks!** ✨
156
+ - Want to get creative? No problem—enter your own **custom prompt** to create a border that's as unique as you are, all powered by **Fireworks' inference API**.
157
+ """)
158
+ st.write("Customize the parameters for generating each holiday card. Each parameter will influence the final design and style of the card.")
159
 
160
  # Define the list of suggested holiday prompts
161
  holiday_prompts = [
 
167
  ]
168
 
169
  # Define input fields for each holiday card's parameters in expanders
 
170
  for i in range(4):
171
  with st.expander(f"Holiday Card {i + 1} Parameters"):
172
  st.write(f"### Holiday Card {i + 1}")
173
 
174
+ # Get the card params from session_state if they exist
175
+ card_params = st.session_state.card_params[i]
176
+ card_params.setdefault("prompt", f"Custom Prompt {i + 1}")
177
+ card_params.setdefault("guidance_scale", 3.5)
178
+ card_params.setdefault("num_inference_steps", 30)
179
+ card_params.setdefault("seed", i * 100)
180
+ card_params.setdefault("controlnet_conditioning_scale", 0.5)
181
+ card_params.setdefault("control_mode", 0)
182
+
183
  # Dropdown to choose a suggested holiday prompt or enter custom prompt
184
  selected_prompt = st.selectbox(f"Choose a holiday-themed prompt for Holiday Card {i + 1}", options=["Custom"] + holiday_prompts)
185
+ custom_prompt = st.text_input(f"Enter custom prompt for Holiday Card {i + 1}", value=card_params["prompt"]) if selected_prompt == "Custom" else selected_prompt
186
 
187
+ # Parameter sliders for each holiday card with tooltips
188
+ guidance_scale = st.slider(f"Guidance Scale for Holiday Card {i + 1}", min_value=0.0, max_value=20.0, value=card_params["guidance_scale"], step=0.1,
189
+ help="Adjusts how strongly the model follows the prompt. Higher values mean stronger adherence to the prompt.")
190
+ num_inference_steps = st.slider(f"Number of Inference Steps for Holiday Card {i + 1}", min_value=1, max_value=100, value=card_params["num_inference_steps"], step=1,
191
+ help="More inference steps can lead to a higher quality image but will take longer to generate.")
192
+ seed = st.slider(f"Random Seed for Holiday Card {i + 1}", min_value=0, max_value=1000, value=card_params["seed"],
193
+ help="The seed value allows you to recreate the same image each time, or explore variations by changing the seed.")
194
+ controlnet_conditioning_scale = st.slider(f"ControlNet Conditioning Scale for Holiday Card {i + 1}", min_value=0.0, max_value=1.0, value=card_params["controlnet_conditioning_scale"], step=0.1,
195
+ help="Controls how much the ControlNet input influences the output. A lower value reduces its influence.")
196
+ control_mode = st.slider(f"Control Mode for Holiday Card {i + 1}", min_value=0, max_value=2, value=card_params["control_mode"],
197
+ help="Choose how much ControlNet should influence the final image. 0: None, 1: Partial, 2: Full.")
198
 
199
+ # Update session state with the latest parameters
200
+ st.session_state.card_params[i] = {
201
  "prompt": custom_prompt,
202
  "guidance_scale": guidance_scale,
203
  "num_inference_steps": num_inference_steps,
204
  "seed": seed,
205
  "controlnet_conditioning_scale": controlnet_conditioning_scale,
206
  "control_mode": control_mode
207
+ }
208
+
209
+ st.divider() # Add a divider before the "Generate" button
210
 
211
  # Generate the holiday cards
212
+ st.subheader("Just hit play!")
213
  if st.button("Generate Holiday Cards"):
214
  with st.spinner("Processing..."):
215
  # Create a column layout for displaying cards side by side
 
217
  col3, col4 = st.columns(2)
218
  columns = [col1, col2, col3, col4] # To display images in a 2x2 grid
219
 
220
+ # Store image bytes and metadata in lists
221
+ image_files = []
222
+ metadata = []
223
+
224
  # Loop through each card's parameters and generate the holiday card
225
+ for i, params in enumerate(st.session_state.card_params):
226
  prompt = params['prompt']
227
  guidance_scale = params['guidance_scale']
228
  num_inference_steps = params['num_inference_steps']
 
232
 
233
  # Generate the holiday card using the current parameters
234
  generated_image, processed_image, _ = call_control_net_api(
235
+ st.session_state.uploaded_file, prompt, control_mode=control_mode,
236
  guidance_scale=guidance_scale, num_inference_steps=num_inference_steps,
237
  seed=seed, controlnet_conditioning_scale=controlnet_conditioning_scale
238
  )
 
257
  # Paste the cropped portion of the original image onto the generated image at the calculated center
258
  final_image.paste(cropped_original, (center_x, center_y))
259
 
260
+ # Save image to BytesIO
261
+ img_byte_arr = BytesIO()
262
+ final_image.save(img_byte_arr, format="PNG")
263
+ img_byte_arr.seek(0)
264
+ image_files.append((f"holiday_card_{i + 1}.png", img_byte_arr))
265
+
266
+ # Store metadata
267
+ metadata.append({
268
+ "Card": f"Holiday Card {i + 1}",
269
+ "Prompt": prompt,
270
+ "Guidance Scale": guidance_scale,
271
+ "Inference Steps": num_inference_steps,
272
+ "Seed": seed,
273
+ "ControlNet Conditioning Scale": controlnet_conditioning_scale,
274
+ "Control Mode": control_mode
275
+ })
276
+
277
+ # Persist image and metadata in session state
278
+ st.session_state.generated_cards[i] = {
279
+ "image": final_image,
280
+ "metadata": metadata[-1]
281
+ }
282
+
283
  # Display the final holiday card in one of the columns
284
  columns[i].image(final_image, caption=f"Holiday Card {i + 1}", use_column_width=True)
285
 
 
292
  columns[i].write(f"**Control Mode:** {control_mode}")
293
  else:
294
  st.error(f"Failed to generate holiday card {i + 1}. Please try again.")
 
 
295
 
296
+ # Create ZIP file for download
297
+ if image_files:
298
+ zip_buffer = BytesIO()
299
+ with zipfile.ZipFile(zip_buffer, "w") as zf:
300
+ # Add images to the ZIP file
301
+ for file_name, img_data in image_files:
302
+ zf.writestr(file_name, img_data.getvalue())
303
+
304
+ # Add metadata to the ZIP file
305
+ 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])
306
+ zf.writestr("metadata.txt", metadata_str)
307
+
308
+ zip_buffer.seek(0)
309
+ st.subheader("Step 4: Download & Share Your Masterpiece! 📥")
310
+ st.markdown("""
311
+ - Once you're happy with your card, simply hit the download button to save your card and message as a **PNG** image.
312
+ - You can also view and download any **previously generated holiday cards** from this session!
313
+ """)
314
+ st.download_button(
315
+ label="Download all images and metadata as ZIP",
316
+ data=zip_buffer,
317
+ file_name="holiday_cards.zip",
318
+ mime="application/zip"
319
+ )
320
+
321
+ # Display previously generated cards if they exist and create a ZIP download button
322
+ st.divider()
323
+ st.subheader("Previously Generated Holiday Cards")
324
+ if any(st.session_state.generated_cards):
325
+ col1, col2 = st.columns(2)
326
+ col3, col4 = st.columns(2)
327
+ columns = [col1, col2, col3, col4] # Display in 2x2 grid
328
+
329
+ image_files = []
330
+ metadata = [] # Ensure metadata is initialized as a list
331
+
332
+ # Loop through previously generated cards
333
+ for i, card in enumerate(st.session_state.generated_cards):
334
+ if card and "metadata" in card: # Ensure the card exists and has metadata
335
+ columns[i].image(card['image'], caption=f"Holiday Card {i + 1} (Saved)")
336
+ card_metadata = card['metadata'] # Retrieve the metadata for the current card
337
+ columns[i].write(f"**Prompt:** {card_metadata['Prompt']}")
338
+ columns[i].write(f"**Guidance Scale:** {card_metadata['Guidance Scale']}")
339
+ columns[i].write(f"**Inference Steps:** {card_metadata['Inference Steps']}")
340
+ columns[i].write(f"**Seed:** {card_metadata['Seed']}")
341
+ columns[i].write(f"**ControlNet Conditioning Scale:** {card_metadata['ControlNet Conditioning Scale']}")
342
+ columns[i].write(f"**Control Mode:** {card_metadata['Control Mode']}")
343
+
344
+ # Add each image and its metadata to prepare for ZIP download
345
+ img_byte_arr = BytesIO()
346
+ card['image'].save(img_byte_arr, format="PNG")
347
+ img_byte_arr.seek(0)
348
+ image_files.append((f"holiday_card_{i + 1}.png", img_byte_arr))
349
+ metadata.append(card_metadata) # Append card's metadata to the metadata list
350
+
351
+ # Provide a ZIP download button for previously generated cards
352
+ if image_files:
353
+ zip_buffer = BytesIO()
354
+ with zipfile.ZipFile(zip_buffer, "w") as zf:
355
+ # Add images to the ZIP file
356
+ for file_name, img_data in image_files:
357
+ zf.writestr(file_name, img_data.getvalue())
358
+
359
+ # Add metadata to the ZIP file
360
+ 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])
361
+ zf.writestr("metadata.txt", metadata_str)
362
+
363
+ # """ zip_buffer.seek(0)
364
+ # st.divider()
365
+ # st.subheader("Save images & metadata")
366
+ # st.download_button(
367
+ # label="Download all previously generated images and metadata as ZIP",
368
+ # data=zip_buffer,
369
+ # file_name="holiday_cards.zip",
370
+ # mime="application/zip"
371
+ # )
372
+ # """
pages/2_Customize_HolidayCard.py DELETED
@@ -1,322 +0,0 @@
1
- import streamlit as st
2
- import cv2
3
- import requests
4
- from io import BytesIO
5
- from PIL import Image, ImageDraw, ImageFont
6
- import numpy as np
7
- import os
8
- from dotenv import load_dotenv
9
- from datetime import datetime
10
- import json
11
-
12
- # Load environment variables
13
- dotenv_path = os.path.join(os.path.dirname(__file__), '../env/.env')
14
- load_dotenv(dotenv_path, override=True)
15
- api_key = os.getenv("FIREWORKS_API_KEY")
16
-
17
- if not api_key:
18
- st.error("API key not found. Make sure FIREWORKS_API_KEY is set in the .env file.")
19
- st.stop()
20
-
21
- VALID_ASPECT_RATIOS = {
22
- (1, 1): "1:1", (21, 9): "21:9", (16, 9): "16:9", (3, 2): "3:2", (5, 4): "5:4",
23
- (4, 5): "4:5", (2, 3): "2:3", (9, 16): "9:16", (9, 21): "9:21",
24
- }
25
-
26
- def get_closest_aspect_ratio(width, height):
27
- aspect_ratio = width / height
28
- closest_ratio = min(VALID_ASPECT_RATIOS.keys(), key=lambda x: abs((x[0] / x[1]) - aspect_ratio))
29
- return VALID_ASPECT_RATIOS[closest_ratio]
30
-
31
- def create_control_image(original_image, x_pos, y_pos, crop_width, crop_height):
32
- cropped_area = original_image.crop((x_pos, y_pos, x_pos + crop_width, y_pos + crop_height))
33
- pad_width = int(crop_width * 0.2)
34
- pad_height = int(crop_height * 0.2)
35
- padded_width = crop_width + 2 * pad_width
36
- padded_height = crop_height + 2 * pad_height
37
- control_image = Image.new('RGB', (padded_width, padded_height), (128, 128, 128))
38
- control_image.paste(cropped_area, (pad_width, pad_height))
39
- return control_image
40
-
41
- def process_image(image):
42
- gray_image = image.convert('L')
43
- np_image = np.array(gray_image)
44
- edges = cv2.Canny(np_image, 100, 200)
45
- edges_rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
46
- edge_image = Image.fromarray(edges_rgb)
47
- byte_arr = BytesIO()
48
- edge_image.save(byte_arr, format='JPEG')
49
- byte_arr.seek(0)
50
- return byte_arr, edge_image
51
-
52
- 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):
53
- processed_image_bytes, processed_image = process_image(control_image)
54
- files = {'control_image': ('control_image.jpg', processed_image_bytes, 'image/jpeg')}
55
-
56
- width, height = control_image.size
57
- aspect_ratio = get_closest_aspect_ratio(width, height)
58
-
59
- data = {
60
- 'prompt': prompt,
61
- 'control_mode': control_mode,
62
- 'aspect_ratio': aspect_ratio,
63
- 'guidance_scale': guidance_scale,
64
- 'num_inference_steps': num_inference_steps,
65
- 'seed': seed,
66
- 'controlnet_conditioning_scale': controlnet_conditioning_scale
67
- }
68
-
69
- headers = {
70
- 'accept': 'image/jpeg',
71
- 'authorization': f'Bearer {api_key}',
72
- }
73
-
74
- response = requests.post(
75
- 'https://api.fireworks.ai/inference/v1/workflows/accounts/fireworks/models/flux-1-dev-controlnet-union/control_net',
76
- files=files, data=data, headers=headers
77
- )
78
-
79
- if response.status_code == 200:
80
- return Image.open(BytesIO(response.content)), processed_image
81
- else:
82
- st.error(f"Request failed with status code: {response.status_code}, Response: {response.text}")
83
- return None, None
84
-
85
- def draw_crop_preview(image, x, y, width, height):
86
- draw = ImageDraw.Draw(image)
87
- for i in range(5): # Draw multiple rectangles for thickness
88
- draw.rectangle([x+i, y+i, x+width-i, y+height-i], outline="red")
89
- return image
90
-
91
- def create_placement_preview(generated_image, original_image, x_pos, y_pos, crop_width, crop_height, final_x_pos, final_y_pos, resize_factor):
92
- expand_factor = 1.3
93
- new_width = int(original_image.width * expand_factor)
94
- new_height = int(original_image.height * expand_factor)
95
-
96
- preview_image = generated_image.resize((new_width, new_height)).copy()
97
- draw = ImageDraw.Draw(preview_image)
98
-
99
- # Try to load a bold font, fall back to default if not available
100
- try:
101
- font = ImageFont.truetype("arialbd.ttf", 60) # Trying to use Arial Bold with larger size
102
- except IOError:
103
- try:
104
- font = ImageFont.truetype("arial.ttf", 60) # Fallback to regular Arial
105
- except IOError:
106
- font = ImageFont.load_default()
107
-
108
- # Function to draw text with background
109
- def draw_text_with_background(draw, text, position, font, text_color, bg_color):
110
- text_bbox = draw.textbbox(position, text, font=font)
111
- draw.rectangle(text_bbox, fill=bg_color)
112
- draw.text(position, text, font=font, fill=text_color)
113
-
114
- # Draw rule of thirds lines with labels
115
- for i in range(1, 3):
116
- x = new_width * i // 3
117
- y = new_height * i // 3
118
- draw.line([(x, 0), (x, new_height)], fill=(255, 255, 0), width=5) # Even thicker vertical lines
119
- draw.line([(0, y), (new_width, y)], fill=(255, 255, 0), width=5) # Even thicker horizontal lines
120
-
121
- # Add labels with background
122
- draw_text_with_background(draw, f"{i/3:.2f}", (x + 10, 20), font, (0, 0, 0), (255, 255, 255, 180))
123
- draw_text_with_background(draw, f"{i/3:.2f}", (20, y + 10), font, (0, 0, 0), (255, 255, 255, 180))
124
-
125
- # Draw center crosshair
126
- center_x, center_y = new_width // 2, new_height // 2
127
- crosshair_size = min(new_width, new_height) // 15
128
- draw.line([(center_x - crosshair_size, center_y), (center_x + crosshair_size, center_y)], fill=(0, 255, 255), width=5)
129
- draw.line([(center_x, center_y - crosshair_size), (center_x, center_y + crosshair_size)], fill=(0, 255, 255), width=5)
130
- draw_text_with_background(draw, "0.50", (center_x + 10, center_y + 10), font, (0, 0, 0), (255, 255, 255, 180))
131
-
132
- # Add more position indicators
133
- for i in range(0, 11):
134
- x = new_width * i // 10
135
- y = new_height * i // 10
136
- if i % 5 != 0: # Skip 0, 0.5, and 1 as they're already marked
137
- draw_text_with_background(draw, f"{i/10:.2f}", (x + 10, 20), font, (0, 0, 0), (255, 255, 255, 180))
138
- draw_text_with_background(draw, f"{i/10:.2f}", (20, y + 10), font, (0, 0, 0), (255, 255, 255, 180))
139
-
140
- # Crop and resize the original image
141
- cropped_original = original_image.crop((x_pos, y_pos, x_pos + crop_width, y_pos + crop_height))
142
- new_crop_width = int(crop_width * resize_factor)
143
- new_crop_height = int(crop_height * resize_factor)
144
- cropped_original = cropped_original.resize((new_crop_width, new_crop_height), Image.LANCZOS)
145
-
146
- # Calculate paste position
147
- paste_x = int(final_x_pos * new_width)
148
- paste_y = int(final_y_pos * new_height)
149
-
150
- # Paste the cropped and resized original onto the preview
151
- preview_image.paste(cropped_original, (paste_x, paste_y))
152
-
153
- # Draw a border around the pasted area
154
- for i in range(5): # Draw multiple rectangles for thickness
155
- draw.rectangle([paste_x+i, paste_y+i, paste_x+new_crop_width-i, paste_y+new_crop_height-i], outline=(255, 0, 0), width=2)
156
-
157
- return preview_image
158
-
159
- def create_final_image(original_image, generated_image, x_pos, y_pos, crop_width, crop_height, final_x_pos, final_y_pos, resize_factor):
160
- expand_factor = 1.3
161
- new_width = int(original_image.width * expand_factor)
162
- new_height = int(original_image.height * expand_factor)
163
-
164
- final_image = generated_image.resize((new_width, new_height))
165
- paste_x = int(final_x_pos * new_width)
166
- paste_y = int(final_y_pos * new_height)
167
- cropped_original = original_image.crop((x_pos, y_pos, x_pos + crop_width, y_pos + crop_height))
168
- new_crop_width = int(crop_width * resize_factor)
169
- new_crop_height = int(crop_height * resize_factor)
170
- cropped_original = cropped_original.resize((new_crop_width, new_crop_height), Image.LANCZOS)
171
- final_image.paste(cropped_original, (paste_x, paste_y))
172
-
173
- return final_image
174
-
175
- def create_run_folder():
176
- folder_name = f"run_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
177
- full_path = os.path.join(os.path.dirname(__file__), folder_name)
178
- os.makedirs(full_path, exist_ok=True)
179
- return full_path
180
-
181
- def save_results(folder, original, generated, control, composite, metadata):
182
- original.save(os.path.join(folder, "original.png"))
183
- generated.save(os.path.join(folder, "generated.png"))
184
- control.save(os.path.join(folder, "control.png"))
185
- composite.save(os.path.join(folder, "composite.png"))
186
- with open(os.path.join(folder, "metadata.json"), 'w') as f:
187
- json.dump(metadata, f, indent=4)
188
-
189
- # Streamlit UI
190
- st.title("Holiday Card Generator with ControlNet")
191
-
192
- uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
193
-
194
- if uploaded_file is not None:
195
- original_image = Image.open(uploaded_file)
196
- st.image(original_image, caption="Uploaded Image", use_column_width=True)
197
-
198
- img_width, img_height = original_image.size
199
-
200
- st.subheader("Crop Selection")
201
- col1, col2 = st.columns(2)
202
- with col1:
203
- x_pos = st.slider("X position", 0, img_width, img_width // 4)
204
- crop_width = st.slider("Width", 10, img_width - x_pos, min(img_width // 2, img_width - x_pos))
205
- with col2:
206
- y_pos = st.slider("Y position", 0, img_height, img_height // 4)
207
- crop_height = st.slider("Height", 10, img_height - y_pos, min(img_height // 2, img_height - y_pos))
208
-
209
- preview_image = draw_crop_preview(original_image.copy(), x_pos, y_pos, crop_width, crop_height)
210
- st.image(preview_image, caption="Crop Preview", use_column_width=True)
211
-
212
- holiday_prompts = [
213
- "A border of Festive snowflakes and winter patterns for a holiday card border",
214
- "A border of Joyful Christmas ornaments and lights decorating the edges",
215
- "A border of Warm and cozy fireplace scene with stockings and garlands",
216
- "A border of Colorful Hanukkah menorahs and dreidels along the border",
217
- "A border of New Year's Eve fireworks with stars and confetti framing the image"
218
- ]
219
-
220
- selected_prompt = st.selectbox("Choose a holiday-themed prompt or enter your own", options=["Custom"] + holiday_prompts)
221
- custom_prompt = st.text_input("Enter your custom prompt") if selected_prompt == "Custom" else ""
222
- prompt = custom_prompt if selected_prompt == "Custom" else selected_prompt
223
-
224
- with st.expander("Advanced Parameters"):
225
- control_mode = st.slider("Control Mode", min_value=0, max_value=2, value=0)
226
- controlnet_conditioning_scale = st.slider("ControlNet Conditioning Scale", min_value=0.0, max_value=1.0, value=0.5, step=0.1)
227
- guidance_scale = st.slider("Guidance Scale", min_value=0.0, max_value=20.0, value=3.5, step=0.1)
228
- num_inference_steps = st.slider("Number of Inference Steps", min_value=1, max_value=100, value=30, step=1)
229
- seed = st.slider("Random Seed", min_value=0, max_value=1000, value=0)
230
-
231
- if st.button("Generate Flux Image"):
232
- if not prompt.strip():
233
- st.error("Please enter a prompt.")
234
- else:
235
- with st.spinner("Generating Flux image..."):
236
- control_image = create_control_image(original_image, x_pos, y_pos, crop_width, crop_height)
237
- st.image(control_image, caption="Control Image (Cropped and Padded)", use_column_width=True)
238
-
239
- generated_image, processed_image = call_control_net_api(
240
- control_image, prompt, control_mode=control_mode,
241
- guidance_scale=guidance_scale, num_inference_steps=num_inference_steps,
242
- seed=seed, controlnet_conditioning_scale=controlnet_conditioning_scale
243
- )
244
-
245
- if generated_image is not None:
246
- with st.expander("Edge Detection Result (Input to ControlNet)"):
247
- st.image(processed_image, caption="Processed Edge Detection Image", use_column_width=True)
248
-
249
- st.session_state.generated_image = generated_image
250
- st.session_state.control_image = control_image
251
- st.image(generated_image, caption="Generated Flux Image", use_column_width=True)
252
- st.success("Flux image generated successfully! Now you can choose the final placement and size.")
253
- else:
254
- st.error("Failed to generate image. Please try again.")
255
-
256
- if 'generated_image' in st.session_state:
257
- st.subheader("Final Image Placement and Sizing")
258
-
259
- # Radio button for centering or manual position
260
- placement_option = st.radio(
261
- "Choose placement mode:",
262
- ("Manual Position", "Auto Center")
263
- )
264
-
265
- # Resize factor (applied in both modes)
266
- resize_factor = st.slider("Resize factor", 0.1, 2.0, 1.0, 0.1,
267
- help="1.0 is original size, <1 is smaller, >1 is larger")
268
-
269
- # Get dimensions of generated image and resized cropped image
270
- generated_width, generated_height = st.session_state.generated_image.size
271
- crop_width_resized = int(crop_width * resize_factor)
272
- crop_height_resized = int(crop_height * resize_factor)
273
-
274
- if placement_option == "Manual Position":
275
- # Manual position: User selects final X & Y
276
- col3, col4, col5 = st.columns(3)
277
- with col3:
278
- final_x_pos = st.slider("Final X position", 0.0, 1.0, 0.5, 0.01,
279
- help="0 is left, 1 is right")
280
- with col4:
281
- final_y_pos = st.slider("Final Y position", 0.0, 1.0, 0.5, 0.01,
282
- help="0 is top, 1 is bottom")
283
- else:
284
- # Auto-center: Calculate center positions, adjusting for the resized cropped image dimensions
285
- final_x_pos = (generated_width - crop_width_resized) / 2 / generated_width
286
- final_y_pos = (generated_height - crop_height_resized) / 2 / generated_height
287
-
288
- # Generate placement preview with updated final X & Y positions and resize factor
289
- placement_preview = create_placement_preview(st.session_state.generated_image, original_image,
290
- x_pos, y_pos, crop_width, crop_height,
291
- final_x_pos, final_y_pos, resize_factor)
292
- st.image(placement_preview, caption="Placement and Size Preview (with numbered guidelines)", use_column_width=True)
293
- st.info("Yellow lines show the rule of thirds. Cyan crosshair shows the center. White numbers indicate position values. Use these to help position your image.")
294
-
295
-
296
-
297
- if st.button("Create Final Holiday Card"):
298
- final_image = create_final_image(original_image, st.session_state.generated_image,
299
- x_pos, y_pos, crop_width, crop_height,
300
- final_x_pos, final_y_pos, resize_factor)
301
- st.subheader("Final Holiday Card")
302
- st.image(final_image, caption="Holiday Card Image with Custom Placement and Size", use_column_width=True)
303
-
304
- # Save results
305
- run_folder = create_run_folder()
306
- metadata = {
307
- "prompt": prompt,
308
- "crop": {"x": x_pos, "y": y_pos, "width": crop_width, "height": crop_height},
309
- "placement": {"x": final_x_pos, "y": final_y_pos},
310
- "resize_factor": resize_factor,
311
- "control_mode": control_mode,
312
- "controlnet_conditioning_scale": controlnet_conditioning_scale,
313
- "guidance_scale": guidance_scale,
314
- "num_inference_steps": num_inference_steps,
315
- "seed": seed
316
- }
317
- save_results(run_folder, original_image, st.session_state.generated_image,
318
- st.session_state.control_image, final_image, metadata)
319
- st.success(f"Results saved in folder: {run_folder}")
320
-
321
- else:
322
- st.warning("Please upload an image to get started.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
pages/2_Part_B_-_Card_Generator.py ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import cv2
3
+ import requests
4
+ from io import BytesIO
5
+ from PIL import Image, ImageDraw, ImageFont, ImageFile
6
+ import numpy as np
7
+ import os
8
+ from dotenv import load_dotenv
9
+ import zipfile
10
+
11
+ # Allow truncated images to be loaded
12
+ ImageFile.LOAD_TRUNCATED_IMAGES = True
13
+
14
+ # Load environment variables
15
+ dotenv_path = os.path.join(os.path.dirname(__file__), '../env/.env')
16
+ load_dotenv(dotenv_path, override=True)
17
+ api_key = os.getenv("FIREWORKS_API_KEY")
18
+
19
+ # Folder to store generated images
20
+ GENERATED_IMAGES_DIR = "generated_images"
21
+ os.makedirs(GENERATED_IMAGES_DIR, exist_ok=True)
22
+
23
+ if not api_key:
24
+ st.error("API key not found. Make sure FIREWORKS_API_KEY is set in the .env file.")
25
+ st.stop()
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 VALID_ASPECT_RATIOS[closest_ratio]
36
+
37
+ def process_image(uploaded_image):
38
+ image = np.array(Image.open(uploaded_image).convert('L'))
39
+ edges = cv2.Canny(image, 100, 200)
40
+ edges_rgb = cv2.cvtColor(edges, cv2.COLOR_GRAY2RGB)
41
+ pil_image = Image.fromarray(edges_rgb)
42
+ byte_arr = BytesIO()
43
+ pil_image.save(byte_arr, format='JPEG')
44
+ byte_arr.seek(0)
45
+ return byte_arr, pil_image
46
+
47
+ def call_control_net_api(uploaded_image, prompt, control_mode=0, guidance_scale=3.5, num_inference_steps=30, seed=0, controlnet_conditioning_scale=1.0):
48
+ control_image, processed_image = process_image(uploaded_image)
49
+ files = {'control_image': ('control_image.jpg', control_image, 'image/jpeg')}
50
+ original_image = Image.open(uploaded_image)
51
+ width, height = original_image.size
52
+ aspect_ratio = get_closest_aspect_ratio(width, height)
53
+ data = {
54
+ 'prompt': prompt,
55
+ 'control_mode': control_mode,
56
+ 'aspect_ratio': aspect_ratio,
57
+ 'guidance_scale': guidance_scale,
58
+ 'num_inference_steps': num_inference_steps,
59
+ 'seed': seed,
60
+ 'controlnet_conditioning_scale': controlnet_conditioning_scale
61
+ }
62
+ headers = {
63
+ 'accept': 'image/jpeg',
64
+ 'authorization': f'Bearer {api_key}',
65
+ }
66
+ response = requests.post('https://api.fireworks.ai/inference/v1/workflows/accounts/fireworks/models/flux-1-dev-controlnet-union/control_net',
67
+ files=files, data=data, headers=headers)
68
+ if response.status_code == 200:
69
+ return Image.open(BytesIO(response.content)), processed_image, original_image
70
+ else:
71
+ st.error(f"Request failed with status code: {response.status_code}, Response: {response.text}")
72
+ return None, None, None
73
+
74
+ def draw_crop_preview(image, x, y, width, height):
75
+ draw = ImageDraw.Draw(image)
76
+ draw.rectangle([x, y, x + width, y + height], outline="red", width=2)
77
+ return image
78
+
79
+ def add_message_to_image(image, cropped_bottom_y, message, font_path, font_size):
80
+ draw = ImageDraw.Draw(image)
81
+
82
+ # Try to load the selected font file with user-defined size
83
+ try:
84
+ font = ImageFont.truetype(font_path, font_size)
85
+ st.write(f"Loaded font from {font_path} with font size {font_size}")
86
+ except IOError as e:
87
+ st.error(f"Error loading font: {e}. Loading default font.")
88
+ font = ImageFont.load_default()
89
+
90
+ # Calculate the text size dynamically
91
+ text_bbox = draw.textbbox((0, 0), message, font=font)
92
+ text_width = text_bbox[2] - text_bbox[0]
93
+ text_height = text_bbox[3] - text_bbox[1]
94
+ st.write(f"Text width: {text_width}, Text height: {text_height}")
95
+
96
+ # Calculate the space between the bottom of the cropped image and the bottom of the card
97
+ bottom_space = image.height - cropped_bottom_y
98
+
99
+ # Place the text box centered along the Y axis in the bottom space
100
+ y_position = cropped_bottom_y + (bottom_space - text_height) // 2
101
+
102
+ # Position the text box at the center of the width of the image
103
+ x_position = (image.width - text_width) // 2
104
+
105
+ # Define the padding for the text box
106
+ padding_x = 50 # Adjust the padding width as needed
107
+ padding_y = 50 # Adjust the padding height as needed
108
+
109
+ # Define the text box (background) coordinates with padding
110
+ box_coords = [
111
+ x_position - padding_x, y_position - padding_y,
112
+ x_position + text_width + padding_x, y_position + text_height + padding_y
113
+ ]
114
+
115
+ # Draw a white rectangle as the background for the text box
116
+ draw.rectangle(box_coords, fill="white")
117
+
118
+ # Draw the text in black on top of the white background
119
+ draw.text((x_position, y_position), message, font=font, fill="black")
120
+
121
+ return image
122
+
123
+ # Define the fonts you want to allow
124
+ fonts = {
125
+ "DejaVu Sans Bold": "./fonts/dejavu-sans-bold.ttf",
126
+ "Covered By You": "./fonts/CoveredByYourGrace-Regular.ttf", # Update this path to your actual font paths
127
+ "Julee Regular": "./fonts/Julee-Regular.ttf", # Example font
128
+ "Kalam Regular": "./fonts/Kalam-Regular.ttf",
129
+ "Knewave Regular": "./fonts/Knewave-Regular.ttf",
130
+ "Sancreek Regular": "./fonts/Sancreek-Regular.ttf",
131
+ "Vast Shadow Regular": "./fonts/VastShadow-Regular.ttf",
132
+ }
133
+
134
+ # Fireworks Logo at the top
135
+ logo_image = Image.open("img/fireworksai_logo.png")
136
+ st.image(logo_image)
137
+
138
+ st.title("🎨 Holiday Card Generator - Part B: Finalize Your Holiday Card")
139
+
140
+ st.markdown("""
141
+ Welcome back! You've already set your favorite parameters, and now it's time to finalize your custom holiday card.
142
+
143
+ **Steps**:
144
+ 1. **Choose a Border**: Select or confirm a holiday-themed border to frame your image—choose from snowflakes, ornaments, cozy fireplaces, and more!
145
+ 2. **Add a Personalized Message**: Write your holiday greeting and customize it with font and size options to match your style.
146
+ 3. **Review & Download**: Preview your finished card and download it for sharing.
147
+
148
+ **Features**:
149
+ - Confirm your AI-generated border with your preferred parameters
150
+ - Personalize the message with a variety of fonts and sizes
151
+ - Save your card with metadata for future use
152
+
153
+ 🎁 Get your perfect holiday card ready to share! 🌟
154
+ """)
155
+
156
+
157
+ st.divider()
158
+
159
+ # Initialize session state variables if they don't exist
160
+ if 'uploaded_file' not in st.session_state:
161
+ st.session_state.uploaded_file = None
162
+ if 'generated_image' not in st.session_state:
163
+ st.session_state.generated_image = None
164
+
165
+ # File uploader - if a file is uploaded, save it in session_state
166
+ st.subheader("🖼️ Step 1: Upload Your Picture!")
167
+ st.markdown("""
168
+ - Click on the "Upload Image" button to select the image you want to feature on your holiday card. Make sure it's a **JPG** or **PNG** file.
169
+ - Once uploaded, your image will appear on the screen—easy peasy!
170
+ """)
171
+ uploaded_file = st.file_uploader("Upload an image", type=["png", "jpg", "jpeg"])
172
+ if uploaded_file is not None:
173
+ st.session_state.uploaded_file = uploaded_file # Save to session state
174
+ st.divider()
175
+
176
+ # Load the image from session state if it exists
177
+ if st.session_state.uploaded_file is not None:
178
+ try:
179
+ original_image = Image.open(st.session_state.uploaded_file)
180
+ st.subheader("Your uploaded image")
181
+ st.image(original_image, caption="Uploaded Image", use_column_width=True)
182
+
183
+ img_width, img_height = original_image.size
184
+ st.divider()
185
+
186
+ st.subheader("✂️ Step 2: Crop It Like It's Hot!")
187
+ st.markdown("""
188
+ - Adjust the **crop** sliders to select the perfect area of your image. This cropped section will be the centerpiece of your festive card. 🎨
189
+ - A preview will show you exactly how your crop looks before moving to the next step!
190
+ """)
191
+ col1, col2 = st.columns(2)
192
+ with col1:
193
+ x_pos = st.slider("X position (Left-Right)", 0, img_width, img_width // 4,
194
+ help="Move the slider to adjust the crop's left-right position.")
195
+ crop_width = st.slider("Crop Width", 10, img_width - x_pos, min(img_width // 2, img_width - x_pos),
196
+ help="Adjust the width of the crop.")
197
+ with col2:
198
+ y_pos = st.slider("Y position (Up-Down)", 0, img_height, img_height // 4,
199
+ help="Move the slider to adjust the crop's up-down position.")
200
+ crop_height = st.slider("Crop Height", 10, img_height - y_pos, min(img_height // 2, img_height - y_pos),
201
+ help="Adjust the height of the crop.")
202
+
203
+ preview_image = draw_crop_preview(original_image.copy(), x_pos, y_pos, crop_width, crop_height)
204
+ st.image(preview_image, caption="Crop Preview", use_column_width=True)
205
+
206
+
207
+ # Holiday card prompt and parameters
208
+ st.divider()
209
+ holiday_prompts = [
210
+ "A border of Festive snowflakes and winter patterns for a holiday card border",
211
+ "A border of Joyful Christmas ornaments and lights decorating the edges",
212
+ "A border of Warm and cozy fireplace scene with stockings and garlands",
213
+ "A border of Colorful Hanukkah menorahs and dreidels along the border",
214
+ "A border of New Year's Eve fireworks with stars and confetti framing the image"
215
+ ]
216
+ st.subheader("⚙️ Step 3: Design Your Festive Border with Flux + Fireworks!")
217
+ st.markdown("""
218
+ - Choose from a selection of holiday-themed borders like **snowflakes**, **Christmas lights**, or even **New Year's Eve fireworks**—all generated through **Flux models on Fireworks!** ✨
219
+ - Want to get creative? No problem—enter your own **custom prompt** to create a border that's as unique as you are, all powered by **Fireworks' inference API**. """)
220
+ selected_prompt = st.selectbox("Choose a holiday-themed prompt or enter your own", options=["Custom"] + holiday_prompts)
221
+ custom_prompt = st.text_input("Enter your custom prompt") if selected_prompt == "Custom" else ""
222
+ prompt = custom_prompt if selected_prompt == "Custom" else selected_prompt
223
+
224
+ with st.expander("Advanced Parameters"):
225
+ control_mode = st.slider("Control Mode", min_value=0, max_value=2, value=0)
226
+ controlnet_conditioning_scale = st.slider("ControlNet Conditioning Scale", min_value=0.0, max_value=1.0, value=0.5, step=0.1)
227
+ guidance_scale = st.slider("Guidance Scale", min_value=0.0, max_value=20.0, value=3.5, step=0.1)
228
+ num_inference_steps = st.slider("Number of Inference Steps", min_value=1, max_value=100, value=30, step=1)
229
+ seed = st.slider("Random Seed", min_value=0, max_value=1000, value=0)
230
+
231
+ if st.button("Generate Holiday Card"):
232
+ if not prompt.strip():
233
+ st.error("Please enter a prompt.")
234
+ else:
235
+ with st.spinner("Processing..."):
236
+ generated_image, processed_image, _ = call_control_net_api(
237
+ st.session_state.uploaded_file, prompt, control_mode=control_mode,
238
+ guidance_scale=guidance_scale, num_inference_steps=num_inference_steps,
239
+ seed=seed, controlnet_conditioning_scale=controlnet_conditioning_scale
240
+ )
241
+
242
+ if generated_image is not None:
243
+ # Resize generated_image to match original_image size
244
+ generated_image = generated_image.resize(original_image.size)
245
+
246
+ # Create a copy of the generated image
247
+ final_image = generated_image.copy()
248
+
249
+ # Crop the selected portion of the original image
250
+ cropped_original = original_image.crop((x_pos, y_pos, x_pos + crop_width, y_pos + crop_height))
251
+
252
+ # Get the size of the cropped image
253
+ cropped_width, cropped_height = cropped_original.size
254
+
255
+ # Calculate the center of the generated image
256
+ center_x = (final_image.width - cropped_width) // 2
257
+ center_y = (final_image.height - cropped_height) // 2
258
+
259
+ # Paste the cropped portion of the original image onto the generated image at the calculated center
260
+ final_image.paste(cropped_original, (center_x, center_y))
261
+
262
+ # Save the generated image in session state for persistence
263
+ st.session_state.generated_image = final_image
264
+
265
+ # Save the image locally
266
+ final_image.save(f"{GENERATED_IMAGES_DIR}/holiday_card.png")
267
+
268
+ # Display the final holiday card
269
+ st.image(final_image, caption="Final Holiday Card", use_column_width=True)
270
+ else:
271
+ st.error("Failed to generate holiday card. Please try again.")
272
+
273
+ # Add a text box to input a custom message (limit to 280 characters like a tweet)
274
+ st.divider()
275
+ if 'generated_image' in st.session_state:
276
+ st.subheader("✏️ Step 4: Add Your Custom Holiday Message!")
277
+ st.markdown("""
278
+ - Add a fun, heartfelt, or witty holiday message to the bottom of your card. 🎉
279
+ - Choose from a variety of **festive fonts** and adjust the **font size** to make your message stand out! 🎅 """)
280
+
281
+ # Text input for custom message
282
+ custom_message = st.text_input("Add a custom holiday message to the card (max 280 characters)", max_chars=280)
283
+
284
+ # Font selection dropdown
285
+ selected_font = st.selectbox("Choose a font for your message", options=list(fonts.keys()))
286
+
287
+ # Slider to allow the user to adjust the font size
288
+ font_size = st.slider("Adjust font size", min_value=10, max_value=200, value=100, step=10)
289
+
290
+ # Get the corresponding font path
291
+ font_path = fonts[selected_font]
292
+
293
+ if st.button("Generate Holiday Card with Message"):
294
+ final_image_with_message = st.session_state.generated_image.copy()
295
+
296
+ # Get the dimensions of the cropped image and final image
297
+ cropped_bottom_y = y_pos + crop_height # y_pos is the top Y position of the cropped area
298
+
299
+ # Add the custom message to the image
300
+ if custom_message:
301
+ final_image_with_message = add_message_to_image(final_image_with_message, cropped_bottom_y, custom_message, font_path, font_size)
302
+
303
+ # Display the final holiday card with the message
304
+ st.image(final_image_with_message, caption="Holiday Card with Custom Message", use_column_width=True)
305
+
306
+ # Save image for download
307
+ img_byte_arr = BytesIO()
308
+ final_image_with_message.save(img_byte_arr, format="PNG")
309
+ img_byte_arr.seek(0)
310
+
311
+ # Download button for the final image
312
+ st.divider()
313
+ st.subheader("📥 Step 5: Download & Share Your Masterpiece!")
314
+ st.markdown("""
315
+ - Once you're happy with your card, simply hit the download button to save your card and message as a PNG image.
316
+ - You can also view and download any **previously generated holiday cards** from this session!""")
317
+ st.download_button(
318
+ label="Download Holiday Card with Message",
319
+ data=img_byte_arr,
320
+ file_name="holiday_card_with_message.png",
321
+ mime="image/png"
322
+ )
323
+
324
+ # Save image locally
325
+ final_image_with_message.save(f"{GENERATED_IMAGES_DIR}/holiday_card_with_message.png", format="PNG")
326
+ except OSError:
327
+ st.error("The uploaded image seems to be truncated or corrupted. Please try with a different image.")
328
+ else:
329
+ st.warning("Please upload an image to get started.")
330
+
331
+ # Load and display previously generated images
332
+ st.divider()
333
+ st.subheader("Previously Generated Holiday Cards")
334
+
335
+ saved_image_path = f"{GENERATED_IMAGES_DIR}/holiday_card_with_message.png"
336
+ if os.path.exists(saved_image_path):
337
+ saved_image = Image.open(saved_image_path)
338
+ st.image(saved_image, caption="Previously Generated Holiday Card", use_column_width=True)
pages/3_Pure_FLUX_ImageGeneration.py DELETED
@@ -1,77 +0,0 @@
1
- import os
2
- import requests
3
- from dotenv import load_dotenv
4
- from PIL import Image
5
- from io import BytesIO
6
- import streamlit as st
7
-
8
- # Set page configuration
9
- st.set_page_config(page_title="FLUX Image Generation Tool", page_icon="🎇")
10
-
11
- # Correct the path to the .env file to reflect its location
12
- dotenv_path = os.path.join(os.path.dirname(__file__), '../env/.env')
13
-
14
- # Load environment variables from the .env file
15
- load_dotenv(dotenv_path, override=True)
16
-
17
- # Get the Fireworks API key from the .env file
18
- fireworks_api_key = os.getenv("FIREWORKS_API_KEY")
19
-
20
- if not fireworks_api_key:
21
- st.error("API key not found. Make sure FIREWORKS_API_KEY is set in the .env file.")
22
-
23
- # Function to make requests to the FLUX models
24
- def generate_flux_image(model_path, prompt, steps):
25
- url = f"https://api.fireworks.ai/inference/v1/workflows/accounts/fireworks/models/{model_path}/text_to_image"
26
- headers = {
27
- "Authorization": f"Bearer {fireworks_api_key}",
28
- "Content-Type": "application/json",
29
- "Accept": "image/jpeg"
30
- }
31
- data = {
32
- "prompt": prompt,
33
- "aspect_ratio": "16:9",
34
- "guidance_scale": 3.5,
35
- "num_inference_steps": steps,
36
- "seed": 0
37
- }
38
-
39
- # Send the request
40
- response = requests.post(url, headers=headers, json=data)
41
-
42
- if response.status_code == 200:
43
- # Convert the response to an image
44
- img_data = response.content
45
- img = Image.open(BytesIO(img_data))
46
- return img
47
- else:
48
- raise RuntimeError(f"Error with FLUX model {model_path}: {response.text}")
49
-
50
- # Streamlit UI
51
- st.title("FLUX Image Generation")
52
- st.write("Generate images using the FLUX models.")
53
-
54
- # User input for the prompt
55
- prompt = st.text_input("Enter your prompt for image generation:")
56
-
57
- # Dropdown to select the model
58
- model_choice = st.selectbox("Select the model:", ["flux-1-dev", "flux-1-schnell"])
59
-
60
- # Button to generate images
61
- if st.button("Generate Image"):
62
- if not prompt.strip():
63
- st.error("Please provide a prompt.")
64
- else:
65
- try:
66
- with st.spinner("Generating image..."):
67
- # Determine steps based on model
68
- steps = 30 if model_choice == "flux-1-dev" else 4
69
-
70
- # Generate image
71
- generated_image = generate_flux_image(model_choice, prompt, steps)
72
-
73
- # Display the image
74
- st.image(generated_image, caption=f"Generated using {model_choice}", use_column_width=True)
75
-
76
- except Exception as e:
77
- st.error(f"An error occurred: {e}")