Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,144 +1,414 @@
|
|
| 1 |
import streamlit as st
|
| 2 |
-
from PIL import Image
|
| 3 |
-
from io import BytesIO
|
| 4 |
import requests
|
|
|
|
|
|
|
| 5 |
import base64
|
|
|
|
|
|
|
| 6 |
import time
|
| 7 |
-
from datetime import datetime
|
| 8 |
-
import re
|
| 9 |
|
| 10 |
-
#
|
| 11 |
st.set_page_config(
|
| 12 |
-
page_title="
|
| 13 |
-
page_icon="
|
| 14 |
layout="wide",
|
| 15 |
-
initial_sidebar_state="
|
| 16 |
-
)
|
| 17 |
-
|
| 18 |
-
# --- Global CSS for consistent fonts & spacing ---
|
| 19 |
-
st.markdown(
|
| 20 |
-
"""
|
| 21 |
-
<style>
|
| 22 |
-
body, .stApp { font-family: 'Helvetica Neue', Arial, sans-serif !important; }
|
| 23 |
-
h1, h2, h3, h4, h5, h6 { font-family: inherit !important; font-weight: 600 !important; }
|
| 24 |
-
pre, code { font-family: 'Courier New', monospace !important; white-space: pre-wrap !important; word-break: break-word !important; }
|
| 25 |
-
.stMarkdown ul > li { margin-bottom: 0.5rem; line-height: 1.4; }
|
| 26 |
-
</style>
|
| 27 |
-
""",
|
| 28 |
-
unsafe_allow_html=True
|
| 29 |
)
|
| 30 |
|
| 31 |
-
#
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
-
#
|
| 60 |
-
def
|
| 61 |
-
if not api_key:
|
| 62 |
-
return "Error: API key is required."
|
| 63 |
headers = {
|
| 64 |
-
"
|
| 65 |
-
"
|
| 66 |
}
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
"messages": [
|
| 80 |
-
{"role": "system", "content":
|
| 81 |
-
{"role": "user", "content":
|
| 82 |
],
|
| 83 |
-
"max_tokens":
|
| 84 |
}
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
if not
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
|
| 99 |
-
#
|
| 100 |
-
st.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
-
#
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
)
|
| 107 |
-
|
| 108 |
-
"Selling timeframe", ["Within 1 month", "1–3 months", "3–6 months", "6–12 months", ">12 months"]
|
| 109 |
-
)
|
| 110 |
-
budget = st.sidebar.slider("Max improvement budget ($)", 1000, 50000, 10000, 1000)
|
| 111 |
-
focus = st.sidebar.multiselect(
|
| 112 |
-
"Focus areas",
|
| 113 |
-
["Curb appeal", "Kitchen", "Bathroom", "Living Spaces", "Outdoor", "Storage"],
|
| 114 |
-
default=["Kitchen", "Bathroom"]
|
| 115 |
-
)
|
| 116 |
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 122 |
else:
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
f"
|
| 139 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
)
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
|
|
|
|
|
|
| 2 |
import requests
|
| 3 |
+
import os
|
| 4 |
+
import json
|
| 5 |
import base64
|
| 6 |
+
from io import BytesIO
|
| 7 |
+
from PIL import Image
|
| 8 |
import time
|
|
|
|
|
|
|
| 9 |
|
| 10 |
+
# Set page config
|
| 11 |
st.set_page_config(
|
| 12 |
+
page_title="Marketing Graphic Generator",
|
| 13 |
+
page_icon="🎨",
|
| 14 |
layout="wide",
|
| 15 |
+
initial_sidebar_state="expanded"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
)
|
| 17 |
|
| 18 |
+
# Custom CSS
|
| 19 |
+
st.markdown("""
|
| 20 |
+
<style>
|
| 21 |
+
.main .block-container {
|
| 22 |
+
padding-top: 2rem;
|
| 23 |
+
padding-bottom: 2rem;
|
| 24 |
+
}
|
| 25 |
+
.stApp {
|
| 26 |
+
background-color: #f8f9fa;
|
| 27 |
+
}
|
| 28 |
+
.title-area {
|
| 29 |
+
text-align: center;
|
| 30 |
+
margin-bottom: 2rem;
|
| 31 |
+
}
|
| 32 |
+
.custom-subheader {
|
| 33 |
+
background-color: #f0f2f6;
|
| 34 |
+
padding: 10px;
|
| 35 |
+
border-radius: 5px;
|
| 36 |
+
margin-bottom: 10px;
|
| 37 |
+
font-weight: 600;
|
| 38 |
+
}
|
| 39 |
+
.generated-image {
|
| 40 |
+
border: 1px solid #ddd;
|
| 41 |
+
border-radius: 5px;
|
| 42 |
+
padding: 10px;
|
| 43 |
+
background-color: white;
|
| 44 |
+
}
|
| 45 |
+
.stButton button {
|
| 46 |
+
width: 100%;
|
| 47 |
+
}
|
| 48 |
+
.footnote {
|
| 49 |
+
font-size: 0.8rem;
|
| 50 |
+
color: #6c757d;
|
| 51 |
+
margin-top: 2rem;
|
| 52 |
+
}
|
| 53 |
+
</style>
|
| 54 |
+
""", unsafe_allow_html=True)
|
| 55 |
|
| 56 |
+
# Title and description
|
| 57 |
+
st.markdown("""
|
| 58 |
+
<div class="title-area">
|
| 59 |
+
<h1>Marketing Graphic Generator 🎨</h1>
|
| 60 |
+
<p>Create professional marketing and advertising graphics using AI. Customize text, colors, and style for your business.</p>
|
| 61 |
+
</div>
|
| 62 |
+
""", unsafe_allow_html=True)
|
| 63 |
|
| 64 |
+
# Initialize session state
|
| 65 |
+
if "api_key" not in st.session_state:
|
| 66 |
+
st.session_state["api_key"] = ""
|
| 67 |
+
if "generated_image" not in st.session_state:
|
| 68 |
+
st.session_state["generated_image"] = None
|
| 69 |
+
if "prompt_history" not in st.session_state:
|
| 70 |
+
st.session_state["prompt_history"] = []
|
| 71 |
+
if "image_history" not in st.session_state:
|
| 72 |
+
st.session_state["image_history"] = []
|
| 73 |
|
| 74 |
+
# Functions
|
| 75 |
+
def generate_image_from_prompt(prompt, api_key, model="gpt-4o"):
|
|
|
|
|
|
|
| 76 |
headers = {
|
| 77 |
+
"Content-Type": "application/json",
|
| 78 |
+
"Authorization": f"Bearer {api_key}"
|
| 79 |
}
|
| 80 |
+
|
| 81 |
+
# Create a system message directing the model to create high-quality marketing graphics
|
| 82 |
+
system_message = """You are an expert graphic designer specialized in creating marketing and advertising materials.
|
| 83 |
+
Create high-quality, professional marketing graphics based on the user's specifications.
|
| 84 |
+
Pay careful attention to font choices, color schemes, layout, and branding elements.
|
| 85 |
+
Ensure text is readable and properly positioned.
|
| 86 |
+
Create images with proper aspect ratios and compositions that would work well for marketing purposes."""
|
| 87 |
+
|
| 88 |
+
# Enhance the user's prompt with specific guidance for marketing images
|
| 89 |
+
enhanced_prompt = f"""Create a professional marketing or advertising graphic with the following specifications:
|
| 90 |
+
|
| 91 |
+
{prompt}
|
| 92 |
+
|
| 93 |
+
Make sure the image has:
|
| 94 |
+
1. High visual appeal suitable for marketing purposes
|
| 95 |
+
2. Clear, readable text with proper spacing and alignment
|
| 96 |
+
3. Professional design elements and composition
|
| 97 |
+
4. Appropriate color harmony and contrast
|
| 98 |
+
5. Balanced layout with focal points that draw attention
|
| 99 |
+
|
| 100 |
+
The image should look like it was created by a professional graphic designer and be ready to use for marketing campaigns.
|
| 101 |
+
"""
|
| 102 |
+
|
| 103 |
+
data = {
|
| 104 |
+
"model": model,
|
| 105 |
"messages": [
|
| 106 |
+
{"role": "system", "content": system_message},
|
| 107 |
+
{"role": "user", "content": enhanced_prompt}
|
| 108 |
],
|
| 109 |
+
"max_tokens": 4096
|
| 110 |
}
|
| 111 |
+
|
| 112 |
+
try:
|
| 113 |
+
response = requests.post(
|
| 114 |
+
"https://api.openai.com/v1/chat/completions",
|
| 115 |
+
headers=headers,
|
| 116 |
+
json=data
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
if response.status_code == 200:
|
| 120 |
+
response_data = response.json()
|
| 121 |
+
content = response_data["choices"][0]["message"]["content"]
|
| 122 |
+
|
| 123 |
+
# Extract image URL if present
|
| 124 |
+
if "[1].split(")")[0]
|
| 126 |
+
if image_url.startswith("https://"):
|
| 127 |
+
return {"success": True, "image_url": image_url, "message": "Image generated successfully!"}
|
| 128 |
+
|
| 129 |
+
# If using the newer image generation where the image is embedded in the response
|
| 130 |
+
if "image_url" in content or "data:image" in content:
|
| 131 |
+
# For newer versions where image content might be directly embedded
|
| 132 |
+
image_matches = re.findall(r'(https://[^\s]+\.(?:png|jpg|jpeg|gif))', content)
|
| 133 |
+
if image_matches:
|
| 134 |
+
return {"success": True, "image_url": image_matches[0], "message": "Image generated successfully!"}
|
| 135 |
+
elif "data:image" in content:
|
| 136 |
+
# Handle base64 encoded image if present
|
| 137 |
+
base64_match = re.search(r'data:image/[^;]+;base64,([^"]+)', content)
|
| 138 |
+
if base64_match:
|
| 139 |
+
base64_data = base64_match.group(1)
|
| 140 |
+
return {"success": True, "image_data": base64_data, "message": "Image generated successfully!"}
|
| 141 |
+
|
| 142 |
+
return {"success": False, "message": "Could not extract image from response. The model may need additional prompting."}
|
| 143 |
+
|
| 144 |
+
else:
|
| 145 |
+
error_message = f"API Error: {response.status_code}"
|
| 146 |
+
if response.text:
|
| 147 |
+
try:
|
| 148 |
+
error_json = response.json()
|
| 149 |
+
if "error" in error_json:
|
| 150 |
+
error_message += f" - {error_json['error']['message']}"
|
| 151 |
+
except:
|
| 152 |
+
error_message += f" - {response.text[:200]}"
|
| 153 |
+
return {"success": False, "message": error_message}
|
| 154 |
+
except Exception as e:
|
| 155 |
+
return {"success": False, "message": f"Error: {str(e)}"}
|
| 156 |
|
| 157 |
+
def save_image(image_data):
|
| 158 |
+
# Create directory if it doesn't exist
|
| 159 |
+
if not os.path.exists("generated_images"):
|
| 160 |
+
os.makedirs("generated_images")
|
| 161 |
+
|
| 162 |
+
# Generate a unique filename
|
| 163 |
+
timestamp = int(time.time())
|
| 164 |
+
filename = f"generated_images/marketing_graphic_{timestamp}.png"
|
| 165 |
+
|
| 166 |
+
# Save the image
|
| 167 |
+
image_data.save(filename)
|
| 168 |
+
|
| 169 |
+
return filename
|
| 170 |
|
| 171 |
+
# Sidebar - Configuration
|
| 172 |
+
with st.sidebar:
|
| 173 |
+
st.markdown('<div class="custom-subheader">API Configuration</div>', unsafe_allow_html=True)
|
| 174 |
+
|
| 175 |
+
api_key = st.text_input(
|
| 176 |
+
"Enter your OpenAI API Key",
|
| 177 |
+
value=st.session_state["api_key"],
|
| 178 |
+
type="password",
|
| 179 |
+
help="Your API key is required to generate images. It will not be stored permanently."
|
| 180 |
+
)
|
| 181 |
+
st.session_state["api_key"] = api_key
|
| 182 |
+
|
| 183 |
+
# Display a warning if no API key is provided
|
| 184 |
+
if not api_key:
|
| 185 |
+
st.warning("⚠️ Please enter your OpenAI API key to use this tool")
|
| 186 |
+
|
| 187 |
+
st.markdown('<div class="custom-subheader">Advanced Settings</div>', unsafe_allow_html=True)
|
| 188 |
+
|
| 189 |
+
# Image quality and size settings
|
| 190 |
+
image_quality = st.select_slider(
|
| 191 |
+
"Image Quality",
|
| 192 |
+
options=["Standard", "High", "Maximum"],
|
| 193 |
+
value="High"
|
| 194 |
+
)
|
| 195 |
+
|
| 196 |
+
aspect_ratio = st.selectbox(
|
| 197 |
+
"Aspect Ratio",
|
| 198 |
+
["Square (1:1)", "Landscape (16:9)", "Portrait (9:16)", "Facebook (1200x628)", "Instagram (1080x1080)", "Twitter (1200x675)"],
|
| 199 |
+
index=0
|
| 200 |
+
)
|
| 201 |
|
| 202 |
+
# History
|
| 203 |
+
if st.session_state["prompt_history"]:
|
| 204 |
+
st.markdown('<div class="custom-subheader">Prompt History</div>', unsafe_allow_html=True)
|
| 205 |
+
for i, prompt in enumerate(st.session_state["prompt_history"][-5:]):
|
| 206 |
+
if st.button(f"Reuse: {prompt[:30]}...", key=f"history_{i}"):
|
| 207 |
+
st.session_state["current_prompt"] = prompt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
|
| 209 |
+
# Main content
|
| 210 |
+
col1, col2 = st.columns([1, 1])
|
| 211 |
+
|
| 212 |
+
with col1:
|
| 213 |
+
st.markdown('<div class="custom-subheader">Design Specifications</div>', unsafe_allow_html=True)
|
| 214 |
+
|
| 215 |
+
# Business Information
|
| 216 |
+
business_name = st.text_input("Business Name", placeholder="e.g., Sunset Cafe")
|
| 217 |
+
business_type = st.text_input("Business Type/Industry", placeholder="e.g., Coffee Shop, Real Estate, Fitness Studio")
|
| 218 |
+
location = st.text_input("Location (City/Region)", placeholder="e.g., San Francisco, CA")
|
| 219 |
+
|
| 220 |
+
# Marketing Content
|
| 221 |
+
st.markdown("##### Marketing Content")
|
| 222 |
+
|
| 223 |
+
marketing_purpose = st.selectbox(
|
| 224 |
+
"Purpose of Graphic",
|
| 225 |
+
["Advertisement", "Social Media Post", "Flyer", "Banner", "Logo", "Business Card", "Email Header", "Website Hero Image", "Promotional Offer"],
|
| 226 |
+
index=0
|
| 227 |
+
)
|
| 228 |
+
|
| 229 |
+
headline = st.text_input("Headline/Main Text", placeholder="e.g., Grand Opening! 50% Off All Drinks")
|
| 230 |
+
subheading = st.text_input("Subheading/Secondary Text", placeholder="e.g., This weekend only - May 15-17")
|
| 231 |
+
call_to_action = st.text_input("Call to Action", placeholder="e.g., Visit us today! Call 555-123-4567")
|
| 232 |
+
|
| 233 |
+
# Visual Style
|
| 234 |
+
st.markdown("##### Visual Style")
|
| 235 |
+
|
| 236 |
+
color_scheme = st.text_input("Color Scheme", placeholder="e.g., Blue and gold, #FF5733 and #33FF57, Corporate colors")
|
| 237 |
+
font_style = st.text_input("Font Style", placeholder="e.g., Modern sans-serif, Elegant serif, Playful handwritten")
|
| 238 |
+
image_style = st.text_input("Image Style/Mood", placeholder="e.g., Minimalist, Vibrant, Professional, Vintage")
|
| 239 |
+
|
| 240 |
+
# Additional Elements
|
| 241 |
+
st.markdown("##### Additional Elements")
|
| 242 |
+
|
| 243 |
+
visual_elements = st.text_area(
|
| 244 |
+
"Specific Visual Elements to Include",
|
| 245 |
+
placeholder="e.g., Coffee cup with steam, Mountain backdrop, Product showcase, People enjoying the service",
|
| 246 |
+
height=100
|
| 247 |
+
)
|
| 248 |
+
|
| 249 |
+
special_instructions = st.text_area(
|
| 250 |
+
"Special Instructions",
|
| 251 |
+
placeholder="Any additional details or specific requirements for the design",
|
| 252 |
+
height=100
|
| 253 |
+
)
|
| 254 |
+
|
| 255 |
+
# Build the prompt
|
| 256 |
+
if "current_prompt" in st.session_state:
|
| 257 |
+
complete_prompt = st.session_state["current_prompt"]
|
| 258 |
+
del st.session_state["current_prompt"]
|
| 259 |
else:
|
| 260 |
+
prompt_parts = []
|
| 261 |
+
|
| 262 |
+
# Add business information
|
| 263 |
+
if business_name:
|
| 264 |
+
prompt_parts.append(f"Business Name: {business_name}")
|
| 265 |
+
if business_type:
|
| 266 |
+
prompt_parts.append(f"Business Type: {business_type}")
|
| 267 |
+
if location:
|
| 268 |
+
prompt_parts.append(f"Location: {location}")
|
| 269 |
+
|
| 270 |
+
# Add marketing content
|
| 271 |
+
prompt_parts.append(f"Create a {marketing_purpose.lower()}")
|
| 272 |
+
if headline:
|
| 273 |
+
prompt_parts.append(f"Headline: '{headline}'")
|
| 274 |
+
if subheading:
|
| 275 |
+
prompt_parts.append(f"Subheading: '{subheading}'")
|
| 276 |
+
if call_to_action:
|
| 277 |
+
prompt_parts.append(f"Call to Action: '{call_to_action}'")
|
| 278 |
+
|
| 279 |
+
# Add visual style
|
| 280 |
+
if color_scheme:
|
| 281 |
+
prompt_parts.append(f"Color Scheme: {color_scheme}")
|
| 282 |
+
if font_style:
|
| 283 |
+
prompt_parts.append(f"Font Style: {font_style}")
|
| 284 |
+
if image_style:
|
| 285 |
+
prompt_parts.append(f"Visual Style: {image_style}")
|
| 286 |
+
|
| 287 |
+
# Add aspect ratio
|
| 288 |
+
if "Square" in aspect_ratio:
|
| 289 |
+
prompt_parts.append("Create a square (1:1) image")
|
| 290 |
+
elif "Landscape" in aspect_ratio:
|
| 291 |
+
prompt_parts.append("Create a landscape (16:9) format image")
|
| 292 |
+
elif "Portrait" in aspect_ratio:
|
| 293 |
+
prompt_parts.append("Create a portrait (9:16) format image")
|
| 294 |
+
elif "Facebook" in aspect_ratio:
|
| 295 |
+
prompt_parts.append("Create an image in Facebook post dimensions (1200x628)")
|
| 296 |
+
elif "Instagram" in aspect_ratio:
|
| 297 |
+
prompt_parts.append("Create an image in Instagram post dimensions (1080x1080)")
|
| 298 |
+
elif "Twitter" in aspect_ratio:
|
| 299 |
+
prompt_parts.append("Create an image in Twitter post dimensions (1200x675)")
|
| 300 |
+
|
| 301 |
+
# Add image quality
|
| 302 |
+
prompt_parts.append(f"Generate a {image_quality.lower()} quality image")
|
| 303 |
+
|
| 304 |
+
# Add additional elements
|
| 305 |
+
if visual_elements:
|
| 306 |
+
prompt_parts.append(f"Include these visual elements: {visual_elements}")
|
| 307 |
+
if special_instructions:
|
| 308 |
+
prompt_parts.append(f"Special instructions: {special_instructions}")
|
| 309 |
+
|
| 310 |
+
prompt_parts.append("Make text clear, readable, and properly positioned. Ensure professional design suitable for marketing purposes.")
|
| 311 |
+
|
| 312 |
+
complete_prompt = ". ".join(prompt_parts)
|
| 313 |
+
|
| 314 |
+
# Display the complete prompt with ability to edit
|
| 315 |
+
final_prompt = st.text_area(
|
| 316 |
+
"Complete Prompt (Edit as needed)",
|
| 317 |
+
value=complete_prompt,
|
| 318 |
+
height=150
|
| 319 |
+
)
|
| 320 |
+
|
| 321 |
+
# Generate button
|
| 322 |
+
generate_button = st.button(
|
| 323 |
+
"🎨 Generate Marketing Graphic",
|
| 324 |
+
disabled=not api_key,
|
| 325 |
+
use_container_width=True
|
| 326 |
+
)
|
| 327 |
+
|
| 328 |
+
if generate_button:
|
| 329 |
+
with st.spinner("Generating your marketing graphic... This may take up to 60 seconds"):
|
| 330 |
+
# Save the prompt to history
|
| 331 |
+
if final_prompt not in st.session_state["prompt_history"]:
|
| 332 |
+
st.session_state["prompt_history"].insert(0, final_prompt)
|
| 333 |
+
# Keep only the last 10 prompts
|
| 334 |
+
st.session_state["prompt_history"] = st.session_state["prompt_history"][:10]
|
| 335 |
+
|
| 336 |
+
# Call API to generate image
|
| 337 |
+
result = generate_image_from_prompt(final_prompt, api_key)
|
| 338 |
+
|
| 339 |
+
if result["success"]:
|
| 340 |
+
# Handle image URL or base64 data
|
| 341 |
+
if "image_url" in result:
|
| 342 |
+
try:
|
| 343 |
+
response = requests.get(result["image_url"])
|
| 344 |
+
img = Image.open(BytesIO(response.content))
|
| 345 |
+
st.session_state["generated_image"] = img
|
| 346 |
+
except Exception as e:
|
| 347 |
+
st.error(f"Error loading image: {str(e)}")
|
| 348 |
+
elif "image_data" in result:
|
| 349 |
+
try:
|
| 350 |
+
img_data = base64.b64decode(result["image_data"])
|
| 351 |
+
img = Image.open(BytesIO(img_data))
|
| 352 |
+
st.session_state["generated_image"] = img
|
| 353 |
+
except Exception as e:
|
| 354 |
+
st.error(f"Error decoding image: {str(e)}")
|
| 355 |
+
else:
|
| 356 |
+
st.error(result["message"])
|
| 357 |
+
if "API key" in result["message"]:
|
| 358 |
+
st.warning("Please check that your API key is valid and has access to the GPT-4o model")
|
| 359 |
+
|
| 360 |
+
# Display generated image
|
| 361 |
+
with col2:
|
| 362 |
+
st.markdown('<div class="custom-subheader">Generated Marketing Graphic</div>', unsafe_allow_html=True)
|
| 363 |
+
|
| 364 |
+
if st.session_state["generated_image"] is not None:
|
| 365 |
+
st.markdown('<div class="generated-image">', unsafe_allow_html=True)
|
| 366 |
+
st.image(st.session_state["generated_image"], use_column_width=True)
|
| 367 |
+
st.markdown('</div>', unsafe_allow_html=True)
|
| 368 |
+
|
| 369 |
+
# Download button
|
| 370 |
+
img_buffer = BytesIO()
|
| 371 |
+
st.session_state["generated_image"].save(img_buffer, format="PNG")
|
| 372 |
+
img_bytes = img_buffer.getvalue()
|
| 373 |
+
|
| 374 |
+
st.download_button(
|
| 375 |
+
label="💾 Download Image",
|
| 376 |
+
data=img_bytes,
|
| 377 |
+
file_name=f"marketing_graphic_{int(time.time())}.png",
|
| 378 |
+
mime="image/png",
|
| 379 |
+
use_container_width=True
|
| 380 |
)
|
| 381 |
+
|
| 382 |
+
# Regenerate button
|
| 383 |
+
if st.button("🔄 Regenerate with Same Prompt", use_container_width=True):
|
| 384 |
+
with st.spinner("Regenerating image... This may take up to 60 seconds"):
|
| 385 |
+
result = generate_image_from_prompt(final_prompt, api_key)
|
| 386 |
+
|
| 387 |
+
if result["success"]:
|
| 388 |
+
if "image_url" in result:
|
| 389 |
+
try:
|
| 390 |
+
response = requests.get(result["image_url"])
|
| 391 |
+
img = Image.open(BytesIO(response.content))
|
| 392 |
+
st.session_state["generated_image"] = img
|
| 393 |
+
except Exception as e:
|
| 394 |
+
st.error(f"Error loading image: {str(e)}")
|
| 395 |
+
elif "image_data" in result:
|
| 396 |
+
try:
|
| 397 |
+
img_data = base64.b64decode(result["image_data"])
|
| 398 |
+
img = Image.open(BytesIO(img_data))
|
| 399 |
+
st.session_state["generated_image"] = img
|
| 400 |
+
except Exception as e:
|
| 401 |
+
st.error(f"Error decoding image: {str(e)}")
|
| 402 |
+
else:
|
| 403 |
+
st.error(result["message"])
|
| 404 |
+
else:
|
| 405 |
+
st.info("Your generated marketing graphic will appear here. Fill in the form and click 'Generate Marketing Graphic' to create your image.")
|
| 406 |
+
st.image("https://via.placeholder.com/800x800.png?text=Marketing+Graphic+Preview", use_column_width=True)
|
| 407 |
+
|
| 408 |
+
# Footer with disclaimer
|
| 409 |
+
st.markdown("""
|
| 410 |
+
<div class="footnote">
|
| 411 |
+
<p><strong>Disclaimer:</strong> This tool uses OpenAI's 4o Image Generation to create marketing graphics. The quality and accuracy of the generated images depend on the model's capabilities and your prompt. For professional marketing materials, consider reviewing and refining the generated images with a graphic designer.</p>
|
| 412 |
+
<p>Images generated using this tool comply with OpenAI's usage policies. You are responsible for ensuring that your use of the generated images complies with applicable laws and regulations.</p>
|
| 413 |
+
</div>
|
| 414 |
+
""", unsafe_allow_html=True)
|