Cydercoder commited on
Commit
590e6fe
·
verified ·
1 Parent(s): b0fbf54

first commit

Browse files
Files changed (4) hide show
  1. .gitignore +4 -0
  2. README.md +136 -9
  3. app.py +256 -0
  4. requirements.txt +11 -0
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .DS_Store
4
+ .env
README.md CHANGED
@@ -1,15 +1,142 @@
1
  ---
2
- title: Cydermotion
3
- emoji: 📉
4
- colorFrom: gray
5
- colorTo: green
6
  sdk: gradio
7
- sdk_version: 6.24.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
11
- license: apache-2.0
12
- short_description: 'Personal AI video generator (text & image to video) '
13
  ---
14
 
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: My Motion Video AI
3
+ emoji: 🎬
4
+ colorFrom: purple
5
+ colorTo: blue
6
  sdk: gradio
 
 
7
  app_file: app.py
8
  pinned: false
9
+ models:
10
+ - Lightricks/LTX-Video-0.9.5
11
  ---
12
 
13
+ # 🎬 My Motion Video AI
14
+
15
+ Your own AI video generator — **runs 100% in the cloud** on Hugging Face GPUs.
16
+ Your old laptop only needs a browser. No local install, no local GPU, no cost
17
+ to deploy.
18
+
19
+ - **Model:** [LTX-Video 0.9.5 (2B)](https://huggingface.co/Lightricks/LTX-Video-0.9.5) (open source, by Lightricks)
20
+ - **Stack:** Gradio web UI + Diffusers
21
+ - **Hosting:** Hugging Face Space with **ZeroGPU** (free GPU in the cloud)
22
+ - **Features:** Text-to-Video and Image-to-Video (animate a logo or title card)
23
+
24
+ ---
25
+
26
+ ## How to deploy it (free, ~20 minutes)
27
+
28
+ 1. **Create a Hugging Face account** → https://huggingface.co/join
29
+ (verify your email so you're in "good standing" and can host ZeroGPU Spaces)
30
+
31
+ 2. **Create a new Space:**
32
+ - Go to https://huggingface.co/new-space
33
+ - Name it e.g. `my-motion-video-ai`
34
+ - License: any (Apache 2.0 is fine)
35
+ - SDK: **Gradio**
36
+ - Click **Create Space**, then in **Settings → Hardware** select
37
+ **ZeroGPU** ⚠️ (free GPU). The README also requests it via
38
+ `hardware: {accelerator: zero-gpu}` when you push these files.
39
+
40
+ > Note: ZeroGPU hosting needs an account in good standing — verified email
41
+ > and account older than 30 days. If you just created the account, it may
42
+ > take a few weeks before you can host a ZeroGPU Space; until then you can
43
+ > still use *other* public ZeroGPU Spaces, or ask me to point you at ready-made ones.
44
+
45
+ 3. **Upload these files.** Either:
46
+ - Use the **Files** tab → "Add file" → upload `app.py`, `requirements.txt`,
47
+ `README.md` (replace the auto-generated README), or
48
+ - Push from your laptop with git:
49
+ ```bash
50
+ git init
51
+ git add .
52
+ git commit -m "initial"
53
+ git remote add origin https://huggingface.co/spaces/<your-username>/<space-name>
54
+ git push --force
55
+ ```
56
+
57
+ 4. **Wait for the build** (the model is downloaded automatically at build time
58
+ thanks to the `models:` key in this README). Then open the app — it's live
59
+ at `https://huggingface.co/spaces/<your-username>/<space-name>`.
60
+
61
+ That's it. The app is **your** AI, hosted on their GPU, reachable from any
62
+ browser, on any device, forever (as long as the Space stays public/free).
63
+
64
+ ---
65
+
66
+ ## ⚠️ The real limits (read this — it saves disappointment)
67
+
68
+ | Account | Free GPU per day | Note |
69
+ |---|---|---|
70
+ | No account | 2 minutes | Low queue priority |
71
+ | Free account | **5 minutes** | Resets 24h after first use each day |
72
+ | PRO ($9/mo) | 40 minutes + credits | Highest queue priority |
73
+
74
+ (Data from the official [ZeroGPU docs](https://huggingface.co/docs/hub/en/spaces-zerogpu),
75
+ Aug 2026. Free accounts can host up to 2 ZeroGPU Spaces.)
76
+
77
+ - One short clip (~5s, 30 steps) consumes roughly **1–2 minutes** of that quota,
78
+ so a free account realistically gets **~3–5 videos per day**.
79
+ - Queue priority is based on remaining quota — use your quota early in the day.
80
+ - There is **no unlimited free tier anywhere** for video generation. GPUs are
81
+ expensive; that's physics, not a scam.
82
+
83
+ ---
84
+
85
+ ## How to use it well
86
+
87
+ ### Prompting tips (motion graphics)
88
+ - Describe the scene **and** the motion: *"glossy chrome sphere rotating slowly,
89
+ volumetric lighting, dark studio"*.
90
+ - Keep clips short (~5s, 121 frames) — LTX-Video shines at short, single-shot clips.
91
+ - More inference steps (40–50) = better quality but slower and more quota.
92
+ - Reuse a **seed** to reproduce a video and iterate on it.
93
+
94
+ ### Kinetic typography / logos (the pro move)
95
+ Text rendering in video models is unreliable. Instead:
96
+ 1. Generate the title/logo as an **image** (free tools: Stable Diffusion in a
97
+ free Space, or Google AI Studio for images).
98
+ 2. Switch the app to **Image to Video**, upload it, and prompt for motion:
99
+ *"logo rotating in 3D, smooth, reflective floor, cinematic lighting"*.
100
+
101
+ ### Sample prompts
102
+ - **3D-style:** `Cinematic 3D render, glossy chrome sphere rotating on a dark studio background, volumetric lighting, smooth slow motion, octane render, 8k`
103
+ - **Abstract loop:** `Seamless abstract loop, flowing liquid metal, iridescent gradient colors, dark background, smooth hypnotic motion`
104
+ - **Kinetic typography:** `Kinetic typography, the word MOTION exploding into view letter by letter, bold neon glowing letters, dark background, energetic dynamic camera`
105
+
106
+ ---
107
+
108
+ ## Phase 2: training it on YOUR style (optional, later)
109
+
110
+ "Training your own" realistically means **fine-tuning / LoRA** on top of an
111
+ existing open model. For LTX-Video, the official trainer is
112
+ [`ltx-video` (ltx-trainer)](https://github.com/Lightricks/ltx-video).
113
+
114
+ - **What you need:** ~10–50 of your own motion-graphics clips, a few hours of
115
+ rented GPU, and some patience.
116
+ - **Cheapest real path:** rent a GPU for a few hours (~$0.5–2/hr at providers
117
+ like RunPod/Vast.ai; Google Colab free is too slow/limited for this).
118
+ - **Cost honesty:** fine-tuning a video model from *scratch* costs tens of
119
+ thousands of dollars — nobody does that. Fine-tuning on top of LTX-Video or
120
+ Wan 2.2 is the legitimate, achievable version.
121
+ - **Do Phase 1 first.** The base model already handles 3D-style shots, abstract
122
+ loops, and kinetic typography — you may never need Phase 2.
123
+
124
+ ---
125
+
126
+ ## FAQ
127
+
128
+ **My laptop is old / low spec. Does that matter?**
129
+ No. The app runs on Hugging Face's GPU. Your laptop just opens a web page.
130
+
131
+ **Is this really free?**
132
+ Deploying and running the Space is free. Generation is limited by the 5
133
+ min/day free GPU quota above.
134
+
135
+ **I want "unlimited".**
136
+ Then you'll pay eventually — the cheapest legit path is HF PRO ($9/mo, 40 min
137
+ GPU/day + credits) or renting a GPU for batch jobs. Anyone promising unlimited
138
+ free video AI is either lying or harvesting your data.
139
+
140
+ **Can others use my app?**
141
+ Yes — if the Space is public, anyone with the link can use it (consuming your
142
+ daily quota). Make it private if it's just for you.
app.py ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """My Motion Video AI — LTX-Video (text-to-video + image-to-video) on ZeroGPU.
2
+
3
+ Deploy as a Hugging Face Space with the ZeroGPU hardware option selected.
4
+ Everything runs in the cloud: your laptop only needs a browser.
5
+ """
6
+
7
+ import os
8
+ import random
9
+ import tempfile
10
+
11
+ import gradio as gr
12
+ import spaces
13
+
14
+ # The 2B LTX-Video checkpoint (0.9.5): much lighter than the 13B main repo
15
+ # (~15GB bf16 vs ~38GB), so it fits the 48GB ZeroGPU slice comfortably.
16
+ # Un-gated, official diffusers structure, supports text-to-video + image-to-video.
17
+ MODEL_ID = "Lightricks/LTX-Video-0.9.5"
18
+
19
+ DEFAULT_NEGATIVE = (
20
+ "worst quality, inconsistent motion, blurry, jittery, distorted, "
21
+ "low resolution, watermark, flicker"
22
+ )
23
+
24
+ RESOLUTIONS = {
25
+ "Landscape 768x512": (768, 512),
26
+ "Portrait 512x768": (512, 768),
27
+ "Square 768x768": (768, 768),
28
+ "Square 512x512": (512, 512),
29
+ }
30
+
31
+ FPS = 24
32
+
33
+ # Pipelines are loaded lazily on the first generation (the model files are
34
+ # prefetched at build time via the `models:` key in README.md, so this only
35
+ # loads them into GPU memory once). Keeps the Space from OOM-ing at startup.
36
+ _text_pipe = None
37
+ _image_pipe = None
38
+
39
+
40
+ def _load_pipes():
41
+ """Load the text-to-video and image-to-video pipelines once, then reuse."""
42
+ global _text_pipe, _image_pipe
43
+
44
+ import torch
45
+ from diffusers import LTXImageToVideoPipeline, LTXPipeline
46
+
47
+ if _text_pipe is None:
48
+ _text_pipe = LTXPipeline.from_pretrained(MODEL_ID, torch_dtype=torch.bfloat16)
49
+ _text_pipe.to("cuda")
50
+ _text_pipe.vae.enable_slicing()
51
+ _text_pipe.vae.enable_tiling()
52
+
53
+ if _image_pipe is None:
54
+ _image_pipe = LTXImageToVideoPipeline.from_pretrained(
55
+ MODEL_ID, torch_dtype=torch.bfloat16
56
+ )
57
+ _image_pipe.to("cuda")
58
+ _image_pipe.vae.enable_slicing()
59
+ _image_pipe.vae.enable_tiling()
60
+
61
+ return _text_pipe, _image_pipe
62
+
63
+
64
+ def _get_duration(
65
+ prompt, negative_prompt, mode, input_image, num_frames, resolution, seed, num_steps, guidance
66
+ ):
67
+ """Return the GPU runtime budget for this call (seconds).
68
+
69
+ ZeroGPU charges quota based on this reservation, so keep it tight.
70
+ The first call also loads the model into GPU memory, so give it more room.
71
+ """
72
+ if _text_pipe is None:
73
+ return 240 # first call: model load + generation
74
+ return max(45, int(num_steps * 1.5) + 15)
75
+
76
+
77
+ @spaces.GPU(duration=_get_duration)
78
+ def generate_video(
79
+ prompt,
80
+ negative_prompt,
81
+ mode,
82
+ input_image,
83
+ num_frames,
84
+ resolution,
85
+ seed,
86
+ num_steps,
87
+ guidance,
88
+ ):
89
+ """Generate a video from a text prompt (or an image + prompt)."""
90
+ import torch
91
+ from diffusers.utils import export_to_video
92
+
93
+ if not prompt or not prompt.strip():
94
+ raise gr.Error("Please write a prompt first.")
95
+
96
+ negative_prompt = (negative_prompt or "").strip() or DEFAULT_NEGATIVE
97
+ width, height = RESOLUTIONS[resolution]
98
+
99
+ seed = int(seed) # gr.Number returns a float
100
+ if seed < 0:
101
+ seed = random.randint(0, 2**31 - 1)
102
+ generator = torch.Generator(device="cuda").manual_seed(seed)
103
+
104
+ text_pipe, image_pipe = _load_pipes()
105
+
106
+ # Timestep-aware VAE settings recommended for LTX-Video 0.9.1+.
107
+ decode_kwargs = {"decode_timestep": 0.05, "decode_noise_scale": 0.025}
108
+
109
+ if mode == "Image to Video":
110
+ if input_image is None:
111
+ raise gr.Error("Upload an image to use Image-to-Video mode.")
112
+ result = image_pipe(
113
+ prompt=prompt,
114
+ negative_prompt=negative_prompt,
115
+ image=input_image,
116
+ num_frames=num_frames,
117
+ height=height,
118
+ width=width,
119
+ num_inference_steps=num_steps,
120
+ guidance_scale=guidance,
121
+ image_cond_noise_scale=0.025,
122
+ generator=generator,
123
+ **decode_kwargs,
124
+ )
125
+ else:
126
+ result = text_pipe(
127
+ prompt=prompt,
128
+ negative_prompt=negative_prompt,
129
+ num_frames=num_frames,
130
+ height=height,
131
+ width=width,
132
+ num_inference_steps=num_steps,
133
+ guidance_scale=guidance,
134
+ generator=generator,
135
+ **decode_kwargs,
136
+ )
137
+
138
+ frames = result.frames[0]
139
+ out_path = os.path.join(
140
+ tempfile.gettempdir(), f"ltx_{seed}_{random.randint(0, 99999)}.mp4"
141
+ )
142
+ export_to_video(frames, out_path, fps=FPS)
143
+ return out_path
144
+
145
+
146
+ PROMPT_EXAMPLES = [
147
+ "Cinematic 3D render, glossy chrome sphere rotating on a dark studio background, volumetric lighting, smooth slow motion, octane render, 8k",
148
+ "Seamless abstract loop, flowing liquid metal, iridescent gradient colors, dark background, smooth hypnotic motion",
149
+ "Kinetic typography, the word MOTION exploding into view letter by letter, bold neon glowing letters, dark background, energetic dynamic camera",
150
+ ]
151
+
152
+ with gr.Blocks(title="My Motion Video AI", theme=gr.themes.Soft()) as demo:
153
+ gr.Markdown(
154
+ """# 🎬 My Motion Video AI
155
+
156
+ Your own video generation AI, running 100% in the cloud on Hugging Face GPUs
157
+ (open-source **LTX-Video**). Your laptop never does the work.
158
+
159
+ > **Free tier limit:** ~5 minutes of GPU per day (resets 24h after first use).
160
+ > One short clip ≈ 1–2 minutes of that. Choose your prompts wisely!
161
+ """
162
+ )
163
+
164
+ with gr.Row():
165
+ with gr.Column(scale=1):
166
+ mode = gr.Radio(
167
+ ["Text to Video", "Image to Video"],
168
+ value="Text to Video",
169
+ label="Mode",
170
+ info="Image to Video animates an uploaded image — great for kinetic typography and logos.",
171
+ )
172
+ prompt = gr.Textbox(
173
+ lines=3,
174
+ label="Prompt",
175
+ placeholder="Describe the motion graphics you want...",
176
+ info="Describe the scene AND the motion. Short clips work best.",
177
+ )
178
+ negative_prompt = gr.Textbox(
179
+ lines=2,
180
+ label="Negative prompt (optional)",
181
+ placeholder=DEFAULT_NEGATIVE,
182
+ )
183
+ input_image = gr.Image(
184
+ type="pil",
185
+ label="Starting image (Image to Video only)",
186
+ visible=False,
187
+ )
188
+
189
+ with gr.Accordion("Settings", open=False):
190
+ num_frames = gr.Slider(
191
+ minimum=49,
192
+ maximum=241,
193
+ value=121,
194
+ step=8,
195
+ label="Frames (121 ≈ 5 seconds)",
196
+ )
197
+ resolution = gr.Dropdown(
198
+ list(RESOLUTIONS.keys()),
199
+ value="Landscape 768x512",
200
+ label="Resolution",
201
+ )
202
+ num_steps = gr.Slider(
203
+ minimum=10,
204
+ maximum=50,
205
+ value=30,
206
+ step=1,
207
+ label="Inference steps (more = slower but higher quality)",
208
+ )
209
+ guidance = gr.Slider(
210
+ minimum=1.0,
211
+ maximum=6.0,
212
+ value=3.0,
213
+ step=0.5,
214
+ label="Guidance scale (how strictly it follows the prompt)",
215
+ )
216
+ seed = gr.Number(
217
+ value=-1,
218
+ label="Seed (-1 = random, reuse a seed to reproduce a video)",
219
+ )
220
+
221
+ generate_btn = gr.Button("🎬 Generate video", variant="primary")
222
+
223
+ with gr.Column(scale=1):
224
+ output_video = gr.Video(
225
+ label="Your video", format="mp4", autoplay=False
226
+ )
227
+ gr.Examples(
228
+ examples=PROMPT_EXAMPLES,
229
+ inputs=prompt,
230
+ label="Try one of these",
231
+ )
232
+
233
+ def toggle_image_visibility(selected_mode):
234
+ return gr.update(visible=(selected_mode == "Image to Video"))
235
+
236
+ mode.change(toggle_image_visibility, inputs=mode, outputs=input_image)
237
+
238
+ generate_btn.click(
239
+ generate_video,
240
+ inputs=[
241
+ prompt,
242
+ negative_prompt,
243
+ mode,
244
+ input_image,
245
+ num_frames,
246
+ resolution,
247
+ seed,
248
+ num_steps,
249
+ guidance,
250
+ ],
251
+ outputs=output_video,
252
+ )
253
+
254
+
255
+ if __name__ == "__main__":
256
+ demo.queue().launch()
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio>=5.0
2
+ diffusers>=0.33.0
3
+ transformers>=4.46.0
4
+ accelerate>=0.34.0
5
+ torch>=2.8.0
6
+ safetensors>=0.4.5
7
+ imageio>=2.35.0
8
+ imageio-ffmpeg>=0.5.0
9
+ pillow>=10.0.0
10
+ spaces>=0.28.0
11
+ huggingface_hub>=0.26.0