Spaces:
Running
Running
File size: 7,909 Bytes
f04794a 00def7d f04794a 7d93276 d556179 2ab4d4a d556179 7d93276 7824523 e2710c9 aecd8c4 d556179 857b096 d556179 aecd8c4 d556179 ce3abb5 185cd3b c0a27a1 185cd3b c0a27a1 185cd3b c0a27a1 185cd3b c0a27a1 ce3abb5 d556179 aecd8c4 d556179 857b096 6045760 aecd8c4 6045760 857b096 7d93276 d556179 7d93276 857b096 d556179 7d93276 d556179 857b096 d556179 f04794a d556179 aecd8c4 857b096 7d93276 aecd8c4 d556179 7d93276 857b096 7d93276 857b096 82c9256 857b096 7d93276 857b096 791ca28 857b096 aecd8c4 857b096 aecd8c4 857b096 7824523 82c9256 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
import gradio as gr
from google import genai
from google.genai import types
from PIL import Image
from io import BytesIO
import tempfile
import concurrent.futures
import os
import time
from threading import Lock
# Load API credentials from environment
api_key = os.environ.get("API_KEY")
univin_model = os.environ.get("univin")
client = genai.Client(api_key=api_key)
CALL_INTERVAL = 2.0 / 10.0 # seconds
_dt_lock = Lock()
_last_call_time = 0.0
def throttle():
"""
Ensures there's at least CALL_INTERVAL seconds between API calls.
"""
global _last_call_time
with _dt_lock:
now = time.time()
elapsed = now - _last_call_time
if elapsed < CALL_INTERVAL:
time.sleep(CALL_INTERVAL - elapsed)
_last_call_time = time.time()
PROMPT_VARIATIONS = [
# 1: Front view
"Create a high-resolution 800×800px image of the EXACT SAME product from a front view. CRITICAL INSTRUCTIONS: The product must be a PIXEL-PERFECT match to the original in EVERY aspect - EXACT same text (including font, size, spacing, and positioning), EXACT same colors (including all shades, gradients, and color codes), EXACT same materials and textures, EXACT same branding elements, EXACT same dimensions and proportions, EXACT same markings and labels, EXACT same finish and surface details, EXACT same shadows and highlights, EXACT same reflections and gloss, EXACT same embossing or debossing if present. DO NOT modify ANY aspect of the product. ONLY change the viewing angle to front view. Maintain a pure white background with professional studio lighting. The output must be a high-quality, e-commerce ready image with perfect color accuracy and sharp details.",
# 2: Left-side view
"Create a high-resolution 800×800px image of the EXACT SAME product from a left-side three-quarter (45-degree) angle. CRITICAL INSTRUCTIONS: The product must be a PIXEL-PERFECT match to the original in EVERY aspect - EXACT same text (including font, size, spacing, and positioning), EXACT same colors (including all shades, gradients, and color codes), EXACT same materials and textures, EXACT same branding elements, EXACT same dimensions and proportions, EXACT same markings and labels, EXACT same finish and surface details, EXACT same shadows and highlights, EXACT same reflections and gloss, EXACT same embossing or debossing if present. DO NOT modify ANY aspect of the product. ONLY change the viewing angle to left-side view. Maintain a pure white background with professional studio lighting. The output must be a high-quality, e-commerce ready image with perfect color accuracy and sharp details.",
# 3: Right-side view
"Create a high-resolution 800×800px image of the EXACT SAME product from a right-side three-quarter (45-degree) angle. CRITICAL INSTRUCTIONS: The product must be a PIXEL-PERFECT match to the original in EVERY aspect - EXACT same text (including font, size, spacing, and positioning), EXACT same colors (including all shades, gradients, and color codes), EXACT same materials and textures, EXACT same branding elements, EXACT same dimensions and proportions, EXACT same markings and labels, EXACT same finish and surface details, EXACT same shadows and highlights, EXACT same reflections and gloss, EXACT same embossing or debossing if present. DO NOT modify ANY aspect of the product. ONLY change the viewing angle to right-side view. Maintain a pure white background with professional studio lighting. The output must be a high-quality, e-commerce ready image with perfect color accuracy and sharp details.",
# 4: Top-down view
"Create a high-resolution 800×800px image of the EXACT SAME product from a top-down (bird's-eye) angle. CRITICAL INSTRUCTIONS: The product must be a PIXEL-PERFECT match to the original in EVERY aspect - EXACT same text (including font, size, spacing, and positioning), EXACT same colors (including all shades, gradients, and color codes), EXACT same materials and textures, EXACT same branding elements, EXACT same dimensions and proportions, EXACT same markings and labels, EXACT same finish and surface details, EXACT same shadows and highlights, EXACT same reflections and gloss, EXACT same embossing or debossing if present. DO NOT modify ANY aspect of the product. ONLY change the viewing angle to top-down view. Maintain a pure white background with professional studio lighting. The output must be a high-quality, e-commerce ready image with perfect color accuracy and sharp details."
]
# Detailed prompt variations for different backgrounds/angles
def process_variation(variation, input_image):
# Throttle to respect API rate limit
throttle()
# Build text + image input
text_input = (
"Hi, this is a picture of a product.",
variation
)
# Call the GenAI API
response = client.models.generate_content(
model=univin_model,
contents=[text_input, input_image],
config=types.GenerateContentConfig(response_modalities=['Text', 'Image'])
)
# Extract generated image bytes
for part in response.candidates[0].content.parts:
if part.inline_data is not None:
img = Image.open(BytesIO(part.inline_data.data))
# Save to temp file and return its path
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmp:
img.save(tmp, format="PNG")
return tmp.name
return None
def generate_images(input_image):
"""
Generate one image per prompt variation in parallel, respecting rate limits.
"""
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = [
executor.submit(process_variation, var, input_image)
for var in PROMPT_VARIATIONS
]
return [f.result() for f in futures if f.result()]
# Gradio UI setup with custom styling
def build_interface():
custom_css = """
#generate-button {
background-color: #4A90E2;
color: white;
border-radius: 8px;
padding: 12px 24px;
font-size: 16px;
margin-top: 10px;
}
#gallery .gallery-item {
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: transform 0.2s ease;
}
#gallery .gallery-item:hover {
transform: scale(1.05);
}
#input-row {
gap: 20px;
align-items: start;
}
"""
demo = gr.Blocks(css=custom_css, theme=gr.themes.Soft())
with demo:
gr.Markdown(
"""
## 🎨 Uni-Imaginator
**Create professional, e-commerce–ready product images effortlessly without worrying abot copyrights.**
"""
)
with gr.Row(elem_id="input-row"):
with gr.Column(scale=1):
input_image = gr.Image(
type="pil", label="Upload Product Image", elem_id="upload-img"
)
generate_button = gr.Button(
"Generate Images", variant="primary", elem_id="generate-button"
)
with gr.Column(scale=1):
gr.Markdown(
"""
**How to Use:**
1. Upload a clear photo of your product.
2. Click **Generate Images** and wait a few moments while images are processed within rate limits.
"""
)
gallery = gr.Gallery(
label="Generated Images",
elem_id="gallery",
columns=4,
object_fit="contain",
height="auto",
show_label=False
)
generate_button.click(
fn=generate_images,
inputs=[input_image],
outputs=gallery
)
return demo
# Launch the app
if __name__ == "__main__":
demo_app = build_interface()
demo_app.launch() |