Veo-3.1-Fast / app.py
Open-Source-Lab
Update app.py
8fd8f96 verified
import gradio as gr
import os
from huggingface_hub import InferenceClient
import tempfile
from pathlib import Path
from PIL import Image as PILImage
import io
# Initialize the Hugging Face Inference client
client = InferenceClient(
provider="fal-ai",
api_key=os.environ.get("HF_TOKEN"), # Your HF token must be set in the environment
bill_to="huggingface",
)
# --- Core Functions ---
def text_to_video(prompt, duration=5, aspect_ratio="16:9", resolution="720p"):
"""Generate video from text prompt"""
try:
if not prompt or prompt.strip() == "":
return None, "⚠️ Please enter a text prompt."
# Generate video from text
video = client.text_to_video(
prompt,
model="akhaliq/veo3.1-fast",
)
# Save the video to a temporary file
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_file:
tmp_file.write(video)
video_path = tmp_file.name
return video_path, f"✅ Video generated successfully from prompt: '{prompt[:50]}...'"
except Exception as e:
return None, f"❌ Error generating video: {str(e)}"
def image_to_video(image, prompt, duration=5, aspect_ratio="16:9", resolution="720p"):
"""Generate video from image and prompt"""
try:
if image is None:
return None, "⚠️ Please upload an image."
if not prompt or prompt.strip() == "":
return None, "⚠️ Please enter a motion description."
# Convert image to bytes
if isinstance(image, PILImage.Image):
buffer = io.BytesIO()
image.save(buffer, format="PNG")
input_image = buffer.getvalue()
else:
pil_image = PILImage.fromarray(image)
buffer = io.BytesIO()
pil_image.save(buffer, format="PNG")
input_image = buffer.getvalue()
# Generate video from image
video = client.image_to_video(
input_image,
prompt=prompt,
model="akhaliq/veo3.1-fast-image-to-video",
)
# Save the video to a temporary file
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as tmp_file:
tmp_file.write(video)
video_path = tmp_file.name
return video_path, f"✅ Video generated successfully with motion: '{prompt[:50]}...'"
except Exception as e:
return None, f"❌ Error generating video: {str(e)}"
def clear_text_tab():
"""Clear text-to-video tab"""
return "", None, ""
def clear_image_tab():
"""Clear image-to-video tab"""
return None, "", None, ""
# --- Custom CSS ---
custom_css = """
.container {
max-width: 1200px;
margin: auto;
}
.status-box {
padding: 10px;
border-radius: 5px;
margin-top: 10px;
}
"""
# --- Gradio App ---
with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator") as demo:
gr.Markdown(
"""
# 🎬 AI Video Generator
### Generate stunning videos from text or animate your images with AI
#### Powered by VEO 3.1 Fast Model
"""
)
with gr.Tabs() as tabs:
# Text-to-Video Tab
with gr.Tab("📝 Text to Video"):
gr.Markdown("### Transform your text descriptions into dynamic videos")
with gr.Row():
with gr.Column(scale=1):
text_prompt = gr.Textbox(
label="Text Prompt",
placeholder="Describe the video you want to create...",
lines=4,
max_lines=6
)
with gr.Accordion("Advanced Settings", open=False):
text_duration = gr.Slider(1, 10, value=5, step=1, label="Duration (seconds)")
text_aspect_ratio = gr.Dropdown(
["16:9", "9:16", "1:1", "4:3", "21:9"], value="16:9", label="Aspect Ratio"
)
text_resolution = gr.Dropdown(
["480p", "720p", "1080p"], value="720p", label="Resolution"
)
with gr.Row():
text_generate_btn = gr.Button("🎬 Generate Video", variant="primary")
text_clear_btn = gr.ClearButton(value="🗑️ Clear")
text_status = gr.Textbox(
label="Status", interactive=False, visible=True, elem_classes=["status-box"]
)
with gr.Column(scale=1):
text_video_output = gr.Video(
label="Generated Video", autoplay=True, show_download_button=True, height=400
)
gr.Examples(
examples=[
["A serene beach at sunset with gentle waves"],
["A bustling city street with neon lights at night"],
["A majestic eagle soaring through mountain peaks"],
["An astronaut floating in space near the ISS"],
["Cherry blossoms falling in a Japanese garden"],
],
inputs=text_prompt,
label="Example Prompts",
)
# Image-to-Video Tab
with gr.Tab("🖼️ Image to Video"):
gr.Markdown("### Bring your static images to life with motion")
with gr.Row():
with gr.Column(scale=1):
image_input = gr.Image(label="Upload Image", type="pil", height=300)
image_prompt = gr.Textbox(
label="Motion Prompt",
placeholder="Describe how the image should move...",
lines=3,
max_lines=5
)
with gr.Accordion("Advanced Settings", open=False):
image_duration = gr.Slider(1, 10, value=5, step=1, label="Duration (seconds)")
image_aspect_ratio = gr.Dropdown(
["16:9", "9:16", "1:1", "4:3", "21:9"], value="16:9", label="Aspect Ratio"
)
image_resolution = gr.Dropdown(
["480p", "720p", "1080p"], value="720p", label="Resolution"
)
with gr.Row():
image_generate_btn = gr.Button("🎬 Animate Image", variant="primary")
image_clear_btn = gr.ClearButton(value="🗑️ Clear")
image_status = gr.Textbox(
label="Status", interactive=False, visible=True, elem_classes=["status-box"]
)
with gr.Column(scale=1):
image_video_output = gr.Video(
label="Generated Video", autoplay=True, show_download_button=True, height=400
)
gr.Examples(
examples=[
[None, "The person starts walking forward"],
[None, "The animal begins to run"],
[None, "Camera slowly zooms in while the subject smiles"],
[None, "The flowers sway gently in the breeze"],
[None, "The clouds move across the sky in time-lapse"],
],
inputs=[image_input, image_prompt],
label="Example Motion Prompts",
)
# --- Event handlers ---
text_generate_btn.click(
fn=text_to_video,
inputs=[text_prompt, text_duration, text_aspect_ratio, text_resolution],
outputs=[text_video_output, text_status],
)
text_clear_btn.click(
fn=clear_text_tab,
inputs=[],
outputs=[text_prompt, text_video_output, text_status],
)
image_generate_btn.click(
fn=image_to_video,
inputs=[image_input, image_prompt, image_duration, image_aspect_ratio, image_resolution],
outputs=[image_video_output, image_status],
)
image_clear_btn.click(
fn=clear_image_tab,
inputs=[],
outputs=[image_input, image_prompt, image_video_output, image_status],
)
# Launch the app
if __name__ == "__main__":
demo.launch(show_api=False, share=False, quiet=True)