AItool commited on
Commit
7e1f9a4
·
verified ·
1 Parent(s): 31c207c

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -0
app.py ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import tempfile
4
+ import threading
5
+ import subprocess
6
+ from pathlib import Path
7
+
8
+ import gradio as gr
9
+ from PIL import Image
10
+
11
+ # Config
12
+ RIFE_REPO_URL = "https://github.com/hzwer/arXiv2020-RIFE"
13
+ RIFE_DIR = Path("arXiv2020-RIFE")
14
+ TRAIN_LOG_DIR = RIFE_DIR / "train_log"
15
+ OUTPUT_DIR = RIFE_DIR / "output"
16
+ WEIGHTS_ID = "1APIzVeI-4ZZCEuIRE1m6WYfSCaOsi_7_" # RIFE v3.6
17
+
18
+ LOCK = threading.Lock()
19
+ RIFE_READY = False
20
+
21
+ def interpolate(a: Image.Image, b: Image.Image, fps: int = 14, exp: int = 2):
22
+ global RIFE_READY
23
+
24
+ with LOCK:
25
+ # Lazy one-time setup
26
+ if not RIFE_READY:
27
+ if not RIFE_DIR.exists():
28
+ subprocess.run(["git", "clone", "--depth", "1", RIFE_REPO_URL, str(RIFE_DIR)], check=True)
29
+ TRAIN_LOG_DIR.mkdir(parents=True, exist_ok=True)
30
+ has_weights = any(p.suffix in {".pkl", ".pth"} for p in TRAIN_LOG_DIR.glob("*"))
31
+ if not has_weights:
32
+ zip_path = TRAIN_LOG_DIR / "RIFE_trained_model_v3.6.zip"
33
+ subprocess.run(["gdown", "--id", WEIGHTS_ID, "-O", str(zip_path)], check=True)
34
+ subprocess.run(["unzip", "-o", str(zip_path), "-d", str(TRAIN_LOG_DIR)], check=True)
35
+ RIFE_READY = True
36
+
37
+ # Normalize inputs
38
+ a = a.convert("RGB")
39
+ b = b.convert("RGB")
40
+ if b.size != a.size:
41
+ b = b.resize(a.size, Image.BICUBIC)
42
+
43
+ work_dir = Path(tempfile.mkdtemp(prefix="rife_run_"))
44
+ p1 = work_dir / "a.png"
45
+ p2 = work_dir / "b.png"
46
+ a.save(p1, "PNG")
47
+ b.save(p2, "PNG")
48
+
49
+ # Clean RIFE output and run inference
50
+ if OUTPUT_DIR.exists():
51
+ shutil.rmtree(OUTPUT_DIR)
52
+ OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
53
+
54
+ cmd = ["python3", "inference_img.py", "--img", str(p1), str(p2)]
55
+ if isinstance(exp, int) and exp >= 1:
56
+ cmd += ["--exp", str(exp)]
57
+ subprocess.run(cmd, cwd=str(RIFE_DIR), check=True)
58
+
59
+ # Collect frames in natural sequence: img1.png → imgN.png
60
+ frames = []
61
+ i = 1
62
+ while True:
63
+ fp = OUTPUT_DIR / f"img{i}.png"
64
+ if not fp.exists():
65
+ break
66
+ frames.append(fp)
67
+ i += 1
68
+ if not frames:
69
+ raise RuntimeError("No frames produced by RIFE.")
70
+
71
+ # Assemble GIF
72
+ images = [Image.open(p).convert("RGBA") for p in frames]
73
+ duration_ms = max(1, int(1000 / max(1, fps)))
74
+ gif_path = work_dir / "interpolation.gif"
75
+ images[0].save(
76
+ gif_path,
77
+ save_all=True,
78
+ append_images=images[1:],
79
+ optimize=False,
80
+ duration=duration_ms,
81
+ loop=0,
82
+ disposal=2,
83
+ )
84
+
85
+ # Optional: cleanup RIFE output
86
+ try:
87
+ shutil.rmtree(OUTPUT_DIR)
88
+ except Exception:
89
+ pass
90
+
91
+ return str(gif_path)
92
+
93
+ TITLE = "RIFE Interpolation → GIF (PyTorch, minimal)"
94
+ with gr.Blocks(title=TITLE, analytics_enabled=False) as demo:
95
+ gr.Markdown(f"# {TITLE}")
96
+ with gr.Row():
97
+ with gr.Column():
98
+ img_a = gr.Image(type="pil", label="Image A")
99
+ img_b = gr.Image(type="pil", label="Image B")
100
+ with gr.Column():
101
+ fps = gr.Slider(6, 30, value=14, step=1, label="FPS")
102
+ exp = gr.Slider(1, 4, value=2, step=1, label="Interpolation exponent (2^exp frames)")
103
+ run = gr.Button("Interpolate", variant="primary")
104
+ gif_out = gr.Image(type="filepath", label="Result GIF")
105
+ run.click(interpolate, inputs=[img_a, img_b, fps, exp], outputs=[gif_out])
106
+ demo.queue(concurrency_count=1, max_size=8)
107
+
108
+ if __name__ == "__main__":
109
+ demo.launch()