veo3.1-fast / app.py
reab5555's picture
Update app.py
e30072d verified
raw
history blame
5.62 kB
import gradio as gr
import os
from huggingface_hub import InferenceClient
import tempfile
from pathlib import Path
# Initialize the client
client = InferenceClient(
provider="fal-ai",
api_key=os.environ.get("HF_TOKEN"),
bill_to="huggingface",
)
def text_to_video(prompt, aspect_ratio="16:9", profile: gr.OAuthProfile | None = None):
"""Generate video from text prompt"""
try:
if profile is None:
return None, "❌ Click Sign in with Hugging Face button to use this app for free"
if not prompt or prompt.strip() == "":
return None, "Please enter a text prompt"
# Generate video from text with aspect ratio parameter
video = client.text_to_video(
prompt,
model="akhaliq/veo3.1-fast",
aspect_ratio=aspect_ratio,
)
# Save the video
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, aspect_ratio="16:9", profile: gr.OAuthProfile | None = None):
"""Generate video from image and prompt"""
try:
if profile is None:
return None, "❌ Click Sign in with Hugging Face button to use this app for free"
if image is None:
return None, "Please upload an image"
if not prompt or prompt.strip() == "":
return None, "Please enter a prompt describing the motion"
import io
from PIL import Image as PILImage
# Convert image to bytes
buffer = io.BytesIO()
if isinstance(image, PILImage.Image):
image.save(buffer, format='PNG')
else:
PILImage.fromarray(image).save(buffer, format='PNG')
input_image = buffer.getvalue()
# Generate video from image with aspect ratio parameter
video = client.image_to_video(
input_image,
prompt=prompt,
model="akhaliq/veo3.1-fast-image-to-video",
aspect_ratio=aspect_ratio,
)
# Save the video
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)}"
# Custom CSS
custom_css = """
.container {
max-width: 1200px;
margin: auto;
}
.status-box {
padding: 10px;
border-radius: 5px;
margin-top: 10px;
}
"""
# Interface
with gr.Blocks(css=custom_css, theme=gr.themes.Soft(), title="AI Video Generator") as demo:
gr.Markdown("# 🎬 AI Video Generator\n### Generate videos from text or animate images with AI")
gr.LoginButton()
with gr.Tabs() as tabs:
# --- TEXT TO VIDEO TAB ---
with gr.Tab("πŸ“ Text to Video", id=0):
text_prompt = gr.Textbox(
label="Text Prompt",
placeholder="Describe the video you want to create...",
lines=4
)
text_aspect = gr.Radio(
choices=["16:9", "9:16"],
value="16:9",
label="Aspect Ratio"
)
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)
text_video_output = gr.Video(label="Generated Video", autoplay=True, show_download_button=True)
text_generate_btn.click(
fn=text_to_video,
inputs=[text_prompt, text_aspect],
outputs=[text_video_output, text_status],
show_progress="full"
)
text_clear_btn.click(
fn=lambda: ("", None, ""),
outputs=[text_prompt, text_video_output, text_status]
)
# --- IMAGE TO VIDEO TAB ---
with gr.Tab("πŸ–ΌοΈ Image to Video", id=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...")
image_aspect = gr.Radio(
choices=["16:9", "9:16"],
value="16:9",
label="Aspect Ratio"
)
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)
image_video_output = gr.Video(label="Generated Video", autoplay=True, show_download_button=True)
image_generate_btn.click(
fn=image_to_video,
inputs=[image_input, image_prompt, image_aspect],
outputs=[image_video_output, image_status],
show_progress="full"
)
image_clear_btn.click(
fn=lambda: (None, "", None, ""),
outputs=[image_input, image_prompt, image_video_output, image_status]
)
# Launch
if __name__ == "__main__":
demo.launch(share=False, show_api=False, show_error=True, quiet=True)