|
import streamlit as st |
|
import torch |
|
from transformers import pipeline |
|
from PIL import Image |
|
from diffusers import LTXVideoProcessor, LTXVideoPipeline |
|
import numpy as np |
|
from moviepy.editor import ImageSequenceClip |
|
import tempfile |
|
import os |
|
|
|
def generate_video_from_image(image, duration_seconds=10, progress_bar=None): |
|
""" |
|
Generate a video from an image using LTX-Video and image captioning. |
|
|
|
Args: |
|
image: PIL Image object |
|
duration_seconds: Duration of output video in seconds |
|
progress_bar: Streamlit progress bar object |
|
""" |
|
try: |
|
if progress_bar: |
|
progress_bar.progress(0.1, "Generating image caption...") |
|
|
|
|
|
captioner = pipeline("image-to-text", model="Salesforce/blip-image-captioning-base") |
|
|
|
|
|
caption = captioner(image)[0]['generated_text'] |
|
st.write(f"Generated caption: *{caption}*") |
|
|
|
if progress_bar: |
|
progress_bar.progress(0.3, "Loading LTX-Video model...") |
|
|
|
|
|
processor = LTXVideoProcessor() |
|
pipeline = LTXVideoPipeline.from_pretrained("Lightricks/ltx-video") |
|
|
|
if progress_bar: |
|
progress_bar.progress(0.4, "Processing image...") |
|
|
|
|
|
processed_image = processor(image).pixel_values |
|
processed_image = torch.from_numpy(processed_image).unsqueeze(0) |
|
|
|
if progress_bar: |
|
progress_bar.progress(0.5, "Generating video frames...") |
|
|
|
|
|
num_frames = duration_seconds * 30 |
|
video_frames = pipeline( |
|
processed_image, |
|
num_inference_steps=50, |
|
num_frames=num_frames, |
|
guidance_scale=7.5, |
|
prompt=caption, |
|
).videos |
|
|
|
if progress_bar: |
|
progress_bar.progress(0.8, "Creating final video...") |
|
|
|
|
|
frames = [np.array(frame) for frame in video_frames[0]] |
|
|
|
|
|
with tempfile.NamedTemporaryFile(delete=False, suffix='.mp4') as tmp_file: |
|
output_path = tmp_file.name |
|
|
|
|
|
clip = ImageSequenceClip(frames, fps=30) |
|
clip.write_videofile(output_path, codec='libx264', audio=False) |
|
|
|
if progress_bar: |
|
progress_bar.progress(1.0, "Video generation complete!") |
|
|
|
return output_path, caption |
|
|
|
except Exception as e: |
|
st.error(f"Error generating video: {str(e)}") |
|
return None, None |
|
|
|
def main(): |
|
st.set_page_config(page_title="Video Generator", page_icon="π₯") |
|
|
|
st.title("π₯ Video Generator") |
|
st.write(""" |
|
Upload an image to generate a video with AI-powered motion and transitions. |
|
The app will automatically generate a caption for your image and use it as inspiration for the video. |
|
""") |
|
|
|
|
|
uploaded_file = st.file_uploader("Choose an image", type=['png', 'jpg', 'jpeg']) |
|
|
|
|
|
duration = st.slider("Video duration (seconds)", min_value=1, max_value=30, value=10) |
|
|
|
if uploaded_file is not None: |
|
|
|
image = Image.open(uploaded_file) |
|
st.image(image, caption="Uploaded Image", use_column_width=True) |
|
|
|
|
|
if st.button("Generate Video"): |
|
|
|
progress_text = "Operation in progress. Please wait..." |
|
my_bar = st.progress(0, text=progress_text) |
|
|
|
|
|
video_path, caption = generate_video_from_image(image, duration, my_bar) |
|
|
|
if video_path and os.path.exists(video_path): |
|
|
|
with open(video_path, 'rb') as video_file: |
|
video_bytes = video_file.read() |
|
|
|
|
|
st.download_button( |
|
label="Download Video", |
|
data=video_bytes, |
|
file_name="generated_video.mp4", |
|
mime="video/mp4" |
|
) |
|
|
|
|
|
st.video(video_bytes) |
|
|
|
|
|
os.unlink(video_path) |
|
else: |
|
st.error("Failed to generate video. Please try again.") |
|
|
|
if __name__ == "__main__": |
|
main() |