import gradio as gr import replicate import os from PIL import Image import requests from io import BytesIO import time import tempfile import base64 # Set up Replicate API key from environment variable os.environ['REPLICATE_API_TOKEN'] = os.getenv('REPLICATE_API_TOKEN') def upload_image_to_hosting(image): """ Upload image to multiple hosting services with fallback """ # Method 1: Try imgbb.com (most reliable) try: buffered = BytesIO() image.save(buffered, format="PNG") buffered.seek(0) img_base64 = base64.b64encode(buffered.getvalue()).decode() response = requests.post( "https://api.imgbb.com/1/upload", data={ 'key': '6d207e02198a847aa98d0a2a901485a5', 'image': img_base64, } ) if response.status_code == 200: data = response.json() if data.get('success'): return data['data']['url'] except: pass # Method 2: Try 0x0.st (simple and reliable) try: buffered = BytesIO() image.save(buffered, format="PNG") buffered.seek(0) files = {'file': ('image.png', buffered, 'image/png')} response = requests.post("https://0x0.st", files=files) if response.status_code == 200: return response.text.strip() except: pass # Method 3: Fallback to base64 buffered = BytesIO() image.save(buffered, format="PNG") buffered.seek(0) img_base64 = base64.b64encode(buffered.getvalue()).decode() return f"data:image/png;base64,{img_base64}" def process_images(prompt, image1, image2=None): """ Process uploaded images with Replicate API """ if not image1: return None, "Please upload at least one image" if not os.getenv('REPLICATE_API_TOKEN'): return None, "Please set REPLICATE_API_TOKEN" try: image_urls = [] # Upload images url1 = upload_image_to_hosting(image1) image_urls.append(url1) if image2: url2 = upload_image_to_hosting(image2) image_urls.append(url2) # Run the model output = replicate.run( "google/nano-banana", input={ "prompt": prompt, "image_input": image_urls } ) if output is None: return None, "No output received" # Get the generated image try: if hasattr(output, 'read'): img_data = output.read() img = Image.open(BytesIO(img_data)) return img, "✨ Generated successfully!" except: pass try: if hasattr(output, 'url'): output_url = output.url() response = requests.get(output_url, timeout=30) if response.status_code == 200: img = Image.open(BytesIO(response.content)) return img, "✨ Generated successfully!" except: pass output_url = None if isinstance(output, str): output_url = output elif isinstance(output, list) and len(output) > 0: output_url = output[0] if output_url: response = requests.get(output_url, timeout=30) if response.status_code == 200: img = Image.open(BytesIO(response.content)) return img, "✨ Generated successfully!" return None, "Could not process output" except Exception as e: return None, f"Error: {str(e)[:100]}" # Enhanced CSS with modern, minimal design css = """ .gradio-container { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; min-height: 100vh; } .header-container { background: linear-gradient(135deg, #ffd93d 0%, #ffb347 100%); padding: 2.5rem; border-radius: 24px; margin-bottom: 2.5rem; box-shadow: 0 20px 60px rgba(255, 179, 71, 0.25); } .logo-text { font-size: 3.5rem; font-weight: 900; color: #2d3436; text-align: center; margin: 0; letter-spacing: -2px; } .subtitle { color: #2d3436; text-align: center; font-size: 1rem; margin-top: 0.5rem; opacity: 0.8; } .main-content { background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(20px); border-radius: 24px; padding: 2.5rem; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08); } .gr-button-primary { background: linear-gradient(135deg, #ffd93d 0%, #ffb347 100%) !important; border: none !important; color: #2d3436 !important; font-weight: 700 !important; font-size: 1.1rem !important; padding: 1.2rem 2rem !important; border-radius: 14px !important; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; text-transform: uppercase; letter-spacing: 1px; width: 100%; margin-top: 1rem !important; } .gr-button-primary:hover { transform: translateY(-3px) !important; box-shadow: 0 15px 40px rgba(255, 179, 71, 0.35) !important; } .gr-input, .gr-textarea { background: #ffffff !important; border: 2px solid #e1e8ed !important; border-radius: 14px !important; color: #2d3436 !important; font-size: 1rem !important; padding: 0.8rem 1rem !important; } .gr-input:focus, .gr-textarea:focus { border-color: #ffd93d !important; box-shadow: 0 0 0 4px rgba(255, 217, 61, 0.15) !important; } .gr-form { background: transparent !important; border: none !important; } .gr-panel { background: #ffffff !important; border: 2px solid #e1e8ed !important; border-radius: 16px !important; padding: 1.5rem !important; } .gr-box { border-radius: 14px !important; border-color: #e1e8ed !important; } label { color: #636e72 !important; font-weight: 600 !important; font-size: 0.85rem !important; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 0.5rem !important; } .status-text { font-family: 'SF Mono', 'Monaco', monospace; color: #00b894; font-size: 0.9rem; } .image-container { border-radius: 14px !important; overflow: hidden; border: 2px solid #e1e8ed !important; background: #fafbfc !important; } footer { display: none !important; } /* Equal sizing for all image containers */ .image-upload { min-height: 200px !important; max-height: 200px !important; } .output-image { min-height: 420px !important; max-height: 420px !important; } /* Ensure consistent spacing */ .gr-row { gap: 1rem !important; } .gr-column { gap: 1rem !important; } """ with gr.Blocks(css=css, theme=gr.themes.Base()) as demo: with gr.Column(elem_classes="header-container"): gr.HTML("""
AI-Powered Image Style Transfer
""") with gr.Column(elem_classes="main-content"): with gr.Row(equal_height=True): # Left Column - Inputs with gr.Column(scale=1): prompt = gr.Textbox( label="Style Description", placeholder="Describe your style...", lines=3, value="Make the sheets in the style of the logo. Make the scene natural.", elem_classes="prompt-input" ) with gr.Row(equal_height=True): image1 = gr.Image( label="Primary Image", type="pil", height=200, elem_classes="image-container image-upload" ) image2 = gr.Image( label="Secondary Image", type="pil", height=200, elem_classes="image-container image-upload" ) generate_btn = gr.Button( "Generate Magic ✨", variant="primary", size="lg" ) # Right Column - Output with gr.Column(scale=1): output_image = gr.Image( label="Generated Result", type="pil", height=420, elem_classes="image-container output-image" ) status = gr.Textbox( label="Status", interactive=False, lines=1, elem_classes="status-text", value="Ready to generate..." ) # Event handler generate_btn.click( fn=process_images, inputs=[prompt, image1, image2], outputs=[output_image, status] ) # Launch if __name__ == "__main__": demo.launch( share=True, server_name="0.0.0.0", server_port=7860 )