File size: 9,968 Bytes
47283f8
 
 
 
 
 
 
047bc32
 
47283f8
 
 
 
bf74327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47283f8
 
 
 
 
 
 
 
 
 
 
 
bf74327
47283f8
bf74327
65f0832
 
bf74327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47283f8
bf74327
47283f8
bf74327
65f0832
 
bf74327
65f0832
47283f8
65f0832
 
 
 
 
 
bf74327
047bc32
47283f8
bf74327
65f0832
 
047bc32
 
65f0832
 
bf74327
 
 
 
 
 
 
 
047bc32
 
bf74327
47283f8
65f0832
 
bf74327
65f0832
 
047bc32
bf74327
65f0832
 
 
 
 
 
bf74327
47283f8
bf74327
 
47283f8
65f0832
 
bf74327
65f0832
 
 
 
47283f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f457b8d
47283f8
 
 
 
 
 
 
 
 
 
 
 
65f0832
47283f8
 
 
 
 
 
bf74327
 
 
 
047bc32
bf74327
 
 
 
 
 
47283f8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
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_to_imgur(image):
    """
    Upload image to Imgur and return URL
    Alternative: You can use other services like Cloudinary, imgbb, etc.
    """
    import base64
    import json
    
    # Convert PIL image to base64
    buffered = BytesIO()
    image.save(buffered, format="PNG")
    img_base64 = base64.b64encode(buffered.getvalue()).decode()
    
    # Imgur API (anonymous upload)
    headers = {
        'Authorization': 'Client-ID 0d90e8a3e7d8b4e'  # Public client ID for anonymous uploads
    }
    
    response = requests.post(
        'https://api.imgur.com/3/image',
        headers=headers,
        data={'image': img_base64}
    )
    
    if response.status_code == 200:
        data = response.json()
        return data['data']['link']
    else:
        raise Exception(f"Failed to upload to Imgur: {response.status_code}")

def process_images(prompt, image1, image2=None):
    """
    Process uploaded images with Replicate API
    """
    if not image1:
        return None, "Please upload at least one image"
    
    # Check if API token is set
    if not os.getenv('REPLICATE_API_TOKEN'):
        return None, "⚠️ Please set REPLICATE_API_TOKEN environment variable"
    
    try:
        status_message = "πŸ“€ Uploading images..."
        
        # Upload images to get public URLs
        image_urls = []
        
        try:
            # Try to upload to Imgur (or your preferred service)
            url1 = upload_to_imgur(image1)
            image_urls.append(url1)
            
            if image2:
                url2 = upload_to_imgur(image2)
                image_urls.append(url2)
                
        except Exception as upload_error:
            # Fallback: Convert to base64 data URIs
            buffered1 = BytesIO()
            image1.save(buffered1, format="PNG")
            img_base64_1 = base64.b64encode(buffered1.getvalue()).decode()
            image_urls.append(f"data:image/png;base64,{img_base64_1}")
            
            if image2:
                buffered2 = BytesIO()
                image2.save(buffered2, format="PNG")
                img_base64_2 = base64.b64encode(buffered2.getvalue()).decode()
                image_urls.append(f"data:image/png;base64,{img_base64_2}")
        
        status_message = "🎨 Processing with nano-banana model..."
        
        # Prepare input matching the exact format from your example
        input_data = {
            "prompt": prompt,
            "image_input": image_urls
        }
        
        # Run the model
        output = replicate.run(
            "google/nano-banana",
            input=input_data
        )
        
        # Handle various output formats
        output_url = None
        
        # Check different possible output formats
        if hasattr(output, 'url'):
            output_url = output.url()
        elif isinstance(output, str):
            output_url = output
        elif isinstance(output, list) and len(output) > 0:
            output_url = output[0]
        elif hasattr(output, '__iter__'):
            try:
                for item in output:
                    if isinstance(item, str) and item.startswith('http'):
                        output_url = item
                        break
            except:
                pass
        
        if not output_url:
            return None, f"❌ Error: No valid output URL found. Response type: {type(output)}"
        
        # Download the generated image
        if hasattr(output, 'read'):
            # If output has a read method, use it
            img_data = output.read()
            img = Image.open(BytesIO(img_data))
        else:
            # Otherwise, download from URL
            response = requests.get(output_url)
            if response.status_code == 200:
                img = Image.open(BytesIO(response.content))
            else:
                return None, f"❌ Error: Failed to download image (Status: {response.status_code})"
        
        return img, f"βœ… Image generated successfully! Output URL: {output_url[:50]}..."
        
    except replicate.exceptions.ModelError as e:
        return None, f"❌ Model Error: {str(e)}\n\nMake sure 'google/nano-banana' exists and is accessible."
    except Exception as e:
        error_msg = str(e)
        if "not found" in error_msg.lower():
            return None, "❌ Model 'google/nano-banana' not found. Please check:\n1. Model name is correct\n2. Model is public or you have access\n3. Try format: 'owner/model-name'"
        elif "authentication" in error_msg.lower():
            return None, "❌ Authentication failed. Please check your REPLICATE_API_TOKEN."
        else:
            return None, f"❌ Error: {error_msg}"

# Create Gradio interface with gradient theme
css = """
.gradio-container {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    font-family: 'Inter', sans-serif;
}
.gr-button {
    background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
    border: none;
    color: white;
    font-weight: bold;
    transition: transform 0.2s;
}
.gr-button:hover {
    transform: scale(1.05);
    box-shadow: 0 10px 20px rgba(0,0,0,0.2);
}
.gr-input {
    border-radius: 10px;
    border: 2px solid rgba(255,255,255,0.3);
    background: rgba(255,255,255,0.9);
}
.header-text {
    background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    font-size: 2.5em;
    font-weight: bold;
    text-align: center;
    margin-bottom: 20px;
}
.description-text {
    color: white;
    text-align: center;
    font-size: 1.1em;
    margin-bottom: 30px;
    text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
}
"""

# Build the Gradio interface
with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
    gr.HTML("""
        <div class="header-text">🎨 AI Image Style Transfer Studio</div>
        <div class="description-text">
            Upload 1-2 images and describe how you want them styled.
            The AI will create a beautiful transformation!
        </div>
    """)
    
    with gr.Row():
        with gr.Column(scale=1):
            gr.Markdown("### πŸ“€ Input Section")
            
            prompt = gr.Textbox(
                label="✏️ Style Prompt",
                placeholder="Describe how you want to style your images...",
                lines=3,
                value="Make the sheets in the style of the logo. Make the scene natural."
            )
            
            with gr.Row():
                image1 = gr.Image(
                    label="Image 1 (Required)",
                    type="pil",
                    height=200
                )
                image2 = gr.Image(
                    label="Image 2 (Optional)",
                    type="pil",
                    height=200
                )
            
            generate_btn = gr.Button(
                "πŸš€ Generate Styled Image",
                variant="primary",
                size="lg"
            )
            
            gr.Markdown("""
            #### πŸ’‘ Tips:
            - Upload high-quality images for best results
            - Be specific in your style description
            - Experiment with different prompts!
            """)
        
        with gr.Column(scale=1):
            gr.Markdown("### 🎯 Output Section")
            
            output_image = gr.Image(
                label="Generated Image",
                type="pil",
                height=400
            )
            
            status = gr.Textbox(
                label="Status",
                interactive=False,
                lines=2
            )
    
    # Examples section
    with gr.Row():
        gr.Examples(
            examples=[
                ["Transform into watercolor painting style", None, None],
                ["Make it look like a vintage photograph", None, None],
                ["Apply cyberpunk neon style", None, None],
                ["Convert to minimalist line art", None, None],
            ],
            inputs=[prompt, image1, image2],
            label="Example Prompts"
        )
    
    # Event handlers
    generate_btn.click(
        fn=process_images,
        inputs=[prompt, image1, image2],
        outputs=[output_image, status],
        api_name="generate"
    )
    
    # Additional information
    gr.Markdown("""
    ---
    ### βš™οΈ Setup Instructions:
    
    1. **Set Environment Variable:**
       ```bash
       export REPLICATE_API_TOKEN="your_api_token_here"
       ```
       Get your token from: https://replicate.com/account/api-tokens
    
    2. **Install Required Packages:**
       ```bash
       pip install gradio replicate pillow requests
       ```
    
    3. **Image Hosting Options:**
       - **Option A**: Uses Imgur for free image hosting (default)
       - **Option B**: Falls back to base64 data URIs if upload fails
       - **Option C**: Use your own image hosting service (Cloudinary, S3, etc.)
    
    4. **Model Notes:**
       - Using: `google/nano-banana` model
       - If this model doesn't exist, try:
         - `stability-ai/stable-diffusion`
         - `pharmapsychotic/clip-interrogator`
         - Check available models at: https://replicate.com/explore
    
    ### πŸ”’ Security:
    - API keys are managed through environment variables
    - Never commit API keys to version control
    - Consider implementing user authentication for production
    """)

# Launch the app
if __name__ == "__main__":
    demo.launch(
        share=True,
        server_name="0.0.0.0",
        server_port=7860,
        show_error=True
    )