aiqtech commited on
Commit
ccf2d49
·
verified ·
1 Parent(s): 0bd9c53

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -58
app.py CHANGED
@@ -96,6 +96,42 @@ def image_to_data_uri(image_path: str) -> str:
96
  data_uri = f"data:image/{img_format};base64,{img_base64}"
97
  return data_uri
98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
  def run_single_image_logic(prompt: str, image_path: Optional[str] = None, progress=gr.Progress()) -> str:
100
  """Handles text-to-image or single image-to-image using Replicate's Nano Banana."""
101
  try:
@@ -153,18 +189,20 @@ def run_multi_image_logic(prompt: str, images: List[str], progress=gr.Progress()
153
  try:
154
  progress(0.2, desc="🎨 Preparing images...")
155
 
156
- # Convert all images to data URI format
157
- data_uris = []
158
- for image_path in images:
159
  if isinstance(image_path, (list, tuple)):
160
  image_path = image_path[0]
161
- data_uri = image_to_data_uri(image_path)
162
- data_uris.append(data_uri)
 
 
163
 
164
  # Prepare input for Replicate API with multiple images
165
  input_data = {
166
  "prompt": prompt,
167
- "image_input": data_uris
168
  }
169
 
170
  progress(0.5, desc="✨ Generating...")
@@ -177,36 +215,9 @@ def run_multi_image_logic(prompt: str, images: List[str], progress=gr.Progress()
177
 
178
  progress(0.8, desc="🖼️ Finalizing...")
179
 
180
- # Handle the output - output is already a URL string or FileObject
181
  if output:
182
- # Check if output has a url attribute (FileObject)
183
- if hasattr(output, 'url'):
184
- # If url is a method, call it; if it's a property, just access it
185
- image_url = output.url() if callable(output.url) else output.url
186
- # If output is already a string URL
187
- elif isinstance(output, str):
188
- image_url = output
189
- # If output is a list of URLs
190
- elif isinstance(output, list) and len(output) > 0:
191
- # Check first item in list
192
- first_item = output[0]
193
- if hasattr(first_item, 'url'):
194
- image_url = first_item.url() if callable(first_item.url) else first_item.url
195
- else:
196
- image_url = first_item
197
- else:
198
- raise ValueError(f"Unexpected output format from Replicate: {type(output)}")
199
-
200
- # Download the image from URL
201
- response = requests.get(image_url)
202
- response.raise_for_status()
203
-
204
- # Save to temporary file
205
- img = Image.open(BytesIO(response.content))
206
- with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
207
- img.save(tmpfile.name)
208
- progress(1.0, desc="✅ Complete!")
209
- return tmpfile.name
210
  else:
211
  raise ValueError("No output received from Replicate API")
212
 
@@ -226,7 +237,6 @@ css = '''
226
  margin-bottom: 2rem;
227
  box-shadow: 0 10px 30px rgba(0,0,0,0.1);
228
  }
229
-
230
  .header-title {
231
  font-size: 2.5rem !important;
232
  font-weight: bold;
@@ -235,14 +245,12 @@ css = '''
235
  margin: 0 !important;
236
  text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
237
  }
238
-
239
  .header-subtitle {
240
  color: rgba(255,255,255,0.9);
241
  text-align: center;
242
  margin-top: 0.5rem !important;
243
  font-size: 1.1rem;
244
  }
245
-
246
  /* Card Styling */
247
  .card {
248
  background: white;
@@ -251,28 +259,23 @@ css = '''
251
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
252
  border: 1px solid rgba(0,0,0,0.05);
253
  }
254
-
255
  .dark .card {
256
  background: #1f2937;
257
  border: 1px solid #374151;
258
  }
259
-
260
  /* Tab Styling */
261
  .tabs {
262
  border-radius: 0.5rem;
263
  overflow: hidden;
264
  margin-bottom: 1rem;
265
  }
266
-
267
  .tabitem {
268
  padding: 1rem !important;
269
  }
270
-
271
  button.selected {
272
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
273
  color: white !important;
274
  }
275
-
276
  /* Button Styling */
277
  .generate-btn {
278
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
@@ -287,12 +290,10 @@ button.selected {
287
  width: 100% !important;
288
  margin-top: 1rem !important;
289
  }
290
-
291
  .generate-btn:hover {
292
  transform: translateY(-2px) !important;
293
  box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4) !important;
294
  }
295
-
296
  .use-btn {
297
  background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
298
  border: none !important;
@@ -304,12 +305,10 @@ button.selected {
304
  transition: all 0.3s ease !important;
305
  width: 100% !important;
306
  }
307
-
308
  .use-btn:hover {
309
  transform: translateY(-1px) !important;
310
  box-shadow: 0 5px 15px rgba(16, 185, 129, 0.4) !important;
311
  }
312
-
313
  /* Input Styling */
314
  .prompt-input textarea {
315
  border-radius: 0.5rem !important;
@@ -318,29 +317,24 @@ button.selected {
318
  font-size: 1rem !important;
319
  transition: border-color 0.3s ease !important;
320
  }
321
-
322
  .prompt-input textarea:focus {
323
  border-color: #667eea !important;
324
  outline: none !important;
325
  }
326
-
327
  .dark .prompt-input textarea {
328
  border-color: #374151 !important;
329
  background: #1f2937 !important;
330
  }
331
-
332
  /* Image Output Styling */
333
  #output {
334
  border-radius: 0.5rem !important;
335
  overflow: hidden !important;
336
  box-shadow: 0 4px 6px rgba(0,0,0,0.1) !important;
337
  }
338
-
339
  /* Progress Bar Styling */
340
  .progress-bar {
341
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
342
  }
343
-
344
  /* Examples Styling */
345
  .examples {
346
  background: #f9fafb;
@@ -348,11 +342,9 @@ button.selected {
348
  padding: 1rem;
349
  margin-top: 1rem;
350
  }
351
-
352
  .dark .examples {
353
  background: #1f2937;
354
  }
355
-
356
  /* Login Message Styling */
357
  .login-message {
358
  background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
@@ -361,23 +353,19 @@ button.selected {
361
  text-align: center;
362
  border: 2px solid #f59e0b;
363
  }
364
-
365
  .dark .login-message {
366
  background: linear-gradient(135deg, #7c2d12 0%, #92400e 100%);
367
  border-color: #f59e0b;
368
  }
369
-
370
  /* Emoji Animations */
371
  @keyframes bounce {
372
  0%, 100% { transform: translateY(0); }
373
  50% { transform: translateY(-10px); }
374
  }
375
-
376
  .emoji-icon {
377
  display: inline-block;
378
  animation: bounce 2s infinite;
379
  }
380
-
381
  /* Responsive Design */
382
  @media (max-width: 768px) {
383
  .header-title {
 
96
  data_uri = f"data:image/{img_format};base64,{img_base64}"
97
  return data_uri
98
 
99
+ def process_output(output, progress=gr.Progress()) -> str:
100
+ """Process the output from Replicate API and return a local file path."""
101
+ try:
102
+ # Check if output has a url attribute (FileObject)
103
+ if hasattr(output, 'url'):
104
+ # If url is a method, call it; if it's a property, just access it
105
+ image_url = output.url() if callable(output.url) else output.url
106
+ # If output is already a string URL
107
+ elif isinstance(output, str):
108
+ image_url = output
109
+ # If output is a list of URLs
110
+ elif isinstance(output, list) and len(output) > 0:
111
+ # Check first item in list
112
+ first_item = output[0]
113
+ if hasattr(first_item, 'url'):
114
+ image_url = first_item.url() if callable(first_item.url) else first_item.url
115
+ else:
116
+ image_url = first_item
117
+ else:
118
+ raise ValueError(f"Unexpected output format from Replicate: {type(output)}")
119
+
120
+ # Download the image from URL
121
+ response = requests.get(image_url)
122
+ response.raise_for_status()
123
+
124
+ # Save to temporary file
125
+ img = Image.open(BytesIO(response.content))
126
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as tmpfile:
127
+ img.save(tmpfile.name)
128
+ progress(1.0, desc="✅ Complete!")
129
+ return tmpfile.name
130
+
131
+ except Exception as e:
132
+ print(f"Error processing output: {e}")
133
+ raise ValueError(f"Failed to process output: {str(e)}")
134
+
135
  def run_single_image_logic(prompt: str, image_path: Optional[str] = None, progress=gr.Progress()) -> str:
136
  """Handles text-to-image or single image-to-image using Replicate's Nano Banana."""
137
  try:
 
189
  try:
190
  progress(0.2, desc="🎨 Preparing images...")
191
 
192
+ # Upload all images to get proper URLs
193
+ image_urls = []
194
+ for idx, image_path in enumerate(images):
195
  if isinstance(image_path, (list, tuple)):
196
  image_path = image_path[0]
197
+
198
+ progress(0.2 + (0.2 * idx / len(images)), desc=f"📤 Uploading image {idx+1}/{len(images)}...")
199
+ image_url = upload_image_to_hosting(image_path)
200
+ image_urls.append(image_url)
201
 
202
  # Prepare input for Replicate API with multiple images
203
  input_data = {
204
  "prompt": prompt,
205
+ "image_input": image_urls
206
  }
207
 
208
  progress(0.5, desc="✨ Generating...")
 
215
 
216
  progress(0.8, desc="🖼️ Finalizing...")
217
 
218
+ # Handle the output using the process_output function
219
  if output:
220
+ return process_output(output, progress)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  else:
222
  raise ValueError("No output received from Replicate API")
223
 
 
237
  margin-bottom: 2rem;
238
  box-shadow: 0 10px 30px rgba(0,0,0,0.1);
239
  }
 
240
  .header-title {
241
  font-size: 2.5rem !important;
242
  font-weight: bold;
 
245
  margin: 0 !important;
246
  text-shadow: 2px 2px 4px rgba(0,0,0,0.2);
247
  }
 
248
  .header-subtitle {
249
  color: rgba(255,255,255,0.9);
250
  text-align: center;
251
  margin-top: 0.5rem !important;
252
  font-size: 1.1rem;
253
  }
 
254
  /* Card Styling */
255
  .card {
256
  background: white;
 
259
  box-shadow: 0 4px 6px rgba(0,0,0,0.1);
260
  border: 1px solid rgba(0,0,0,0.05);
261
  }
 
262
  .dark .card {
263
  background: #1f2937;
264
  border: 1px solid #374151;
265
  }
 
266
  /* Tab Styling */
267
  .tabs {
268
  border-radius: 0.5rem;
269
  overflow: hidden;
270
  margin-bottom: 1rem;
271
  }
 
272
  .tabitem {
273
  padding: 1rem !important;
274
  }
 
275
  button.selected {
276
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
277
  color: white !important;
278
  }
 
279
  /* Button Styling */
280
  .generate-btn {
281
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
 
290
  width: 100% !important;
291
  margin-top: 1rem !important;
292
  }
 
293
  .generate-btn:hover {
294
  transform: translateY(-2px) !important;
295
  box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4) !important;
296
  }
 
297
  .use-btn {
298
  background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
299
  border: none !important;
 
305
  transition: all 0.3s ease !important;
306
  width: 100% !important;
307
  }
 
308
  .use-btn:hover {
309
  transform: translateY(-1px) !important;
310
  box-shadow: 0 5px 15px rgba(16, 185, 129, 0.4) !important;
311
  }
 
312
  /* Input Styling */
313
  .prompt-input textarea {
314
  border-radius: 0.5rem !important;
 
317
  font-size: 1rem !important;
318
  transition: border-color 0.3s ease !important;
319
  }
 
320
  .prompt-input textarea:focus {
321
  border-color: #667eea !important;
322
  outline: none !important;
323
  }
 
324
  .dark .prompt-input textarea {
325
  border-color: #374151 !important;
326
  background: #1f2937 !important;
327
  }
 
328
  /* Image Output Styling */
329
  #output {
330
  border-radius: 0.5rem !important;
331
  overflow: hidden !important;
332
  box-shadow: 0 4px 6px rgba(0,0,0,0.1) !important;
333
  }
 
334
  /* Progress Bar Styling */
335
  .progress-bar {
336
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
337
  }
 
338
  /* Examples Styling */
339
  .examples {
340
  background: #f9fafb;
 
342
  padding: 1rem;
343
  margin-top: 1rem;
344
  }
 
345
  .dark .examples {
346
  background: #1f2937;
347
  }
 
348
  /* Login Message Styling */
349
  .login-message {
350
  background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
 
353
  text-align: center;
354
  border: 2px solid #f59e0b;
355
  }
 
356
  .dark .login-message {
357
  background: linear-gradient(135deg, #7c2d12 0%, #92400e 100%);
358
  border-color: #f59e0b;
359
  }
 
360
  /* Emoji Animations */
361
  @keyframes bounce {
362
  0%, 100% { transform: translateY(0); }
363
  50% { transform: translateY(-10px); }
364
  }
 
365
  .emoji-icon {
366
  display: inline-block;
367
  animation: bounce 2s infinite;
368
  }
 
369
  /* Responsive Design */
370
  @media (max-width: 768px) {
371
  .header-title {