File size: 2,649 Bytes
679913c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import os
import torch
import gradio as gr
import numpy as np
from PIL import Image
import imageio

from diffusers import StableVideoDiffusionPipeline

# =========================
# CONFIG
# =========================
MODEL_ID = "stabilityai/stable-video-diffusion-img2vid"
OUTPUT_DIR = "output"

NUM_FRAMES = 14          # AMAN untuk CPU
FPS = 7
SEED = 42

os.makedirs(OUTPUT_DIR, exist_ok=True)

DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32

# =========================
# LOAD MODEL (SAFE)
# =========================
pipe = StableVideoDiffusionPipeline.from_pretrained(
    MODEL_ID,
    torch_dtype=DTYPE
)

pipe.to(DEVICE)
pipe.enable_attention_slicing()

if DEVICE == "cuda":
    pipe.enable_model_cpu_offload()

generator = torch.Generator(device=DEVICE).manual_seed(SEED)

# =========================
# SAVE VIDEO (NO CV2)
# =========================
def save_video(frames, path, fps):
    imageio.mimsave(path, frames, fps=fps)

# =========================
# IMAGE → VIDEO FUNCTION
# =========================
def images_to_videos(files):
    if files is None or len(files) == 0:
        return None

    output_videos = []

    for idx, file in enumerate(files):
        image = Image.open(file.name).convert("RGB")
        image = image.resize((768, 432))  # CPU SAFE SIZE

        with torch.autocast(DEVICE if DEVICE == "cuda" else "cpu"):
            result = pipe(
                image=image,
                num_frames=NUM_FRAMES,
                generator=generator
            )

        frames = [
            (frame * 255).astype(np.uint8)
            for frame in result.frames[0]
        ]

        out_path = os.path.join(OUTPUT_DIR, f"video_{idx}.mp4")
        save_video(frames, out_path, FPS)

        output_videos.append(out_path)

    return output_videos

# =========================
# GRADIO UI
# =========================
with gr.Blocks(title="Image to Video (HF Spaces Safe)") as demo:
    gr.Markdown(
        """
        ## 🎥 Image → Video AI (Hugging Face Spaces)
        - Upload **multiple images**
        - Output **MP4**
        - CPU & GPU compatible
        """
    )

    image_input = gr.File(
        file_types=["image"],
        file_count="multiple",
        label="Upload Images"
    )

    video_output = gr.Video(label="Generated Video")

    generate_btn = gr.Button("🚀 Generate")

    def process(files):
        videos = images_to_videos(files)
        return videos[0] if videos else None

    generate_btn.click(
        fn=process,
        inputs=image_input,
        outputs=video_output
    )

demo.launch()