ginipick commited on
Commit
a8b22a6
Β·
verified Β·
1 Parent(s): 989bf3e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +85 -42
app.py CHANGED
@@ -127,9 +127,11 @@ def update_prompt_placeholder(mode):
127
  def update_image_input(mode):
128
  """Show/hide image input based on mode"""
129
  if mode == "Image to Video":
130
- return gr.update(visible=True)
 
131
  else:
132
- return gr.update(visible=False)
 
133
 
134
  def poll_for_result(request_id, api_key, progress_callback=None):
135
  """Poll WaveSpeed API for video generation result"""
@@ -167,15 +169,16 @@ def poll_for_result(request_id, api_key, progress_callback=None):
167
  except Exception as e:
168
  return False, f"Connection error: {str(e)}"
169
 
170
- def generate_video(mode, prompt, image, aspect_ratio, seed, api_key_override_t2v, api_key_override_i2v, progress=gr.Progress()):
171
  """Main video generation function using WaveSpeed API"""
172
 
173
  # Input validation
174
  if not prompt:
175
  return None, "❌ Please enter a prompt."
176
 
177
- if mode == "Image to Video" and image is None:
178
- return None, "❌ Please upload an image."
 
179
 
180
  try:
181
  progress(0, desc="Preparing request...")
@@ -195,30 +198,35 @@ def generate_video(mode, prompt, image, aspect_ratio, seed, api_key_override_t2v
195
  api_key = api_key_override_i2v or API_KEY_I2V
196
  endpoint = I2V_ENDPOINT
197
 
198
- # Handle image upload
199
- if isinstance(image, str) and (image.startswith('http://') or image.startswith('https://')):
200
- # If it's already a URL
201
- image_url = image
202
- else:
203
- # Convert PIL Image to base64 for upload
204
- progress(0.1, desc="Processing image...")
205
- if isinstance(image, str):
206
- with Image.open(image) as img:
207
- buffered = io.BytesIO()
 
 
208
  img.save(buffered, format="PNG")
209
- image_base64 = base64.b64encode(buffered.getvalue()).decode()
210
  else:
211
- buffered = io.BytesIO()
212
- image.save(buffered, format="PNG")
213
- image_base64 = base64.b64encode(buffered.getvalue()).decode()
214
 
215
- # For this demo, we'll assume the image needs to be uploaded somewhere
216
- # In production, you'd upload to a CDN and get a URL
217
- return None, "❌ Image upload to CDN not implemented. Please use an image URL."
 
 
 
 
218
 
219
  payload = {
220
  "duration": 5,
221
- "image": image_url,
222
  "prompt": prompt,
223
  "seed": seed if seed >= 0 else -1
224
  }
@@ -238,7 +246,21 @@ def generate_video(mode, prompt, image, aspect_ratio, seed, api_key_override_t2v
238
  request_id = result["id"]
239
  progress(0.3, desc=f"Request submitted. ID: {request_id}")
240
  else:
241
- return None, f"❌ API Error: {response.status_code} - {response.text}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
  # Poll for result
244
  success, result = poll_for_result(request_id, api_key, lambda p, desc: progress(p, desc=desc))
@@ -355,19 +377,28 @@ with gr.Blocks(title="Bytedance Seedance Video Free", theme=gr.themes.Soft()) as
355
  value="Text to Video"
356
  )
357
 
358
- # Image upload
359
- image_input = gr.Image(
360
- label="πŸ“· Upload Image or Provide URL",
361
- type="pil",
362
- visible=False
363
- )
 
 
 
 
 
 
 
 
364
 
365
  # Aspect ratio (only for T2V)
366
  aspect_ratio = gr.Dropdown(
367
- label="πŸ“ Aspect Ratio",
368
  choices=list(ASPECT_RATIOS.keys()),
369
  value="16:9",
370
- info="Choose ratio optimized for social media platforms"
 
371
  )
372
 
373
  # Ratio description
@@ -443,12 +474,24 @@ with gr.Blocks(title="Bytedance Seedance Video Free", theme=gr.themes.Soft()) as
443
 
444
  ### Features
445
 
446
- - **Text to Video**: Generate video from text description only
447
- - **Image to Video**: Transform uploaded image into animated video (requires image URL)
448
- - **Aspect Ratios**: Choose ratios optimized for various social media platforms
 
 
449
  - **Seed Value**: Use -1 for random or set specific value for reproducible results
450
  - **Watermark**: Automatically adds "ginigen.com" watermark (requires opencv-python)
451
 
 
 
 
 
 
 
 
 
 
 
452
  ### API Information
453
 
454
  - **Provider**: WaveSpeed AI
@@ -467,12 +510,12 @@ with gr.Blocks(title="Bytedance Seedance Video Free", theme=gr.themes.Soft()) as
467
  # Examples
468
  gr.Examples(
469
  examples=[
470
- ["Text to Video", "A cat walking gracefully across a sunlit room", None, "16:9", -1],
471
- ["Text to Video", "A serene lake at sunrise with mist rolling over the water. Camera slowly pans across the landscape as birds fly overhead.", None, "16:9", 42],
472
- ["Text to Video", "Urban street scene at night with neon lights reflecting on wet pavement. People walking with umbrellas, camera tracking forward.", None, "9:16", 123],
473
- ["Text to Video", "Close-up of a flower blooming in time-lapse, soft natural lighting, shallow depth of field.", None, "1:1", 789],
474
  ],
475
- inputs=[mode, prompt, image_input, aspect_ratio, seed],
476
  label="Example Prompts"
477
  )
478
 
@@ -486,7 +529,7 @@ with gr.Blocks(title="Bytedance Seedance Video Free", theme=gr.themes.Soft()) as
486
  mode.change(
487
  fn=update_image_input,
488
  inputs=[mode],
489
- outputs=[image_input]
490
  )
491
 
492
  aspect_ratio.change(
@@ -497,7 +540,7 @@ with gr.Blocks(title="Bytedance Seedance Video Free", theme=gr.themes.Soft()) as
497
 
498
  generate_btn.click(
499
  fn=generate_video,
500
- inputs=[mode, prompt, image_input, aspect_ratio, seed, api_key_override_t2v, api_key_override_i2v],
501
  outputs=[output_video, output_info]
502
  )
503
 
 
127
  def update_image_input(mode):
128
  """Show/hide image input based on mode"""
129
  if mode == "Image to Video":
130
+ # Show image input, hide aspect ratio for I2V
131
+ return gr.update(visible=True), gr.update(visible=False)
132
  else:
133
+ # Hide image input, show aspect ratio for T2V
134
+ return gr.update(visible=False), gr.update(visible=True)
135
 
136
  def poll_for_result(request_id, api_key, progress_callback=None):
137
  """Poll WaveSpeed API for video generation result"""
 
169
  except Exception as e:
170
  return False, f"Connection error: {str(e)}"
171
 
172
+ def generate_video(mode, prompt, image_url, image_file, aspect_ratio, seed, api_key_override_t2v, api_key_override_i2v, progress=gr.Progress()):
173
  """Main video generation function using WaveSpeed API"""
174
 
175
  # Input validation
176
  if not prompt:
177
  return None, "❌ Please enter a prompt."
178
 
179
+ if mode == "Image to Video":
180
+ if not image_url and image_file is None:
181
+ return None, "❌ Please provide an image URL or upload an image."
182
 
183
  try:
184
  progress(0, desc="Preparing request...")
 
198
  api_key = api_key_override_i2v or API_KEY_I2V
199
  endpoint = I2V_ENDPOINT
200
 
201
+ # Handle image input
202
+ if image_url:
203
+ # Use provided URL directly
204
+ final_image_url = image_url
205
+ elif image_file is not None:
206
+ # Convert PIL image to data URL
207
+ progress(0.1, desc="Converting image to data URL...")
208
+
209
+ # Convert to base64
210
+ buffered = io.BytesIO()
211
+ if isinstance(image_file, str):
212
+ with Image.open(image_file) as img:
213
  img.save(buffered, format="PNG")
 
214
  else:
215
+ image_file.save(buffered, format="PNG")
216
+
217
+ image_base64 = base64.b64encode(buffered.getvalue()).decode()
218
 
219
+ # Try data URL format first
220
+ final_image_url = f"data:image/png;base64,{image_base64}"
221
+
222
+ # Note: If the API doesn't accept data URLs, you'll need to upload to a CDN
223
+ # For now, we'll try the data URL and provide guidance if it fails
224
+ else:
225
+ return None, "❌ No image provided."
226
 
227
  payload = {
228
  "duration": 5,
229
+ "image": final_image_url,
230
  "prompt": prompt,
231
  "seed": seed if seed >= 0 else -1
232
  }
 
246
  request_id = result["id"]
247
  progress(0.3, desc=f"Request submitted. ID: {request_id}")
248
  else:
249
+ error_detail = response.text
250
+ if mode == "Image to Video" and image_file is not None and not image_url:
251
+ return None, f"""❌ API Error: {response.status_code}
252
+
253
+ The API may not accept base64 data URLs. Please try one of these options:
254
+ 1. Use a direct image URL (e.g., https://example.com/image.jpg)
255
+ 2. Upload your image to an image hosting service like:
256
+ - imgur.com
257
+ - imgbb.com
258
+ - postimages.org
259
+ 3. Use the image URL in the Image URL field
260
+
261
+ Error details: {error_detail}"""
262
+ else:
263
+ return None, f"❌ API Error: {response.status_code} - {error_detail}"
264
 
265
  # Poll for result
266
  success, result = poll_for_result(request_id, api_key, lambda p, desc: progress(p, desc=desc))
 
377
  value="Text to Video"
378
  )
379
 
380
+ # Image input - URL or file
381
+ with gr.Column(visible=False) as image_input_group:
382
+ gr.Markdown("### Image Input")
383
+ image_url_input = gr.Textbox(
384
+ label="πŸ“· Image URL",
385
+ placeholder="https://example.com/image.jpg",
386
+ info="Enter a direct image URL"
387
+ )
388
+ gr.Markdown("**OR**")
389
+ image_file_input = gr.Image(
390
+ label="πŸ“€ Upload Image (Beta)",
391
+ type="pil",
392
+ info="Note: Uploaded images will be converted to data URL (may not work with all APIs)"
393
+ )
394
 
395
  # Aspect ratio (only for T2V)
396
  aspect_ratio = gr.Dropdown(
397
+ label="πŸ“ Aspect Ratio (Text to Video only)",
398
  choices=list(ASPECT_RATIOS.keys()),
399
  value="16:9",
400
+ info="Choose ratio optimized for social media platforms",
401
+ visible=True
402
  )
403
 
404
  # Ratio description
 
474
 
475
  ### Features
476
 
477
+ - **Text to Video**: Generate video from text description with aspect ratio selection
478
+ - **Image to Video**: Transform image into animated video
479
+ - Option 1: Provide direct image URL (recommended)
480
+ - Option 2: Upload image file (converted to data URL - may not work)
481
+ - **Aspect Ratios**: Available for Text to Video only
482
  - **Seed Value**: Use -1 for random or set specific value for reproducible results
483
  - **Watermark**: Automatically adds "ginigen.com" watermark (requires opencv-python)
484
 
485
+ ### Image to Video Tips
486
+
487
+ For best results with Image to Video:
488
+ 1. Use direct image URLs (https://...)
489
+ 2. If uploading files doesn't work, upload your image to:
490
+ - [imgur.com](https://imgur.com)
491
+ - [imgbb.com](https://imgbb.com)
492
+ - [postimages.org](https://postimages.org)
493
+ 3. Copy the direct image URL and paste it in the Image URL field
494
+
495
  ### API Information
496
 
497
  - **Provider**: WaveSpeed AI
 
510
  # Examples
511
  gr.Examples(
512
  examples=[
513
+ ["Text to Video", "A cat walking gracefully across a sunlit room", "", None, "16:9", -1],
514
+ ["Text to Video", "A serene lake at sunrise with mist rolling over the water. Camera slowly pans across the landscape as birds fly overhead.", "", None, "16:9", 42],
515
+ ["Text to Video", "Urban street scene at night with neon lights reflecting on wet pavement. People walking with umbrellas, camera tracking forward.", "", None, "9:16", 123],
516
+ ["Image to Video", "The camera slowly zooms in while clouds drift across the sky", "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", None, "16:9", -1],
517
  ],
518
+ inputs=[mode, prompt, image_url_input, image_file_input, aspect_ratio, seed],
519
  label="Example Prompts"
520
  )
521
 
 
529
  mode.change(
530
  fn=update_image_input,
531
  inputs=[mode],
532
+ outputs=[image_input_group, aspect_ratio]
533
  )
534
 
535
  aspect_ratio.change(
 
540
 
541
  generate_btn.click(
542
  fn=generate_video,
543
+ inputs=[mode, prompt, image_url_input, image_file_input, aspect_ratio, seed, api_key_override_t2v, api_key_override_i2v],
544
  outputs=[output_video, output_info]
545
  )
546