File size: 5,624 Bytes
5e93ca8
 
 
 
 
 
 
 
 
 
 
 
 
e30072d
5e93ca8
 
5cf4958
 
e30072d
5e93ca8
 
e30072d
 
5e93ca8
 
 
e30072d
5e93ca8
e30072d
 
5e93ca8
 
 
e30072d
5e93ca8
e30072d
5e93ca8
 
 
e30072d
 
5e93ca8
 
5cf4958
 
e30072d
5e93ca8
 
e30072d
5e93ca8
 
e30072d
 
 
 
 
 
 
 
5e93ca8
e30072d
 
 
 
5e93ca8
 
 
 
e30072d
5e93ca8
e30072d
 
5e93ca8
 
 
e30072d
5e93ca8
e30072d
5e93ca8
 
 
 
e30072d
5e93ca8
 
 
 
 
 
 
 
 
 
 
 
e30072d
5e93ca8
e30072d
 
5cf4958
e30072d
5e93ca8
e30072d
5e93ca8
e30072d
 
 
 
 
 
 
 
 
 
 
5e93ca8
e30072d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5e93ca8
e30072d
 
5e93ca8
e30072d
 
 
 
 
 
 
 
5e93ca8
e30072d
 
 
 
 
 
 
 
 
 
 
5e93ca8
e30072d
 
 
 
 
 
 
5e93ca8
e30072d
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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)