selfit-camera's picture
Add multi-image examples with Git LFS support
ce2dcda
raw
history blame
69.7 kB
import gradio as gr
import threading
import os
import shutil
import tempfile
import time
from util import process_multi_image_edit, process_local_image_edit, download_and_check_result_nsfw
from nfsw import NSFWDetector
# Configuration parameters
FREE_TRY_N = 20 # Free phase: first 20 tries without restrictions
SLOW_TRY_N = 30 # Slow phase start: 30 tries
SLOW2_TRY_N = 40 # Slow phase start: 30 tries
RATE_LIMIT_60 = 60 # Full restriction: blocked after 60 tries
# Time window configuration (minutes)
PHASE_1_WINDOW = 5 # 20-30 tries: 3 minutes
PHASE_2_WINDOW = 8 # 30-40 tries: 6 minutes
PHASE_3_WINDOW = 15 # 40-60 tries: 10 minutes
MAX_IMAGES_PER_WINDOW = 2 # Max images per time window
IP_Dict = {}
# IP generation statistics and time window tracking
IP_Generation_Count = {} # Record total generation count for each IP
IP_Rate_Limit_Track = {} # Record generation count and timestamp in current time window for each IP
def get_ip_generation_count(client_ip):
"""
Get IP generation count
"""
if client_ip not in IP_Generation_Count:
IP_Generation_Count[client_ip] = 0
return IP_Generation_Count[client_ip]
def increment_ip_generation_count(client_ip):
"""
Increment IP generation count
"""
if client_ip not in IP_Generation_Count:
IP_Generation_Count[client_ip] = 0
IP_Generation_Count[client_ip] += 1
return IP_Generation_Count[client_ip]
def get_ip_phase(client_ip):
"""
Get current phase for IP
Returns:
str: 'free', 'rate_limit_1', 'rate_limit_2', 'rate_limit_3', 'blocked'
"""
count = get_ip_generation_count(client_ip)
if count < FREE_TRY_N: # 0-19 tries
return 'free'
elif count < SLOW_TRY_N: # 20-29 tries
return 'rate_limit_1' # NSFW blur + 3 minutes 2 images
elif count < SLOW2_TRY_N: # 30-39 tries
return 'rate_limit_2' # NSFW blur + 6 minutes 2 images
elif count < RATE_LIMIT_60: # 40-59 tries
return 'rate_limit_3' # NSFW blur + 10 minutes 2 images
else: # 60+ tries
return 'blocked' # Generation blocked
def check_rate_limit_for_phase(client_ip, phase):
"""
Check rate limit for specific phase
Returns:
tuple: (is_limited, wait_time_minutes, current_count)
"""
if phase not in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
return False, 0, 0
# Determine time window
if phase == 'rate_limit_1':
window_minutes = PHASE_1_WINDOW # 3 minutes
elif phase == 'rate_limit_2':
window_minutes = PHASE_2_WINDOW # 6 minutes
else: # rate_limit_3
window_minutes = PHASE_3_WINDOW # 10 minutes
current_time = time.time()
window_key = f"{client_ip}_{phase}"
# Clean expired records
if window_key in IP_Rate_Limit_Track:
track_data = IP_Rate_Limit_Track[window_key]
# Check if within current time window
if current_time - track_data['start_time'] > window_minutes * 60:
# Time window expired, reset
IP_Rate_Limit_Track[window_key] = {
'count': 0,
'start_time': current_time,
'last_generation': current_time
}
else:
# Initialize
IP_Rate_Limit_Track[window_key] = {
'count': 0,
'start_time': current_time,
'last_generation': current_time
}
track_data = IP_Rate_Limit_Track[window_key]
# Check if exceeded limit
if track_data['count'] >= MAX_IMAGES_PER_WINDOW:
# Calculate remaining wait time
elapsed = current_time - track_data['start_time']
wait_time = (window_minutes * 60) - elapsed
wait_minutes = max(0, wait_time / 60)
return True, wait_minutes, track_data['count']
return False, 0, track_data['count']
def record_generation_attempt(client_ip, phase):
"""
Record generation attempt
"""
# Increment total count
increment_ip_generation_count(client_ip)
# Record time window count
if phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
window_key = f"{client_ip}_{phase}"
current_time = time.time()
if window_key in IP_Rate_Limit_Track:
IP_Rate_Limit_Track[window_key]['count'] += 1
IP_Rate_Limit_Track[window_key]['last_generation'] = current_time
else:
IP_Rate_Limit_Track[window_key] = {
'count': 1,
'start_time': current_time,
'last_generation': current_time
}
def apply_gaussian_blur_to_image_url(image_url, blur_strength=50):
"""
Apply Gaussian blur to image URL
Args:
image_url (str): Original image URL
blur_strength (int): Blur strength, default 50 (heavy blur)
Returns:
PIL.Image: Blurred PIL Image object
"""
try:
import requests
from PIL import Image, ImageFilter
import io
# Download image
response = requests.get(image_url, timeout=30)
if response.status_code != 200:
return None
# Convert to PIL Image
image_data = io.BytesIO(response.content)
image = Image.open(image_data)
# Apply heavy Gaussian blur
blurred_image = image.filter(ImageFilter.GaussianBlur(radius=blur_strength))
return blurred_image
except Exception as e:
print(f"⚠️ Failed to apply Gaussian blur: {e}")
return None
# Initialize NSFW detector (download from Hugging Face)
try:
nsfw_detector = NSFWDetector() # Auto download falconsai_yolov9_nsfw_model_quantized.pt from Hugging Face
print("βœ… NSFW detector initialized successfully")
except Exception as e:
print(f"❌ NSFW detector initialization failed: {e}")
nsfw_detector = None
def edit_image_interface(input_image1, input_image2, input_image3, prompt, aspect_ratio, request: gr.Request, progress=gr.Progress()):
"""
Interface function for processing multi-image editing with phase-based limitations
"""
try:
# Extract user IP
client_ip = request.client.host
x_forwarded_for = dict(request.headers).get('x-forwarded-for')
if x_forwarded_for:
client_ip = x_forwarded_for
if client_ip not in IP_Dict:
IP_Dict[client_ip] = 0
IP_Dict[client_ip] += 1
# Validate input images
input_images = [input_image1, input_image2, input_image3]
valid_images = [img for img in input_images if img is not None]
if len(valid_images) < 2:
return None, "Please upload at least 2 images", gr.update(visible=False)
if len(valid_images) > 3:
return None, "Maximum 3 images allowed", gr.update(visible=False)
if not prompt or prompt.strip() == "":
return None, "Please enter editing prompt", gr.update(visible=False)
# Check if prompt length is greater than 3 characters
if len(prompt.strip()) <= 3:
return None, "❌ Editing prompt must be more than 3 characters", gr.update(visible=False)
except Exception as e:
print(f"⚠️ Request preprocessing error: {e}")
return None, "❌ Request processing error", gr.update(visible=False)
# Get user current phase
current_phase = get_ip_phase(client_ip)
current_count = get_ip_generation_count(client_ip)
print(f"πŸ“Š User phase info - IP: {client_ip}, current phase: {current_phase}, generation count: {current_count}")
# Check if completely blocked
if current_phase == 'blocked':
# Generate blocked limit button
blocked_button_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 200px;
box-shadow: 0 4px 15px rgba(231, 76, 60, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸš€ Unlimited Generation</a>
</div>
"""
return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/multi-image-edit#generator for unlimited generation", gr.update(value=blocked_button_html, visible=True)
# Check rate limit (applies to rate_limit phases)
if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
is_limited, wait_minutes, window_count = check_rate_limit_for_phase(client_ip, current_phase)
if is_limited:
wait_minutes_int = int(wait_minutes) + 1
# Generate rate limit button
rate_limit_button_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 200px;
box-shadow: 0 4px 15px rgba(243, 156, 18, 0.4);
transition: all 0.3s ease;
border: none;
'>⏰ Skip Wait - Unlimited Generation</a>
</div>
"""
return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/multi-image-edit#generator for unlimited generation, or wait {wait_minutes_int} minutes before generating again", gr.update(value=rate_limit_button_html, visible=True)
# Parse aspect ratio to get width and height
width, height = 0, 0 # Default to auto sizing
if aspect_ratio and aspect_ratio != "Auto":
aspect_ratios = {
"16:9": (1364, 768),
"4:3": (1182, 887),
"1:1": (1024, 1024),
"3:4": (887, 1182),
"9:16": (768, 1364)
}
if aspect_ratio in aspect_ratios:
width, height = aspect_ratios[aspect_ratio]
# Handle NSFW detection based on phase
is_nsfw_task = False # Track if this task involves NSFW content
# Skip NSFW detection in free phase - check first image for NSFW
if current_phase != 'free' and nsfw_detector is not None and valid_images:
try:
nsfw_result = nsfw_detector.predict_pil_label_only(valid_images[0])
if nsfw_result.lower() == "nsfw":
is_nsfw_task = True
print(f"πŸ” Input NSFW detected in {current_phase} phase: ❌❌❌ {nsfw_result} - IP: {client_ip} (will blur result)")
else:
print(f"πŸ” Input NSFW check passed: βœ…βœ…βœ… {nsfw_result} - IP: {client_ip}")
except Exception as e:
print(f"⚠️ Input NSFW detection failed: {e}")
# Allow continuation when detection fails
result_url = None
status_message = ""
def progress_callback(message):
try:
nonlocal status_message
status_message = message
# Add error handling to prevent progress update failure
if progress is not None:
progress(0.5, desc=message)
except Exception as e:
print(f"⚠️ Progress update failed: {e}")
try:
# Record generation attempt (before actual generation to ensure correct count)
record_generation_attempt(client_ip, current_phase)
updated_count = get_ip_generation_count(client_ip)
print(f"βœ… Multi-image processing started - IP: {client_ip}, phase: {current_phase}, total count: {updated_count}, images: {len(valid_images)}, size: {width}x{height}, prompt: {prompt.strip()}", flush=True)
# Call multi-image editing processing function
result_url, message, task_uuid = process_multi_image_edit(valid_images, prompt.strip(), width, height, progress_callback)
if result_url:
print(f"βœ… Processing completed successfully - IP: {client_ip}, result_url: {result_url}, task_uuid: {task_uuid}", flush=True)
# Detect result image NSFW content (only in rate limit phases)
if nsfw_detector is not None and current_phase != 'free':
try:
if progress is not None:
progress(0.9, desc="Checking result image...")
is_nsfw, nsfw_error = download_and_check_result_nsfw(result_url, nsfw_detector)
if nsfw_error:
print(f"⚠️ Result image NSFW detection error - IP: {client_ip}, error: {nsfw_error}")
elif is_nsfw:
is_nsfw_task = True # Mark task as NSFW
print(f"πŸ” Result image NSFW detected in {current_phase} phase: ❌❌❌ - IP: {client_ip} (will blur result)")
else:
print(f"πŸ” Result image NSFW check passed: βœ…βœ…βœ… - IP: {client_ip}")
except Exception as e:
print(f"⚠️ Result image NSFW detection exception - IP: {client_ip}, error: {str(e)}")
# Apply blur if this is an NSFW task in rate limit phases
should_blur = False
if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3'] and is_nsfw_task:
should_blur = True
# Apply blur processing
if should_blur:
if progress is not None:
progress(0.95, desc="Applying content filter...")
blurred_image = apply_gaussian_blur_to_image_url(result_url)
if blurred_image is not None:
final_result = blurred_image # Return PIL Image object
final_message = f"⚠️ NSFW content detected, content filter applied. NSFW content is prohibited by Hugging Face, but you can generate unlimited content at our official website https://omnicreator.net/multi-image-edit#generator"
print(f"πŸ”’ Applied Gaussian blur for NSFW content - IP: {client_ip}")
else:
# Blur failed, return original URL with warning
final_result = result_url
final_message = f"⚠️ NSFW content detected, but content filter failed. Please visit https://omnicreator.net/multi-image-edit#generator for better experience"
# Generate NSFW button for blurred content
nsfw_action_buttons_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 200px;
box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸ”₯ Unlimited NSFW Generation</a>
</div>
"""
return final_result, final_message, gr.update(value=nsfw_action_buttons_html, visible=True)
else:
final_result = result_url
final_message = "βœ… " + message
try:
if progress is not None:
progress(1.0, desc="Processing completed")
except Exception as e:
print(f"⚠️ Final progress update failed: {e}")
# Generate action buttons HTML like Trump AI Voice
action_buttons_html = ""
if task_uuid:
task_detail_url = f"https://omnicreator.net/my-creations/task/{task_uuid}"
action_buttons_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='{task_detail_url}' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 160px;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸ–ΌοΈ Download HD Image</a>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 160px;
box-shadow: 0 4px 15px rgba(17, 153, 142, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸš€ Unlimited Generation</a>
</div>
"""
return final_result, final_message, gr.update(value=action_buttons_html, visible=True)
else:
print(f"❌ Processing failed - IP: {client_ip}, error: {message}", flush=True)
return None, "❌ " + message, gr.update(visible=False)
except Exception as e:
print(f"❌ Processing exception - IP: {client_ip}, error: {str(e)}")
return None, f"❌ Error occurred during processing: {str(e)}", gr.update(visible=False)
def local_edit_interface(image_dict, prompt, request: gr.Request, progress=gr.Progress()):
"""
Handle local editing requests (with phase-based limitations)
"""
try:
# Extract user IP
client_ip = request.client.host
x_forwarded_for = dict(request.headers).get('x-forwarded-for')
if x_forwarded_for:
client_ip = x_forwarded_for
if client_ip not in IP_Dict:
IP_Dict[client_ip] = 0
IP_Dict[client_ip] += 1
if image_dict is None:
return None, "Please upload an image and draw the area to edit", gr.update(visible=False)
# Check if background and layers exist
if "background" not in image_dict or "layers" not in image_dict:
return None, "Please draw the area to edit on the image", gr.update(visible=False)
base_image = image_dict["background"]
layers = image_dict["layers"]
if not layers:
return None, "Please draw the area to edit on the image", gr.update(visible=False)
if not prompt or prompt.strip() == "":
return None, "Please enter editing prompt", gr.update(visible=False)
# Check prompt length
if len(prompt.strip()) <= 3:
return None, "❌ Editing prompt must be more than 3 characters", gr.update(visible=False)
except Exception as e:
print(f"⚠️ Local edit request preprocessing error: {e}")
return None, "❌ Request processing error", gr.update(visible=False)
# Get user current phase
current_phase = get_ip_phase(client_ip)
current_count = get_ip_generation_count(client_ip)
print(f"πŸ“Š Local edit user phase info - IP: {client_ip}, current phase: {current_phase}, generation count: {current_count}")
# Check if completely blocked
if current_phase == 'blocked':
# Generate blocked limit button
blocked_button_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 200px;
box-shadow: 0 4px 15px rgba(231, 76, 60, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸš€ Unlimited Generation</a>
</div>
"""
return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/multi-image-edit#generator for unlimited generation", gr.update(value=blocked_button_html, visible=True)
# Check rate limit (applies to rate_limit phases)
if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
is_limited, wait_minutes, window_count = check_rate_limit_for_phase(client_ip, current_phase)
if is_limited:
wait_minutes_int = int(wait_minutes) + 1
# Generate rate limit button
rate_limit_button_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #f39c12 0%, #e67e22 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 200px;
box-shadow: 0 4px 15px rgba(243, 156, 18, 0.4);
transition: all 0.3s ease;
border: none;
'>⏰ Skip Wait - Unlimited Generation</a>
</div>
"""
return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/multi-image-edit#generator for unlimited generation, or wait {wait_minutes_int} minutes before generating again", gr.update(value=rate_limit_button_html, visible=True)
# Handle NSFW detection based on phase
is_nsfw_task = False # Track if this task involves NSFW content
# Skip NSFW detection in free phase
if current_phase != 'free' and nsfw_detector is not None and base_image is not None:
try:
nsfw_result = nsfw_detector.predict_pil_label_only(base_image)
if nsfw_result.lower() == "nsfw":
is_nsfw_task = True
print(f"πŸ” Local edit input NSFW detected in {current_phase} phase: ❌❌❌ {nsfw_result} - IP: {client_ip} (will blur result)")
else:
print(f"πŸ” Local edit input NSFW check passed: βœ…βœ…βœ… {nsfw_result} - IP: {client_ip}")
except Exception as e:
print(f"⚠️ Local edit input NSFW detection failed: {e}")
# Allow continuation when detection fails
result_url = None
status_message = ""
def progress_callback(message):
try:
nonlocal status_message
status_message = message
# Add error handling to prevent progress update failure
if progress is not None:
progress(0.5, desc=message)
except Exception as e:
print(f"⚠️ Local edit progress update failed: {e}")
try:
# Record generation attempt (before actual generation to ensure correct count)
record_generation_attempt(client_ip, current_phase)
updated_count = get_ip_generation_count(client_ip)
print(f"βœ… Local editing started - IP: {client_ip}, phase: {current_phase}, total count: {updated_count}, prompt: {prompt.strip()}", flush=True)
# Call local image editing processing function
result_url, message, task_uuid = process_local_image_edit(base_image, layers, prompt.strip(), progress_callback)
if result_url:
print(f"βœ… Local editing completed successfully - IP: {client_ip}, result_url: {result_url}, task_uuid: {task_uuid}", flush=True)
# Detect result image NSFW content (only in rate limit phases)
if nsfw_detector is not None and current_phase != 'free':
try:
if progress is not None:
progress(0.9, desc="Checking result image...")
is_nsfw, nsfw_error = download_and_check_result_nsfw(result_url, nsfw_detector)
if nsfw_error:
print(f"⚠️ Local edit result image NSFW detection error - IP: {client_ip}, error: {nsfw_error}")
elif is_nsfw:
is_nsfw_task = True # Mark task as NSFW
print(f"πŸ” Local edit result image NSFW detected in {current_phase} phase: ❌❌❌ - IP: {client_ip} (will blur result)")
else:
print(f"πŸ” Local edit result image NSFW check passed: βœ…βœ…βœ… - IP: {client_ip}")
except Exception as e:
print(f"⚠️ Local edit result image NSFW detection exception - IP: {client_ip}, error: {str(e)}")
# Apply blur if this is an NSFW task in rate limit phases
should_blur = False
if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3'] and is_nsfw_task:
should_blur = True
# Apply blur processing
if should_blur:
if progress is not None:
progress(0.95, desc="Applying content filter...")
blurred_image = apply_gaussian_blur_to_image_url(result_url)
if blurred_image is not None:
final_result = blurred_image # Return PIL Image object
final_message = f"⚠️ NSFW content detected, content filter applied. NSFW content is prohibited by Hugging Face, but you can generate unlimited content at our official website https://omnicreator.net/multi-image-edit#generator"
print(f"πŸ”’ Local edit applied Gaussian blur for NSFW content - IP: {client_ip}")
else:
# Blur failed, return original URL with warning
final_result = result_url
final_message = f"⚠️ NSFW content detected, but content filter failed. Please visit https://omnicreator.net/multi-image-edit#generator for better experience"
# Generate NSFW button for blurred content
nsfw_action_buttons_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 200px;
box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸ”₯ Unlimited NSFW Generation</a>
</div>
"""
return final_result, final_message, gr.update(value=nsfw_action_buttons_html, visible=True)
else:
final_result = result_url
final_message = "βœ… " + message
try:
if progress is not None:
progress(1.0, desc="Processing completed")
except Exception as e:
print(f"⚠️ Local edit final progress update failed: {e}")
# Generate action buttons HTML like Trump AI Voice
action_buttons_html = ""
if task_uuid:
task_detail_url = f"https://omnicreator.net/my-creations/task/{task_uuid}"
action_buttons_html = f"""
<div style='display: flex; justify-content: center; gap: 15px; margin: 10px 0 5px 0; padding: 0px;'>
<a href='{task_detail_url}' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 160px;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸ–ΌοΈ Download HD Image</a>
<a href='https://omnicreator.net/multi-image-edit#generator' target='_blank' style='
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16px 32px;
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
color: white;
text-decoration: none;
border-radius: 12px;
font-weight: 600;
font-size: 16px;
text-align: center;
min-width: 160px;
box-shadow: 0 4px 15px rgba(17, 153, 142, 0.4);
transition: all 0.3s ease;
border: none;
'>πŸš€ Unlimited Generation</a>
</div>
"""
return final_result, final_message, gr.update(value=action_buttons_html, visible=True)
else:
print(f"❌ Local editing processing failed - IP: {client_ip}, error: {message}", flush=True)
return None, "❌ " + message, gr.update(visible=False)
except Exception as e:
print(f"❌ Local editing exception - IP: {client_ip}, error: {str(e)}")
return None, f"❌ Error occurred during processing: {str(e)}", gr.update(visible=False)
# Create Gradio interface
def create_app():
with gr.Blocks(
title="AI Image Editor",
theme=gr.themes.Soft(),
css="""
.main-container {
max-width: 1200px;
margin: 0 auto;
}
.upload-area {
border: 2px dashed #ccc;
border-radius: 10px;
padding: 20px;
text-align: center;
}
.result-area {
margin-top: 20px;
padding: 20px;
border-radius: 10px;
background-color: #f8f9fa;
}
.use-as-input-btn {
margin-top: 10px;
width: 100%;
}
""",
# Improve concurrency performance configuration
head="""
<script>
// Reduce client-side state update frequency, avoid excessive SSE connections
if (window.gradio) {
window.gradio.update_frequency = 2000; // Update every 2 seconds
}
</script>
"""
) as app:
# Main title - styled like Trump AI Voice
gr.HTML("""
<div style="text-align: center; margin: 5px auto 0px auto; max-width: 800px;">
<h1 style="color: #2c3e50; margin: 0; font-size: 3.5em; font-weight: 800; letter-spacing: 3px; text-shadow: 2px 2px 4px rgba(0,0,0,0.1);">
🎨 AI Multi-Image Editor
</h1>
</div>
""", padding=False)
# Powered by line below title - styled like Trump AI Voice
gr.HTML("""
<div style="text-align: center; margin: 0px auto -5px auto;">
<p style="margin: 0; font-size: 16px; color: #999; font-weight: 400;">
powered by <a href="https://omnicreator.net/multi-image-edit#generator" target="_blank" style="color: #667eea; text-decoration: none;">omnicreator.net</a>
</p>
</div>
""", padding=False)
with gr.Tabs():
# Multi-image editing tab
with gr.Tab("πŸ–ΌοΈ Multi-Image Editing"):
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### πŸ“Έ Upload Images (2-3 images)")
# Multiple image inputs
with gr.Row():
input_image1 = gr.Image(
label="Image 1 *",
type="pil",
height=200,
elem_classes=["upload-area"]
)
input_image2 = gr.Image(
label="Image 2 *",
type="pil",
height=200,
elem_classes=["upload-area"]
)
input_image3 = gr.Image(
label="Image 3 (optional)",
type="pil",
height=200,
elem_classes=["upload-area"]
)
gr.Markdown("### πŸ“ Output Size")
aspect_ratio_selector = gr.Radio(
choices=["Auto", "16:9", "4:3", "1:1", "3:4", "9:16"],
value="Auto",
label="Select aspect ratio",
info="Choose output dimensions or Auto for original sizing"
)
gr.Markdown("### ✍️ Multi-Image Editing Instructions")
prompt_input = gr.Textbox(
label="Enter multi-image editing prompt",
placeholder="For example: combine these images into a single scene, merge the best parts from each image, create a collage with artistic transitions...",
lines=4,
max_lines=6
)
edit_button = gr.Button(
"πŸš€ Start Multi-Image Editing",
variant="primary",
size="lg"
)
with gr.Column(scale=1):
gr.Markdown("### 🎯 Multi-Image Editing Result")
output_image = gr.Image(
label="Multi-image edited result",
height=400,
elem_classes=["result-area"]
)
# Add "Use as Input" button
use_as_input_btn = gr.Button(
"πŸ”„ Use as Input",
variant="secondary",
size="sm",
elem_classes=["use-as-input-btn"]
)
status_output = gr.Textbox(
label="Processing status",
lines=2,
max_lines=3,
interactive=False
)
# Action buttons that will show after task completion
action_buttons = gr.HTML(visible=False)
# Example area
gr.Markdown("### πŸ’‘ Multi-Image Editing Examples")
# Helper function to load example images
def load_example_1():
"""Load dancing cats example"""
try:
from PIL import Image
img1 = Image.open("datas/data01/tom02.webp")
img2 = Image.open("datas/data01/tom.webp")
return img1, img2, None, "Let the 2 cats dance together", "16:9"
except Exception as e:
print(f"Failed to load example 1 images: {e}")
return None, None, None, "Let the 2 cats dance together", "16:9"
def load_example_2():
"""Load fashion try-on example"""
try:
from PIL import Image
img1 = Image.open("datas/data02/girl.jpg")
img2 = Image.open("datas/data02/cloth.jpeg")
return img1, img2, None, "Let the girl in first image, wear the dress in second image", "9:16"
except Exception as e:
print(f"Failed to load example 2 images: {e}")
return None, None, None, "Let the girl in first image, wear the dress in second image", "9:16"
def load_example_3():
"""Load beach bikini example"""
try:
from PIL import Image
img1 = Image.open("datas/data03/girl.webp")
img2 = Image.open("datas/data03/cloth.jpg")
return img1, img2, None, "Let the girl in first image, wear the bikini in second image, lying on the beach", "1:1"
except Exception as e:
print(f"Failed to load example 3 images: {e}")
return None, None, None, "Let the girl in first image, wear the bikini in second image, lying on the beach", "1:1"
# Example 1: Cats dancing
gr.Markdown("#### 🐱 Example 1: Dancing Cats (2 images)")
with gr.Row():
with gr.Column(scale=2):
# Preview images for example 1
with gr.Row():
try:
gr.Image("datas/data01/tom02.webp", label="Cat 1", height=100, width=100, show_label=False, interactive=False)
gr.Image("datas/data01/tom.webp", label="Cat 2", height=100, width=100, show_label=False, interactive=False)
except:
gr.Markdown("*Preview images not available*")
gr.Markdown("**Prompt**: Let the 2 cats dance together \n**Size**: 16:9")
with gr.Column(scale=1):
gr.Button(
"🎭 Load Dancing Cats Example",
size="lg",
variant="secondary"
).click(
fn=load_example_1,
outputs=[input_image1, input_image2, input_image3, prompt_input, aspect_ratio_selector]
)
# Example 2: Girl wearing dress
gr.Markdown("#### πŸ‘— Example 2: Fashion Try-on (2 images)")
with gr.Row():
with gr.Column(scale=2):
# Preview images for example 2
with gr.Row():
try:
gr.Image("datas/data02/girl.jpg", label="Girl", height=100, width=100, show_label=False, interactive=False)
gr.Image("datas/data02/cloth.jpeg", label="Dress", height=100, width=100, show_label=False, interactive=False)
except:
gr.Markdown("*Preview images not available*")
gr.Markdown("**Prompt**: Let the girl in first image, wear the dress in second image \n**Size**: 9:16")
with gr.Column(scale=1):
gr.Button(
"πŸ‘— Load Fashion Try-on Example",
size="lg",
variant="secondary"
).click(
fn=load_example_2,
outputs=[input_image1, input_image2, input_image3, prompt_input, aspect_ratio_selector]
)
# Example 3: Beach bikini
gr.Markdown("#### πŸ–οΈ Example 3: Beach Style (2 images)")
with gr.Row():
with gr.Column(scale=2):
# Preview images for example 3
with gr.Row():
try:
gr.Image("datas/data03/girl.webp", label="Girl", height=100, width=100, show_label=False, interactive=False)
gr.Image("datas/data03/cloth.jpg", label="Bikini", height=100, width=100, show_label=False, interactive=False)
except:
gr.Markdown("*Preview images not available*")
gr.Markdown("**Prompt**: Let the girl in first image, wear the bikini in second image, lying on the beach \n**Size**: 1:1")
with gr.Column(scale=1):
gr.Button(
"πŸ–οΈ Load Beach Style Example",
size="lg",
variant="secondary"
).click(
fn=load_example_3,
outputs=[input_image1, input_image2, input_image3, prompt_input, aspect_ratio_selector]
)
# Additional quick prompt examples
gr.Markdown("#### ✨ Quick Prompts")
with gr.Row():
additional_prompts = [
"Combine these images into a single artistic scene",
"Create a collage with artistic transitions between images",
"Blend these images into a cohesive composition"
]
for prompt in additional_prompts:
gr.Button(
prompt,
size="sm"
).click(
lambda p=prompt: p,
outputs=prompt_input
)
# Bind button click events - simplified, remove state management
edit_button.click(
fn=edit_image_interface,
inputs=[input_image1, input_image2, input_image3, prompt_input, aspect_ratio_selector],
outputs=[output_image, status_output, action_buttons],
show_progress=True,
# Increase concurrency settings
concurrency_limit=8, # Limit concurrent requests for multi-image processing
api_name="multi_image_edit"
)
# Simplify "Use as Input" button, use result as first image
def simple_use_as_input(output_img):
if output_img is not None:
return output_img, None, None # Set as first image, clear others
return None, None, None
use_as_input_btn.click(
fn=simple_use_as_input,
inputs=[output_image],
outputs=[input_image1, input_image2, input_image3]
)
# # Local editing tab
# with gr.Tab("πŸ–ŒοΈ Local Editing"):
# with gr.Row():
# with gr.Column(scale=1):
# gr.Markdown("### πŸ“Έ Upload Image and Draw Edit Area")
# local_input_image = gr.ImageEditor(
# label="Upload image and draw mask",
# type="pil",
# height=512,
# brush=gr.Brush(colors=["#ff0000"], default_size=180),
# elem_classes=["upload-area"]
# )
# gr.Markdown("### ✍️ Editing Instructions")
# local_prompt_input = gr.Textbox(
# label="Enter local editing prompt",
# placeholder="For example: change selected area hair to golden, add patterns to selected object, change selected area color, etc...",
# lines=3,
# max_lines=5
# )
# local_edit_button = gr.Button(
# "🎯 Start Local Editing",
# variant="primary",
# size="lg"
# )
# with gr.Column(scale=1):
# gr.Markdown("### 🎯 Editing Result")
# local_output_image = gr.Image(
# label="Local edited image",
# height=320,
# elem_classes=["result-area"]
# )
# # Add "Use as Input" button
# local_use_as_input_btn = gr.Button(
# "πŸ”„ Use as Input",
# variant="secondary",
# size="sm",
# elem_classes=["use-as-input-btn"]
# )
# local_status_output = gr.Textbox(
# label="Processing status",
# lines=2,
# max_lines=3,
# interactive=False
# )
# Action buttons that will show after task completion
# local_action_buttons = gr.HTML(visible=False)
# # Local editing examples
# gr.Markdown("### πŸ’‘ Local Editing Prompt Examples")
# with gr.Row():
# local_example_prompts = [
# "Change selected area hair to golden",
# "Add pattern designs to selected clothing",
# "Change selected area to different material",
# "Add decorations to selected object",
# "Change selected area color and style"
# ]
# for prompt in local_example_prompts:
# gr.Button(
# prompt,
# size="sm"
# ).click(
# lambda p=prompt: p,
# outputs=local_prompt_input
# )
# # Bind local edit button click events - simplified, remove state management
# local_edit_button.click(
# fn=local_edit_interface,
# inputs=[local_input_image, local_prompt_input],
# outputs=[local_output_image, local_status_output, local_action_buttons],
# show_progress=True,
# # Increase concurrency settings
# concurrency_limit=8, # Local editing is more complex, allow fewer concurrent requests
# api_name="local_edit"
# )
# # Simplify local edit "Use as Input" button
# def simple_local_use_as_input(output_img):
# if output_img is not None:
# # Create simple ImageEditor format
# editor_data = {
# "background": output_img,
# "layers": [],
# "composite": output_img
# }
# return editor_data
# return None
# local_use_as_input_btn.click(
# fn=simple_local_use_as_input,
# inputs=[local_output_image],
# outputs=[local_input_image]
# )
# SEO Content Section
gr.HTML("""
<div style="width: 100%; margin: 50px 0; padding: 0 20px;">
<!-- Showcase Section -->
<div style="text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px; border-radius: 20px; margin: 40px 0;">
<h2 style="margin: 0 0 20px 0; font-size: 2.2em; font-weight: 700;">
🎨 Unlimited AI Image Generation & Editing
</h2>
<p style="margin: 0 0 25px 0; font-size: 1.2em; opacity: 0.95; line-height: 1.6;">
Experience the ultimate freedom in AI image creation! Generate and edit unlimited images without restrictions,
including NSFW content, with our premium AI image editing platform.
</p>
<div style="display: flex; justify-content: center; gap: 25px; flex-wrap: wrap; margin: 30px 0;">
<a href="https://omnicreator.net/multi-image-edit#generator" target="_blank" style="
display: inline-flex;
align-items: center;
justify-content: center;
padding: 20px 40px;
background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%);
color: white;
text-decoration: none;
border-radius: 15px;
font-weight: 700;
font-size: 18px;
text-align: center;
min-width: 250px;
box-shadow: 0 8px 25px rgba(255, 107, 107, 0.4);
transition: all 0.3s ease;
border: none;
transform: scale(1);
" onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
πŸš€ Get Unlimited Access Now
</a>
</div>
<p style="color: rgba(255,255,255,0.9); font-size: 1em; margin: 20px 0 0 0;">
Join thousands of creators who trust Omni Creator for unrestricted AI image generation!
</p>
</div>
<!-- Hero Description -->
<div style="text-align: center; margin: 25px auto; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 35px; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.1);">
<h2 style="color: #2c3e50; margin: 0 0 20px 0; font-size: 1.9em; font-weight: 700;">
🌟 Professional AI Multi-Image Editor - No Restrictions
</h2>
<p style="color: #555; font-size: 1.1em; line-height: 1.6; margin: 0 0 20px 0; padding: 0 20px;">
Transform multiple images into stunning compositions with our advanced AI multi-image editing platform. Combine,
merge, and blend 2-3 images to create artistic masterpieces, collages, and seamless compositions with complete
creative freedom and professional quality results.
</p>
</div>
<!-- Features Grid -->
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 25px; margin: 40px 0;">
<div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #e74c3c;">
<h3 style="color: #e74c3c; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
🎯 Unlimited Generation
</h3>
<p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
Premium users enjoy unlimited image generation without daily limits, rate restrictions, or content barriers.
Create as many images as you need, whenever you need them.
</p>
</div>
<div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #3498db;">
<h3 style="color: #3498db; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
πŸ”“ No Content Restrictions
</h3>
<p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
Generate and edit any type of content without NSFW filters or content limitations. Complete creative
freedom for artists, designers, and content creators.
</p>
</div>
<div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #27ae60;">
<h3 style="color: #27ae60; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
⚑ Lightning Fast Processing
</h3>
<p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
Advanced AI infrastructure delivers high-quality results in seconds. No waiting in queues,
no processing delays - just instant, professional-grade image editing.
</p>
</div>
<div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #9b59b6;">
<h3 style="color: #9b59b6; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
🎨 Advanced Editing Tools
</h3>
<p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
Global transformations, precision local editing, style transfer, object removal, background replacement,
and dozens of other professional editing capabilities.
</p>
</div>
<div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #f39c12;">
<h3 style="color: #f39c12; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
πŸ’Ž Premium Quality
</h3>
<p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
State-of-the-art AI models trained on millions of images deliver exceptional quality and realism.
Professional results suitable for commercial use and high-end projects.
</p>
</div>
<div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #34495e;">
<h3 style="color: #34495e; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
🌍 Multi-Modal Support
</h3>
<p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
Support for all image formats, styles, and use cases. From photorealistic portraits to artistic creations,
product photography to digital art - we handle everything.
</p>
</div>
</div>
<!-- Premium Benefits Section -->
<div style="background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); color: white; padding: 40px; border-radius: 20px; margin: 40px 0; text-align: center;">
<h2 style="margin: 0 0 25px 0; font-size: 1.8em; font-weight: 700;">
πŸ’Ž Why Choose Omni Creator Premium?
</h2>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin: 30px 0;">
<div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
<h4 style="margin: 0 0 10px 0; font-size: 1.2em;">🚫 No Rate Limits</h4>
<p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Generate unlimited images without waiting periods or daily restrictions</p>
</div>
<div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
<h4 style="margin: 0 0 10px 0; font-size: 1.2em;">🎭 Unrestricted Content</h4>
<p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Create any type of content without NSFW filters or censorship</p>
</div>
<div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
<h4 style="margin: 0 0 10px 0; font-size: 1.2em;">⚑ Priority Processing</h4>
<p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Skip queues and get instant results with dedicated processing power</p>
</div>
<div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
<h4 style="margin: 0 0 10px 0; font-size: 1.2em;">🎨 Advanced Features</h4>
<p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Access to latest AI models and cutting-edge editing capabilities</p>
</div>
</div>
<div style="display: flex; justify-content: center; margin: 25px 0 0 0;">
<a href="https://omnicreator.net/multi-image-edit#generator" target="_blank" style="
display: inline-flex;
align-items: center;
justify-content: center;
padding: 18px 35px;
background: rgba(255,255,255,0.9);
color: #333;
text-decoration: none;
border-radius: 15px;
font-weight: 700;
font-size: 16px;
text-align: center;
min-width: 200px;
box-shadow: 0 6px 20px rgba(0,0,0,0.3);
transition: all 0.3s ease;
border: none;
">🌟 Start Creating Now</a>
</div>
</div>
<!-- Tips Section -->
<div style="background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 50%, #fecfef 100%); padding: 30px; border-radius: 15px; margin: 40px 0;">
<h3 style="color: #8b5cf6; text-align: center; margin: 0 0 25px 0; font-size: 1.5em; font-weight: 700;">
πŸ’‘ Pro Tips for Best Results
</h3>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 18px;">
<div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
<strong style="color: #8b5cf6; font-size: 1.1em;">πŸ“ Clear Descriptions:</strong>
<p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Use detailed, specific prompts for better results. Describe colors, styles, lighting, and composition clearly.</p>
</div>
<div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
<strong style="color: #8b5cf6; font-size: 1.1em;">🎯 Local Editing:</strong>
<p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Use precise brush strokes to select areas for local editing. Smaller, focused edits often yield better results.</p>
</div>
<div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
<strong style="color: #8b5cf6; font-size: 1.1em;">⚑ Iterative Process:</strong>
<p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Use "Use as Input" feature to refine results. Multiple iterations can achieve complex transformations.</p>
</div>
<div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
<strong style="color: #8b5cf6; font-size: 1.1em;">πŸ–ΌοΈ Image Quality:</strong>
<p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Higher resolution input images (up to 10MB) generally produce better editing results and finer details.</p>
</div>
</div>
</div>
<!-- Use Cases Section -->
<div style="text-align: center; margin: 25px auto; background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); padding: 35px; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.1);">
<h2 style="color: #2c3e50; margin: 0 0 20px 0; font-size: 1.8em; font-weight: 700;">
πŸš€ Perfect For Every Creative Need
</h2>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 25px 0; text-align: left;">
<div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
<h4 style="color: #e74c3c; margin: 0 0 10px 0;">🎨 Digital Art</h4>
<ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
<li>Character design</li>
<li>Concept art</li>
<li>Style transfer</li>
<li>Artistic effects</li>
</ul>
</div>
<div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
<h4 style="color: #3498db; margin: 0 0 10px 0;">πŸ“Έ Photography</h4>
<ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
<li>Background replacement</li>
<li>Object removal</li>
<li>Lighting adjustment</li>
<li>Portrait enhancement</li>
</ul>
</div>
<div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
<h4 style="color: #27ae60; margin: 0 0 10px 0;">πŸ›οΈ E-commerce</h4>
<ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
<li>Product photography</li>
<li>Lifestyle shots</li>
<li>Color variations</li>
<li>Context placement</li>
</ul>
</div>
<div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
<h4 style="color: #9b59b6; margin: 0 0 10px 0;">πŸ“± Social Media</h4>
<ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
<li>Content creation</li>
<li>Meme generation</li>
<li>Brand visuals</li>
<li>Viral content</li>
</ul>
</div>
</div>
<div style="text-align: center; margin: 25px 0 0 0;">
<a href="https://omnicreator.net/multi-image-edit#generator" target="_blank" style="
display: inline-flex;
align-items: center;
justify-content: center;
padding: 18px 35px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
text-decoration: none;
border-radius: 15px;
font-weight: 700;
font-size: 16px;
text-align: center;
min-width: 220px;
box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease;
border: none;
">🎯 Start Your Project Now</a>
</div>
</div>
</div>
<!-- Powered by footer -->
<div style="text-align: center; margin: 30px auto 20px auto; padding: 20px;">
<p style="margin: 0 0 10px 0; font-size: 18px; color: #333; font-weight: 500;">
Powered by <a href="https://omnicreator.net/multi-image-edit#generator" target="_blank" style="color: #667eea; text-decoration: none; font-weight: bold;">Omni Creator</a>
</p>
<p style="margin: 0; font-size: 14px; color: #999; font-weight: 400;">
The ultimate AI image generation and editing platform β€’ Unlimited creativity, zero restrictions
</p>
</div>
""", padding=False)
return app
if __name__ == "__main__":
app = create_app()
# Improve queue configuration to handle high concurrency and prevent SSE connection issues
app.queue(
default_concurrency_limit=20, # Default concurrency limit
max_size=50, # Maximum queue size
api_open=False # Close API access to reduce resource consumption
)
app.launch(
server_name="0.0.0.0",
show_error=True, # Show detailed error information
quiet=False, # Keep log output
max_threads=40, # Increase thread pool size
height=800,
favicon_path=None # Reduce resource loading
)