Spaces:
Running on Zero
Running on Zero
viggle-animate: gpt-image-2 repaint + 4-step render
Browse files- .gitattributes +3 -0
- app.py +20 -11
- examples/lipsync_drive.mp4 +3 -0
- examples/lipsync_out.mp4 +3 -0
- examples/lipsync_ref.png +3 -0
.gitattributes
CHANGED
|
@@ -68,3 +68,6 @@ examples/wushu_animals_out.mp4 filter=lfs diff=lfs merge=lfs -text
|
|
| 68 |
examples/wushu_animals_ref.png filter=lfs diff=lfs merge=lfs -text
|
| 69 |
examples/wushu_robots_out.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 70 |
examples/wushu_robots_ref.png filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
examples/wushu_animals_ref.png filter=lfs diff=lfs merge=lfs -text
|
| 69 |
examples/wushu_robots_out.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 70 |
examples/wushu_robots_ref.png filter=lfs diff=lfs merge=lfs -text
|
| 71 |
+
examples/lipsync_drive.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 72 |
+
examples/lipsync_out.mp4 filter=lfs diff=lfs merge=lfs -text
|
| 73 |
+
examples/lipsync_ref.png filter=lfs diff=lfs merge=lfs -text
|
app.py
CHANGED
|
@@ -65,11 +65,16 @@ EX = Path(__file__).parent / "examples"
|
|
| 65 |
# so clicking one costs no GPU and no OpenAI call. Several share a driving clip, hence the
|
| 66 |
# name -> (drive file prefix, caption) shape: `corgi` and `clay` reuse `costume`'s clip, and
|
| 67 |
# the second take of each two-character pair reuses its partner's.
|
| 68 |
-
# Order is what a visitor reads top to bottom
|
| 69 |
-
#
|
| 70 |
-
#
|
| 71 |
-
#
|
|
|
|
|
|
|
|
|
|
| 72 |
CASES = {
|
|
|
|
|
|
|
| 73 |
"corgi": ("costume", "a corgi"),
|
| 74 |
"panda": ("panda", "a giant panda"),
|
| 75 |
"penguin": ("penguin", "a penguin"),
|
|
@@ -1015,12 +1020,15 @@ with gr.Blocks(title="Viggle-Animate") as demo:
|
|
| 1015 |
"Put the person from a still into a driving video. No pose estimation, no "
|
| 1016 |
"segmentation, no masks — the only preprocessing is repainting the clip's first "
|
| 1017 |
f"frame. 4 sampling steps. Takes {MIN_UPLOAD_S:.0f}–{MAX_FRAMES/FPS:.0f} s of driving "
|
| 1018 |
-
f"video; anything longer is cut to {MAX_FRAMES/FPS:.1f} s.
|
|
|
|
|
|
|
| 1019 |
f"[Model card and weights]({MODEL_CARD}) · [viggle.ai]({SITE})"
|
| 1020 |
)
|
| 1021 |
with gr.Row():
|
| 1022 |
with gr.Column():
|
| 1023 |
-
v = gr.Video(label="driving video — motion, framing and background are kept"
|
|
|
|
| 1024 |
c = gr.Image(label="character — who to put in it", type="filepath")
|
| 1025 |
p = gr.Image(label="…or frame 0, already painted (skips gpt-image-2)",
|
| 1026 |
type="filepath")
|
|
@@ -1051,12 +1059,13 @@ with gr.Blocks(title="Viggle-Animate") as demo:
|
|
| 1051 |
# actual evidence rather than a footnote.
|
| 1052 |
gr.Markdown("### What it produces\n"
|
| 1053 |
"Every example above, rendered at 4 steps with seed 42. Each is a single paint "
|
| 1054 |
-
"and a single render;
|
|
|
|
| 1055 |
items = list(CASES.items())
|
| 1056 |
-
# Rows are cut on aspect, not on a fixed width:
|
| 1057 |
-
# two-character takes,
|
| 1058 |
-
# the portrait ones to a third of their height.
|
| 1059 |
-
for row in (items[0:
|
| 1060 |
with gr.Row():
|
| 1061 |
for n, (_, caption) in row:
|
| 1062 |
gr.Video(str(EX / f"{n}_out.mp4"), label=caption, interactive=False)
|
|
|
|
| 65 |
# so clicking one costs no GPU and no OpenAI call. Several share a driving clip, hence the
|
| 66 |
# name -> (drive file prefix, caption) shape: `corgi` and `clay` reuse `costume`'s clip, and
|
| 67 |
# the second take of each two-character pair reuses its partner's.
|
| 68 |
+
# Order is what a visitor reads top to bottom. `lipsync` is first because it is the only case
|
| 69 |
+
# whose driving clip carries a soundtrack, and therefore the only one where the mouth has
|
| 70 |
+
# anything to track: every other output's audio track is this finetune's digital silence
|
| 71 |
+
# (-105 dBFS, against -22 for this one). Then the swaps where the target is not a person -- one
|
| 72 |
+
# paint and one render each, no best-of-N -- and last the human cases the model card compares
|
| 73 |
+
# against Wan2.2-Animate. Within that, aspect ratio is grouped, because the output rows below
|
| 74 |
+
# are split on these indices.
|
| 75 |
CASES = {
|
| 76 |
+
"lipsync": ("lipsync", "the driving clip has sound, so the mouth has something to say "
|
| 77 |
+
"— turn the volume on"),
|
| 78 |
"corgi": ("costume", "a corgi"),
|
| 79 |
"panda": ("panda", "a giant panda"),
|
| 80 |
"penguin": ("penguin", "a penguin"),
|
|
|
|
| 1020 |
"Put the person from a still into a driving video. No pose estimation, no "
|
| 1021 |
"segmentation, no masks — the only preprocessing is repainting the clip's first "
|
| 1022 |
f"frame. 4 sampling steps. Takes {MIN_UPLOAD_S:.0f}–{MAX_FRAMES/FPS:.0f} s of driving "
|
| 1023 |
+
f"video; anything longer is cut to {MAX_FRAMES/FPS:.1f} s. If the clip carries a "
|
| 1024 |
+
"soundtrack it is pinned into the render and the mouth tracks it; upload a silent clip "
|
| 1025 |
+
"and the mouth moves without saying anything.\n\n"
|
| 1026 |
f"[Model card and weights]({MODEL_CARD}) · [viggle.ai]({SITE})"
|
| 1027 |
)
|
| 1028 |
with gr.Row():
|
| 1029 |
with gr.Column():
|
| 1030 |
+
v = gr.Video(label="driving video — motion, framing and background are kept; "
|
| 1031 |
+
"its soundtrack, if it has one, is what the mouth follows")
|
| 1032 |
c = gr.Image(label="character — who to put in it", type="filepath")
|
| 1033 |
p = gr.Image(label="…or frame 0, already painted (skips gpt-image-2)",
|
| 1034 |
type="filepath")
|
|
|
|
| 1059 |
# actual evidence rather than a footnote.
|
| 1060 |
gr.Markdown("### What it produces\n"
|
| 1061 |
"Every example above, rendered at 4 steps with seed 42. Each is a single paint "
|
| 1062 |
+
"and a single render; the first and the last three swap in a person. Only the "
|
| 1063 |
+
"first one has audio — it is the only one whose driving clip had any.")
|
| 1064 |
items = list(CASES.items())
|
| 1065 |
+
# Rows are cut on aspect, not on a fixed width: the landscape lip-sync take on its own, then
|
| 1066 |
+
# six portrait swaps, the four landscape two-character takes, and the three human cases.
|
| 1067 |
+
# Mixing the two shapes in one row squeezes the portrait ones to a third of their height.
|
| 1068 |
+
for row in (items[0:1], items[1:4], items[4:7], items[7:11], items[11:14]):
|
| 1069 |
with gr.Row():
|
| 1070 |
for n, (_, caption) in row:
|
| 1071 |
gr.Video(str(EX / f"{n}_out.mp4"), label=caption, interactive=False)
|
examples/lipsync_drive.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:fc3dd85a5be2e6246fb40afe46e337cb75d6c3558105fd81fa02f1ff286a5e92
|
| 3 |
+
size 4223283
|
examples/lipsync_out.mp4
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f0daf870fb10c109ecfbb33a313a16ec69e0e49bc4995fe5717557b6effeca15
|
| 3 |
+
size 442574
|
examples/lipsync_ref.png
ADDED
|
Git LFS Details
|