Spaces:
Running
Running
#!/usr/bin/env python3 | |
""" | |
AI Video Generator with Gradio | |
Single file application - app.py | |
""" | |
import os | |
import gradio as gr | |
import replicate | |
import base64 | |
from PIL import Image | |
import io | |
import requests | |
from datetime import datetime | |
import tempfile | |
# API token setup | |
api_token = os.getenv("RAPI_TOKEN") | |
if api_token: | |
os.environ["REPLICATE_API_TOKEN"] = api_token | |
# Aspect ratio options | |
ASPECT_RATIOS = { | |
"16:9": "16:9 (YouTube, Standard Video)", | |
"4:3": "4:3 (Traditional TV Format)", | |
"1:1": "1:1 (Instagram Feed)", | |
"3:4": "3:4 (Instagram Portrait)", | |
"9:16": "9:16 (Instagram Reels, TikTok)", | |
"21:9": "21:9 (Cinematic Wide)", | |
"9:21": "9:21 (Ultra Vertical)" | |
} | |
def update_prompt_placeholder(mode): | |
"""Update prompt placeholder based on mode""" | |
if mode == "Text to Video": | |
return gr.update(placeholder="Describe the video you want to create.\nExample: The sun rises slowly between tall buildings. [Ground-level follow shot] Bicycle tires roll over a dew-covered street at dawn.") | |
else: | |
return gr.update(placeholder="Describe how the image should move.\nExample: Camera slowly zooms in while clouds move across the sky. The subject's hair gently moves in the wind.") | |
def update_image_input(mode): | |
"""Show/hide image input based on mode""" | |
if mode == "Image to Video": | |
return gr.update(visible=True) | |
else: | |
return gr.update(visible=False) | |
def generate_video(mode, prompt, image, aspect_ratio, seed, api_key_input, progress=gr.Progress()): | |
"""Main video generation function""" | |
# API token check | |
token = api_key_input or api_token | |
if not token: | |
return None, "β API token required. Please set RAPI_TOKEN environment variable or enter your API key." | |
os.environ["REPLICATE_API_TOKEN"] = token | |
# Input validation | |
if not prompt: | |
return None, "β Please enter a prompt." | |
if mode == "Image to Video" and image is None: | |
return None, "β Please upload an image." | |
try: | |
progress(0, desc="Preparing video generation...") | |
# Input parameters setup | |
input_params = { | |
"prompt": prompt, | |
"duration": 5, | |
"resolution": "480p", | |
"aspect_ratio": aspect_ratio, | |
"seed": seed | |
} | |
# Image to video mode | |
if mode == "Image to Video" and image is not None: | |
progress(0.1, desc="Processing image...") | |
# Convert PIL Image to base64 | |
if isinstance(image, str): # File path | |
with Image.open(image) as img: | |
buffered = io.BytesIO() | |
img.save(buffered, format="PNG") | |
image_base64 = base64.b64encode(buffered.getvalue()).decode() | |
else: # PIL Image object | |
buffered = io.BytesIO() | |
image.save(buffered, format="PNG") | |
image_base64 = base64.b64encode(buffered.getvalue()).decode() | |
input_params["image"] = f"data:image/png;base64,{image_base64}" | |
progress(0.3, desc="Calling Replicate API...") | |
# Run Replicate | |
output = replicate.run( | |
"bytedance/seedance-1-lite", | |
input=input_params | |
) | |
progress(0.7, desc="Downloading video...") | |
# Get video data | |
if hasattr(output, 'read'): | |
video_data = output.read() | |
else: | |
# Download from URL | |
response = requests.get(output) | |
video_data = response.content | |
# Save to temporary file | |
with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4') as tmp_file: | |
tmp_file.write(video_data) | |
video_path = tmp_file.name | |
# Also save as output.mp4 | |
with open("output.mp4", "wb") as file: | |
file.write(video_data) | |
progress(1.0, desc="Complete!") | |
# Generation info | |
info = f"""β Video generated successfully! | |
π Generation Info: | |
- Mode: {mode} | |
- Aspect Ratio: {aspect_ratio} | |
- Seed: {seed} | |
- Duration: 5 seconds | |
- Resolution: 480p | |
- File: output.mp4""" | |
return video_path, info | |
except Exception as e: | |
error_msg = f"β Error occurred: {str(e)}" | |
return None, error_msg | |
# Gradio interface | |
with gr.Blocks(title="Bytedance Seedance Video Free", theme=gr.themes.Soft()) as app: | |
gr.Markdown(""" | |
# π¬ Bytedance Seedance Video' Free | |
Generate videos from text or images using **Replicate API**. | |
[](https://ginigen.com/) | |
""") | |
with gr.Row(): | |
with gr.Column(scale=1): | |
# API Settings | |
with gr.Accordion("βοΈ API Settings", open=not bool(api_token)): | |
if api_token: | |
gr.Markdown("β API token loaded from environment variable.") | |
api_key_input = gr.Textbox( | |
label="Replicate API Token (Optional)", | |
type="password", | |
placeholder="Enter to override environment variable", | |
value="" | |
) | |
else: | |
gr.Markdown("β οΈ RAPI_TOKEN environment variable not set.") | |
api_key_input = gr.Textbox( | |
label="Replicate API Token (Required)", | |
type="password", | |
placeholder="Enter your Replicate API token", | |
value="" | |
) | |
# Generation mode | |
mode = gr.Radio( | |
label="π― Generation Mode", | |
choices=["Text to Video", "Image to Video"], | |
value="Text to Video" | |
) | |
# Image upload | |
image_input = gr.Image( | |
label="π· Upload Image", | |
type="pil", | |
visible=False | |
) | |
# Aspect ratio | |
aspect_ratio = gr.Dropdown( | |
label="π Aspect Ratio", | |
choices=list(ASPECT_RATIOS.keys()), | |
value="16:9", | |
info="Choose ratio optimized for social media platforms" | |
) | |
# Ratio description | |
ratio_info = gr.Markdown(value=f"Selected ratio: {ASPECT_RATIOS['16:9']}") | |
# Seed setting | |
seed = gr.Number( | |
label="π² Random Seed", | |
value=42, | |
precision=0, | |
info="Use same seed value to reproduce same results" | |
) | |
# Fixed settings display | |
gr.Markdown(""" | |
### π Fixed Settings | |
- **Duration**: 5 seconds | |
- **Resolution**: 480p | |
""") | |
with gr.Column(scale=2): | |
# Prompt input | |
prompt = gr.Textbox( | |
label="βοΈ Prompt", | |
lines=5, | |
placeholder="Describe the video you want to create.\nExample: The sun rises slowly between tall buildings. [Ground-level follow shot] Bicycle tires roll over a dew-covered street at dawn." | |
) | |
# Generate button | |
generate_btn = gr.Button("π¬ Generate Video", variant="primary", size="lg") | |
# Results display | |
with gr.Column(): | |
output_video = gr.Video( | |
label="πΉ Generated Video", | |
autoplay=True | |
) | |
output_info = gr.Textbox( | |
label="Information", | |
lines=8, | |
interactive=False | |
) | |
# Usage instructions | |
with gr.Accordion("π How to Use", open=False): | |
gr.Markdown(""" | |
### Installation | |
1. **Install required packages**: | |
```bash | |
pip install gradio replicate pillow requests | |
``` | |
2. **Set environment variable** (optional): | |
```bash | |
export RAPI_TOKEN="your-replicate-api-token" | |
``` | |
3. **Run**: | |
```bash | |
python app.py | |
``` | |
### Features | |
- **Text to Video**: Generate video from text description only | |
- **Image to Video**: Transform uploaded image into animated video | |
- **Aspect Ratios**: Choose ratios optimized for various social media platforms | |
- **Seed Value**: Use same seed to reproduce identical results | |
### Prompt Writing Tips | |
- Use specific and detailed descriptions | |
- Specify camera movements (e.g., zoom in, pan left, tracking shot) | |
- Describe lighting and atmosphere (e.g., golden hour, dramatic lighting) | |
- Indicate movement speed (e.g., slowly, rapidly, gently) | |
""") | |
# Examples | |
gr.Examples( | |
examples=[ | |
["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], | |
["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], | |
["Text to Video", "Close-up of a flower blooming in time-lapse, soft natural lighting, shallow depth of field.", None, "1:1", 789], | |
], | |
inputs=[mode, prompt, image_input, aspect_ratio, seed], | |
label="Example Prompts" | |
) | |
# Event handlers | |
mode.change( | |
fn=update_prompt_placeholder, | |
inputs=[mode], | |
outputs=[prompt] | |
) | |
mode.change( | |
fn=update_image_input, | |
inputs=[mode], | |
outputs=[image_input] | |
) | |
aspect_ratio.change( | |
fn=lambda x: f"Selected ratio: {ASPECT_RATIOS[x]}", | |
inputs=[aspect_ratio], | |
outputs=[ratio_info] | |
) | |
generate_btn.click( | |
fn=generate_video, | |
inputs=[mode, prompt, image_input, aspect_ratio, seed, api_key_input], | |
outputs=[output_video, output_info] | |
) | |
# Run app | |
if __name__ == "__main__": | |
app.launch( | |
server_name="0.0.0.0", | |
server_port=7860, | |
share=False, | |
inbrowser=True | |
) |