Spaces:
Running
Running
Update app.py
Browse files
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 |
-
|
|
|
131 |
else:
|
132 |
-
|
|
|
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,
|
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"
|
178 |
-
|
|
|
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
|
199 |
-
if
|
200 |
-
#
|
201 |
-
|
202 |
-
|
203 |
-
# Convert PIL
|
204 |
-
progress(0.1, desc="
|
205 |
-
|
206 |
-
|
207 |
-
|
|
|
|
|
208 |
img.save(buffered, format="PNG")
|
209 |
-
image_base64 = base64.b64encode(buffered.getvalue()).decode()
|
210 |
else:
|
211 |
-
buffered =
|
212 |
-
|
213 |
-
|
214 |
|
215 |
-
#
|
216 |
-
|
217 |
-
|
|
|
|
|
|
|
|
|
218 |
|
219 |
payload = {
|
220 |
"duration": 5,
|
221 |
-
"image":
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
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
|
447 |
-
- **Image to Video**: Transform
|
448 |
-
|
|
|
|
|
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 |
-
["
|
474 |
],
|
475 |
-
inputs=[mode, prompt,
|
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=[
|
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,
|
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 |
|