shaheerawan3 commited on
Commit
79b8cf7
Β·
verified Β·
1 Parent(s): 6376f8a

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +558 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,560 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import json
3
+ import requests
4
+ from PIL import Image
5
+ import io
6
+ import base64
7
+ from datetime import datetime
8
+ import time
9
 
10
+ # Page configuration
11
+ st.set_page_config(
12
+ page_title="AdForge AI - AI Advertisement Generator",
13
+ page_icon="🎨",
14
+ layout="wide",
15
+ initial_sidebar_state="expanded"
16
+ )
17
+
18
+ # Custom CSS for professional styling
19
+ st.markdown("""
20
+ <style>
21
+ .main-header {
22
+ font-size: 3rem;
23
+ font-weight: bold;
24
+ background: linear-gradient(120deg, #667eea 0%, #764ba2 100%);
25
+ -webkit-background-clip: text;
26
+ -webkit-text-fill-color: transparent;
27
+ text-align: center;
28
+ padding: 1rem 0;
29
+ }
30
+ .sub-header {
31
+ text-align: center;
32
+ color: #666;
33
+ font-size: 1.2rem;
34
+ margin-bottom: 2rem;
35
+ }
36
+ .stButton>button {
37
+ width: 100%;
38
+ background: linear-gradient(120deg, #667eea 0%, #764ba2 100%);
39
+ color: white;
40
+ border: none;
41
+ padding: 0.75rem 1.5rem;
42
+ font-size: 1.1rem;
43
+ font-weight: bold;
44
+ border-radius: 10px;
45
+ transition: all 0.3s;
46
+ }
47
+ .stButton>button:hover {
48
+ transform: translateY(-2px);
49
+ box-shadow: 0 10px 20px rgba(0,0,0,0.2);
50
+ }
51
+ .success-box {
52
+ padding: 1rem;
53
+ border-radius: 10px;
54
+ background: #d4edda;
55
+ border: 1px solid #c3e6cb;
56
+ color: #155724;
57
+ margin: 1rem 0;
58
+ }
59
+ .info-box {
60
+ padding: 1rem;
61
+ border-radius: 10px;
62
+ background: #d1ecf1;
63
+ border: 1px solid #bee5eb;
64
+ color: #0c5460;
65
+ margin: 1rem 0;
66
+ }
67
+ .feature-card {
68
+ padding: 1.5rem;
69
+ border-radius: 10px;
70
+ background: white;
71
+ box-shadow: 0 4px 6px rgba(0,0,0,0.1);
72
+ margin: 1rem 0;
73
+ }
74
+ </style>
75
+ """, unsafe_allow_html=True)
76
+
77
+ # Initialize session state
78
+ if 'generated_images' not in st.session_state:
79
+ st.session_state.generated_images = []
80
+ if 'generation_history' not in st.session_state:
81
+ st.session_state.generation_history = []
82
+ if 'api_token' not in st.session_state:
83
+ st.session_state.api_token = ""
84
+
85
+ # Helper Functions
86
+ def validate_json(json_string):
87
+ """Validate and parse JSON input"""
88
+ try:
89
+ data = json.loads(json_string)
90
+ return data, None
91
+ except json.JSONDecodeError as e:
92
+ return None, f"Invalid JSON format: {str(e)}"
93
+
94
+ def generate_advanced_prompt(ad_data):
95
+ """Generate sophisticated advertising prompt from JSON data"""
96
+ product = ad_data.get('product_name', 'product')
97
+ description = ad_data.get('description', '')
98
+ style = ad_data.get('style', 'professional')
99
+ mood = ad_data.get('mood', 'energetic')
100
+ target_audience = ad_data.get('target_audience', 'general audience')
101
+ colors = ad_data.get('colors', [])
102
+ setting = ad_data.get('setting', 'studio')
103
+ composition = ad_data.get('composition', 'centered')
104
+ lighting = ad_data.get('lighting', 'soft studio lighting')
105
+
106
+ # Build sophisticated prompt
107
+ prompt_parts = []
108
+
109
+ # Main subject
110
+ prompt_parts.append(f"Professional advertising photography of {product}")
111
+
112
+ if description:
113
+ prompt_parts.append(f"{description}")
114
+
115
+ # Style and mood
116
+ prompt_parts.append(f"{style} style, {mood} mood")
117
+
118
+ # Target audience context
119
+ if target_audience and target_audience != 'general audience':
120
+ prompt_parts.append(f"appealing to {target_audience}")
121
+
122
+ # Visual elements
123
+ if colors:
124
+ color_palette = ", ".join(colors)
125
+ prompt_parts.append(f"color palette: {color_palette}")
126
+
127
+ prompt_parts.append(f"{setting} setting")
128
+ prompt_parts.append(f"{composition} composition")
129
+ prompt_parts.append(f"{lighting}")
130
+
131
+ # Quality tags
132
+ quality_tags = [
133
+ "high-end commercial photography",
134
+ "8k resolution",
135
+ "sharp focus",
136
+ "professional color grading",
137
+ "dramatic lighting",
138
+ "photorealistic",
139
+ "award-winning advertisement"
140
+ ]
141
+
142
+ prompt = ", ".join(prompt_parts) + ", " + ", ".join(quality_tags)
143
+
144
+ return prompt
145
+
146
+ def generate_negative_prompt(ad_data):
147
+ """Generate negative prompt to avoid unwanted elements"""
148
+ base_negative = [
149
+ "low quality", "blurry", "distorted", "ugly", "amateur",
150
+ "poor composition", "bad lighting", "oversaturated",
151
+ "watermark", "text", "signature", "logo overlay",
152
+ "cropped", "out of frame", "deformed", "disfigured",
153
+ "extra limbs", "poorly rendered", "cartoon", "anime"
154
+ ]
155
+
156
+ # Add custom negative prompts if specified
157
+ if 'avoid' in ad_data and ad_data['avoid']:
158
+ base_negative.extend(ad_data['avoid'])
159
+
160
+ return ", ".join(base_negative)
161
+
162
+ def call_huggingface_api(prompt, negative_prompt, api_token):
163
+ """Call Hugging Face Inference API for FLUX.1-schnell"""
164
+ API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-schnell"
165
+
166
+ headers = {
167
+ "Authorization": f"Bearer {api_token}",
168
+ "Content-Type": "application/json"
169
+ }
170
+
171
+ payload = {
172
+ "inputs": prompt,
173
+ "parameters": {
174
+ "negative_prompt": negative_prompt,
175
+ "num_inference_steps": 4, # Schnell optimized for 1-4 steps
176
+ "guidance_scale": 0.0, # Schnell doesn't use guidance
177
+ "width": 1024,
178
+ "height": 1024
179
+ }
180
+ }
181
+
182
+ try:
183
+ response = requests.post(API_URL, headers=headers, json=payload, timeout=60)
184
+
185
+ if response.status_code == 200:
186
+ image = Image.open(io.BytesIO(response.content))
187
+ return image, None
188
+ elif response.status_code == 503:
189
+ return None, "Model is loading. Please wait 20 seconds and try again."
190
+ elif response.status_code == 401:
191
+ return None, "Invalid API token. Please check your Hugging Face token."
192
+ elif response.status_code == 402:
193
+ return None, "You've exceeded your free tier limit. Consider upgrading to PRO or wait for next month."
194
+ else:
195
+ error_msg = response.json().get('error', 'Unknown error')
196
+ return None, f"API Error ({response.status_code}): {error_msg}"
197
+
198
+ except requests.Timeout:
199
+ return None, "Request timed out. The model might be loading. Please try again."
200
+ except Exception as e:
201
+ return None, f"Error: {str(e)}"
202
+
203
+ def image_to_base64(image):
204
+ """Convert PIL Image to base64 string"""
205
+ buffered = io.BytesIO()
206
+ image.save(buffered, format="PNG")
207
+ return base64.b64encode(buffered.getvalue()).decode()
208
+
209
+ # Header
210
+ st.markdown('<h1 class="main-header">🎨 AdForge AI</h1>', unsafe_allow_html=True)
211
+ st.markdown('<p class="sub-header">Transform your concept into stunning advertisements with AI</p>', unsafe_allow_html=True)
212
+
213
+ # Sidebar Configuration
214
+ with st.sidebar:
215
+ st.header("βš™οΈ Configuration")
216
+
217
+ # API Token Input
218
+ st.subheader("πŸ”‘ Hugging Face API Token")
219
+ api_token_input = st.text_input(
220
+ "Enter your HF token",
221
+ type="password",
222
+ value=st.session_state.api_token,
223
+ help="Get your free token from https://huggingface.co/settings/tokens"
224
+ )
225
+
226
+ if api_token_input:
227
+ st.session_state.api_token = api_token_input
228
+ st.success("βœ… Token configured!")
229
+ else:
230
+ st.warning("⚠️ Please enter your Hugging Face API token to generate images")
231
+
232
+ st.markdown("---")
233
+
234
+ # Advanced Settings
235
+ st.subheader("πŸŽ›οΈ Generation Settings")
236
+
237
+ num_variations = st.slider(
238
+ "Number of Variations",
239
+ min_value=1,
240
+ max_value=4,
241
+ value=1,
242
+ help="Generate multiple variations of your ad"
243
+ )
244
+
245
+ image_size = st.selectbox(
246
+ "Image Resolution",
247
+ options=["1024x1024 (Square)", "1024x768 (Landscape)", "768x1024 (Portrait)"],
248
+ index=0
249
+ )
250
+
251
+ st.markdown("---")
252
+
253
+ # Model Info
254
+ st.subheader("ℹ️ About")
255
+ st.info("""
256
+ **Model:** FLUX.1-schnell
257
+ **Speed:** 2-5 seconds
258
+ **Quality:** Professional-grade
259
+ **License:** Apache 2.0
260
+
261
+ FLUX.1-schnell is optimized for rapid, high-quality image generation perfect for advertising.
262
+ """)
263
+
264
+ # Quick Guide
265
+ with st.expander("πŸ“– Quick Guide"):
266
+ st.markdown("""
267
+ **Steps to Generate:**
268
+ 1. Enter your HF API token above
269
+ 2. Fill in the JSON with your ad concept
270
+ 3. Click "Generate Advertisement"
271
+ 4. Download your results!
272
+
273
+ **Get API Token:**
274
+ 1. Visit [Hugging Face](https://huggingface.co)
275
+ 2. Sign up/Login
276
+ 3. Go to Settings β†’ Access Tokens
277
+ 4. Create new token with "Make calls to Inference API" permission
278
+ """)
279
+
280
+ # Main Content Area
281
+ col1, col2 = st.columns([1, 1], gap="large")
282
+
283
+ with col1:
284
+ st.subheader("πŸ“ Advertisement Concept (JSON)")
285
+
286
+ # Sample JSON templates
287
+ sample_templates = {
288
+ "Tech Product": {
289
+ "product_name": "AirPods Pro Max",
290
+ "description": "Premium wireless headphones with spatial audio and active noise cancellation",
291
+ "style": "minimalist and modern",
292
+ "mood": "sophisticated and premium",
293
+ "target_audience": "tech enthusiasts and professionals",
294
+ "colors": ["space gray", "silver", "white"],
295
+ "setting": "modern studio with gradient background",
296
+ "composition": "centered with dramatic angle",
297
+ "lighting": "soft key light with rim lighting",
298
+ "key_features": ["noise cancellation", "spatial audio", "premium build"]
299
+ },
300
+ "Food & Beverage": {
301
+ "product_name": "Artisan Cold Brew Coffee",
302
+ "description": "Smooth cold brew coffee with hints of chocolate and caramel",
303
+ "style": "rustic and organic",
304
+ "mood": "warm and inviting",
305
+ "target_audience": "coffee lovers and millennials",
306
+ "colors": ["rich brown", "cream", "amber"],
307
+ "setting": "wooden table with natural elements",
308
+ "composition": "rule of thirds with foreground elements",
309
+ "lighting": "natural morning light with soft shadows",
310
+ "key_features": ["organic", "small batch", "sustainably sourced"]
311
+ },
312
+ "Fashion": {
313
+ "product_name": "Summer Collection Dress",
314
+ "description": "Elegant flowing summer dress with floral patterns",
315
+ "style": "editorial fashion",
316
+ "mood": "elegant and breezy",
317
+ "target_audience": "fashion-forward women 25-40",
318
+ "colors": ["pastel pink", "soft white", "gold accents"],
319
+ "setting": "outdoor garden at golden hour",
320
+ "composition": "full body shot with movement",
321
+ "lighting": "golden hour backlight with fill",
322
+ "key_features": ["sustainable fabric", "handcrafted", "limited edition"]
323
+ },
324
+ "Automotive": {
325
+ "product_name": "Electric Sports Car",
326
+ "description": "Sleek electric vehicle with cutting-edge design and performance",
327
+ "style": "dynamic and futuristic",
328
+ "mood": "powerful and innovative",
329
+ "target_audience": "luxury car enthusiasts",
330
+ "colors": ["metallic blue", "chrome", "carbon black"],
331
+ "setting": "modern urban environment at night",
332
+ "composition": "low angle hero shot",
333
+ "lighting": "dramatic city lights with reflections",
334
+ "key_features": ["0-60 in 2.5s", "400 mile range", "autopilot"]
335
+ }
336
+ }
337
+
338
+ template_choice = st.selectbox(
339
+ "πŸ“‹ Choose a template or start from scratch",
340
+ options=["Custom"] + list(sample_templates.keys())
341
+ )
342
+
343
+ if template_choice != "Custom":
344
+ default_json = json.dumps(sample_templates[template_choice], indent=2)
345
+ else:
346
+ default_json = json.dumps({
347
+ "product_name": "",
348
+ "description": "",
349
+ "style": "professional",
350
+ "mood": "energetic",
351
+ "target_audience": "",
352
+ "colors": [],
353
+ "setting": "studio",
354
+ "composition": "centered",
355
+ "lighting": "soft studio lighting"
356
+ }, indent=2)
357
+
358
+ json_input = st.text_area(
359
+ "Paste or edit your advertisement concept:",
360
+ value=default_json,
361
+ height=400,
362
+ help="Provide details about your product and desired ad style"
363
+ )
364
+
365
+ # Generate Button
366
+ generate_btn = st.button(
367
+ "πŸš€ Generate Advertisement",
368
+ type="primary",
369
+ disabled=not st.session_state.api_token,
370
+ use_container_width=True
371
+ )
372
+
373
+ if generate_btn:
374
+ if not st.session_state.api_token:
375
+ st.error("❌ Please enter your Hugging Face API token in the sidebar first!")
376
+ else:
377
+ # Validate JSON
378
+ ad_data, error = validate_json(json_input)
379
+
380
+ if error:
381
+ st.error(f"❌ {error}")
382
+ else:
383
+ st.markdown('<div class="success-box">βœ… JSON validated successfully!</div>', unsafe_allow_html=True)
384
+
385
+ # Generate prompts
386
+ main_prompt = generate_advanced_prompt(ad_data)
387
+ negative_prompt = generate_negative_prompt(ad_data)
388
+
389
+ # Display prompts
390
+ with st.expander("πŸ” View Generated Prompts"):
391
+ st.write("**Positive Prompt:**")
392
+ st.code(main_prompt, language=None)
393
+ st.write("**Negative Prompt:**")
394
+ st.code(negative_prompt, language=None)
395
+
396
+ # Generate images
397
+ st.markdown('<div class="info-box">⏳ Generating your advertisement... This takes 5-10 seconds.</div>', unsafe_allow_html=True)
398
+
399
+ progress_bar = st.progress(0)
400
+ generated_images = []
401
+
402
+ for i in range(num_variations):
403
+ progress_bar.progress((i + 1) / num_variations)
404
+
405
+ with st.spinner(f"Creating variation {i+1}/{num_variations}..."):
406
+ image, error = call_huggingface_api(
407
+ main_prompt,
408
+ negative_prompt,
409
+ st.session_state.api_token
410
+ )
411
+
412
+ if error:
413
+ st.error(f"❌ Variation {i+1} failed: {error}")
414
+ if "loading" in error.lower():
415
+ st.info("πŸ’‘ Tip: The model is warming up. Wait 20 seconds and try again.")
416
+ break
417
+ else:
418
+ generated_images.append({
419
+ 'image': image,
420
+ 'prompt': main_prompt,
421
+ 'timestamp': datetime.now(),
422
+ 'ad_data': ad_data
423
+ })
424
+ time.sleep(1) # Small delay between requests
425
+
426
+ progress_bar.progress(1.0)
427
+
428
+ if generated_images:
429
+ st.session_state.generated_images = generated_images
430
+ st.session_state.generation_history.append({
431
+ 'timestamp': datetime.now(),
432
+ 'count': len(generated_images),
433
+ 'product': ad_data.get('product_name', 'Unknown')
434
+ })
435
+ st.success(f"✨ Successfully generated {len(generated_images)} advertisement(s)!")
436
+ st.balloons()
437
+
438
+ with col2:
439
+ st.subheader("πŸ–ΌοΈ Generated Advertisements")
440
+
441
+ if st.session_state.generated_images:
442
+ for idx, item in enumerate(st.session_state.generated_images):
443
+ st.image(
444
+ item['image'],
445
+ caption=f"Advertisement {idx + 1} - {item['ad_data'].get('product_name', 'Product')}",
446
+ use_container_width=True
447
+ )
448
+
449
+ # Download and info buttons
450
+ col_a, col_b = st.columns(2)
451
+
452
+ with col_a:
453
+ # Convert image to bytes for download
454
+ img_buffer = io.BytesIO()
455
+ item['image'].save(img_buffer, format='PNG')
456
+ img_buffer.seek(0)
457
+
458
+ st.download_button(
459
+ label=f"⬇️ Download Ad {idx + 1}",
460
+ data=img_buffer,
461
+ file_name=f"adforge_ad_{idx+1}_{item['timestamp'].strftime('%Y%m%d_%H%M%S')}.png",
462
+ mime="image/png",
463
+ key=f"download_{idx}",
464
+ use_container_width=True
465
+ )
466
+
467
+ with col_b:
468
+ with st.expander("ℹ️ Details"):
469
+ st.json(item['ad_data'])
470
+
471
+ st.markdown("---")
472
+
473
+ # Clear history button
474
+ if st.button("πŸ—‘οΈ Clear All", use_container_width=True):
475
+ st.session_state.generated_images = []
476
+ st.rerun()
477
+
478
+ else:
479
+ st.info("πŸ‘ˆ Configure your advertisement concept and click 'Generate Advertisement' to see results here")
480
+
481
+ # Show example
482
+ st.markdown("### 🎯 Example Output")
483
+ st.markdown("""
484
+ Your generated advertisements will appear here with:
485
+ - ✨ High-resolution professional images
486
+ - πŸ“₯ One-click download buttons
487
+ - πŸ“Š Detailed generation information
488
+ - 🎨 Multiple variations (if selected)
489
+ """)
490
+
491
+ # JSON Schema Documentation
492
+ with st.expander("πŸ“š JSON Schema Reference"):
493
+ st.markdown("""
494
+ ### Complete JSON Schema for Advertisement Generation
495
+
496
+ ```json
497
+ {
498
+ "product_name": "Your Product Name", // REQUIRED: Product identifier
499
+ "description": "Detailed product description", // REQUIRED: What the product is
500
+ "style": "minimalist | professional | vibrant | editorial | rustic",
501
+ "mood": "energetic | calm | luxurious | playful | sophisticated",
502
+ "target_audience": "Description of target demographic",
503
+ "colors": ["color1", "color2", "color3"], // Preferred color palette
504
+ "setting": "studio | outdoor | urban | natural",
505
+ "composition": "centered | rule of thirds | dynamic",
506
+ "lighting": "soft | dramatic | natural | studio",
507
+ "key_features": ["feature1", "feature2"], // Product highlights
508
+ "avoid": ["element1", "element2"] // Optional: Things to exclude
509
+ }
510
+ ```
511
+
512
+ ### Field Descriptions
513
+
514
+ **Required Fields:**
515
+ - `product_name`: The name of your product
516
+ - `description`: Brief but descriptive product overview
517
+
518
+ **Style Options:**
519
+ - `minimalist`: Clean, simple, modern aesthetics
520
+ - `professional`: Corporate, polished look
521
+ - `vibrant`: Colorful, energetic, eye-catching
522
+ - `editorial`: Magazine-quality, artistic
523
+ - `rustic`: Natural, organic, handcrafted feel
524
+
525
+ **Mood Options:**
526
+ - `energetic`: Dynamic, active, exciting
527
+ - `calm`: Peaceful, serene, relaxing
528
+ - `luxurious`: Premium, high-end, exclusive
529
+ - `playful`: Fun, lighthearted, creative
530
+ - `sophisticated`: Refined, elegant, classy
531
+
532
+ **Pro Tips:**
533
+ - Be specific with colors (e.g., "ocean blue" instead of just "blue")
534
+ - Combine multiple style elements for unique results
535
+ - Use the `avoid` field to exclude unwanted elements
536
+ - Experiment with different composition and lighting combinations
537
+ """)
538
+
539
+ # Footer with statistics
540
+ st.markdown("---")
541
+ col_foot1, col_foot2, col_foot3 = st.columns(3)
542
+
543
+ with col_foot1:
544
+ st.metric("Ads Generated This Session", len(st.session_state.generation_history))
545
+
546
+ with col_foot2:
547
+ total_images = sum(item['count'] for item in st.session_state.generation_history)
548
+ st.metric("Total Images Created", total_images)
549
+
550
+ with col_foot3:
551
+ if st.session_state.generation_history:
552
+ last_gen = st.session_state.generation_history[-1]['product']
553
+ st.metric("Last Product", last_gen)
554
+
555
+ st.markdown("""
556
+ <div style='text-align: center; color: gray; padding: 2rem 0;'>
557
+ <p><strong>AdForge AI</strong> - Powered by FLUX.1-schnell & Hugging Face</p>
558
+ <p>🌟 Create professional advertisements in seconds | πŸš€ Free to use | πŸ’Ž Commercial license</p>
559
+ </div>
560
+ """, unsafe_allow_html=True)