openfree's picture
Update app.py
6bf068c verified
raw
history blame
14.4 kB
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 upscale_image(image):
"""
Upscale the generated image using Real-ESRGAN
"""
if not image:
return None, "Please generate an image first"
if not os.getenv('REPLICATE_API_TOKEN'):
return None, "Please set REPLICATE_API_TOKEN"
try:
# Upload image to hosting
image_url = upload_image_to_hosting(image)
# Run Real-ESRGAN model
output = replicate.run(
"nightmareai/real-esrgan:f121d640bd286e1fdc67f9799164c1d5be36ff74576ee11c803ae5b665dd46aa",
input={
"image": image_url,
"scale": 4 # 4x upscaling as default
}
)
if output is None:
return None, "No output received from upscaler"
# Get the upscaled image
try:
if hasattr(output, 'read'):
img_data = output.read()
img = Image.open(BytesIO(img_data))
return img, "๐Ÿ” Upscaled 4x 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, "๐Ÿ” Upscaled 4x 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, "๐Ÿ” Upscaled 4x successfully!"
return None, "Could not process upscaled output"
except Exception as e:
return None, f"Upscale error: {str(e)[:100]}"
def process_images(prompt, image1, image2=None):
"""
Process uploaded images with Replicate API
"""
if not image1:
return None, "Please upload at least one image", gr.update(visible=False)
if not os.getenv('REPLICATE_API_TOKEN'):
return None, "Please set REPLICATE_API_TOKEN", gr.update(visible=False)
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", gr.update(visible=False)
# Get the generated image
try:
if hasattr(output, 'read'):
img_data = output.read()
img = Image.open(BytesIO(img_data))
return img, "โœจ Generated successfully!", gr.update(visible=True)
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!", gr.update(visible=True)
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!", gr.update(visible=True)
return None, "Could not process output", gr.update(visible=False)
except Exception as e:
return None, f"Error: {str(e)[:100]}", gr.update(visible=False)
# 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-button-secondary {
background: linear-gradient(135deg, #74b9ff 0%, #0984e3 100%) !important;
border: none !important;
color: white !important;
font-weight: 600 !important;
font-size: 0.95rem !important;
padding: 0.8rem 1.5rem !important;
border-radius: 12px !important;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
}
.gr-button-secondary:hover {
transform: translateY(-2px) !important;
box-shadow: 0 10px 30px rgba(9, 132, 227, 0.3) !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("""
<h1 class="logo-text">๐ŸŒ Nano Banana Upscale(X4)</h1>
<p class="subtitle">AI-Powered Image Style Transfer</p>
<div style="display: flex; justify-content: center; align-items: center; gap: 10px; margin-top: 20px;">
<a href="https://huggingface.co/spaces/ginigen/Nano-Banana-PRO" target="_blank">
<img src="https://img.shields.io/static/v1?label=NANO%20BANANA&message=PRO&color=%230000ff&labelColor=%23800080&logo=HUGGINGFACE&logoColor=white&style=for-the-badge" alt="badge">
</a>
<a href="https://huggingface.co/spaces/openfree/Free-Nano-Banana" target="_blank">
<img src="https://img.shields.io/static/v1?label=NANO%20BANANA&message=FREE&color=%230000ff&labelColor=%23800080&logo=GOOGLE&logoColor=white&style=for-the-badge" alt="Free Nano Banana">
</a>
<a href="https://huggingface.co/spaces/aiqtech/Nano-Banana-API" target="_blank">
<img src="https://img.shields.io/static/v1?label=NANO%20BANANA&message=API&color=%230000ff&labelColor=%23800080&logo=GOOGLE&logoColor=white&style=for-the-badge" alt="Nano Banana API">
</a>
<a href="https://huggingface.co/spaces/ginigen/Nano-Banana-Video" target="_blank">
<img src="https://img.shields.io/static/v1?label=NANO%20BANANA&message=VIDEO&color=%230000ff&labelColor=%23800080&logo=GOOGLE&logoColor=white&style=for-the-badge" alt="Nano Banana VIDEO">
</a>
<a href="https://discord.gg/openfreeai" target="_blank">
<img src="https://img.shields.io/static/v1?label=Discord&message=Openfree%20AI&color=%230000ff&labelColor=%23800080&logo=discord&logoColor=white&style=for-the-badge" alt="Discord Openfree AI">
</a>
</div>
""")
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"
)
with gr.Row():
status = gr.Textbox(
label="Status",
interactive=False,
lines=1,
elem_classes="status-text",
value="Ready to generate...",
scale=3
)
upscale_btn = gr.Button(
"๐Ÿ” Upscale (4x)",
variant="secondary",
size="lg",
visible=False,
scale=1
)
# Event handlers
generate_btn.click(
fn=process_images,
inputs=[prompt, image1, image2],
outputs=[output_image, status, upscale_btn]
)
upscale_btn.click(
fn=upscale_image,
inputs=[output_image],
outputs=[output_image, status]
)
# Launch
if __name__ == "__main__":
demo.launch(
share=True,
server_name="0.0.0.0",
server_port=7860
)