yhbbgff commited on
Commit
d2a3c36
·
verified ·
1 Parent(s): e37faec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +207 -62
app.py CHANGED
@@ -1,116 +1,261 @@
1
  """
2
- JoyAI-Video-Edit — ZeroGPU Compatible Entry Point
3
- این فایل به عنوان نقطه ورود برای HF Spaces طراحی شده است.
4
- از آنجا که JoyAI اصلی از ماژول داخلی xvideo استفاده می‌کند،
5
- این اسکریپت یک رابط Gradio/ZeroGPU سازگار فراهم می‌کند.
6
  """
7
  import os
8
  import sys
 
9
  from pathlib import Path
10
 
11
- # ✅ تنظیم مسیرهای قابل نوشتن در HF Spaces (رفع PermissionError)
 
 
12
  os.environ["HF_HOME"] = "/tmp/huggingface"
13
  os.environ["XDG_CACHE_HOME"] = "/tmp/cache"
14
  os.environ["JOYOMNI_CKPT_ROOT"] = "/tmp/checkpoints/JoyAI-Video-Edit"
15
- os.environ["COMFYUI_MODEL_PATH"] = "/tmp/comfyui_models"
16
 
17
- # ایجاد دایرکتوری‌ها قبل از هرگونه import
18
- for p in [
19
  os.environ["HF_HOME"],
20
  os.environ["JOYOMNI_CKPT_ROOT"],
21
- os.environ["COMFYUI_MODEL_PATH"],
22
- "/tmp/comfyui_models/diffusion_models",
23
- ]:
24
- Path(p).mkdir(parents=True, exist_ok=True)
 
 
 
25
 
26
- # ✅ الزامی برای شناسایی توسط ZeroGPU
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  import spaces
28
 
29
- @spaces.GPU(duration=60, gpu_size="xlarge")
 
 
 
30
  def load_model():
31
- """بارگذاری مدل در GPU با مدیریت خطا"""
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  try:
33
- # تلاش برای بارگذاری ماژول اصلی JoyAI
34
- from xvideo.inductor_autotune_fix import install as _install_autotune_fix
35
  from xvideo.serving.joyomni_streaming import JoyOmniRuntime
36
 
37
- _install_autotune_fix()
 
38
 
39
- ckpt_root = Path(os.environ["JOYOMNI_CKPT_ROOT"])
40
- rt = JoyOmniRuntime.load(
41
- ckpt_root / "dit" / "joyai_video_edit_dit_0811.pth",
42
- vae_ckpt=ckpt_root / "vae",
43
- text_encoder_ckpt=ckpt_root / "text_encoder",
44
  device="cuda",
45
  seed=42,
46
  warmup_height=480,
47
  warmup_width=840,
48
  )
49
- return rt, None
 
 
50
  except ImportError as e:
51
- return None, f"xvideo module not found: {e}. Please ensure JoyAI runtime is installed."
 
 
52
  except Exception as e:
53
- return None, f"Model loading failed: {str(e)}"
54
-
55
- # بارگذاری اولیه مدل
56
- print("🔄 Loading JoyAI-Video-Edit model...")
57
- runtime, error_msg = load_model()
58
- if error_msg:
59
- print(f"⚠️ Warning: {error_msg}")
60
- else:
61
- print("✅ Model loaded successfully!")
62
 
63
- # ✅ رابط کاربری Gradio (الزامی برای ZeroGPU)
64
- import gradio as gr
65
 
 
 
 
 
66
  def edit_video(video_path, prompt):
67
- """تابع ویرایش ویدیو"""
68
  if runtime is None:
69
- return None, f"❌ Model not available: {error_msg}"
70
-
71
  if not video_path:
72
  return None, "❌ Please upload a video first."
73
-
74
- if not prompt.strip():
75
  return None, "❌ Please enter an editing instruction."
76
 
77
  try:
78
- # TODO: پیاده‌سازی منطق ویرایش با استفاده از runtime
79
- # فعلاً یک پاسخ placeholder برمی‌گردانیم
80
- return video_path, f"✅ Received: '{prompt}'\n(Runtime ready for streaming inference)"
 
 
 
 
 
 
 
 
 
81
  except Exception as e:
82
  return None, f"❌ Editing failed: {str(e)}"
83
 
84
- with gr.Blocks(title="JoyAI Video Edit") as demo:
85
- gr.Markdown("# 🎬 JoyAI-Video-Edit\nReal-Time Open-Ended Video Editing")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  with gr.Row():
88
- with gr.Column():
89
- input_video = gr.Video(label="Input Video", sources=["upload", "webcam"])
 
 
 
 
90
  edit_prompt = gr.Textbox(
91
- label="Editing Instruction",
92
- placeholder="e.g., Transform into watercolor style, Add sunglasses...",
93
- lines=2
 
 
 
 
 
94
  )
95
- submit_btn = gr.Button("✏️ Edit Video", variant="primary")
96
 
97
- with gr.Column():
98
- output_video = gr.Video(label="Edited Output")
99
- status_log = gr.Textbox(label="Status", interactive=False)
 
 
 
 
 
100
 
101
  submit_btn.click(
102
  fn=edit_video,
103
  inputs=[input_video, edit_prompt],
104
- outputs=[output_video, status_log]
105
  )
106
 
107
  gr.Markdown("""
108
- ### ⚠️ Notes
109
- - This space requires **ZeroGPU (xlarge tier)**
110
- - First run may take 1-2 minutes for model warmup
111
- - Supports: style transfer, object edit, subject replacement, background change
 
 
 
 
 
 
 
112
  """)
113
 
114
- # ✅ جلوگیری از خروج فوری سرور
 
 
 
115
  if __name__ == "__main__":
116
- demo.launch(server_name="0.0.0.0", server_port=7860, ssr_mode=False)
 
 
 
 
 
 
1
  """
2
+ JoyAI-Video-Edit — Complete ZeroGPU + Gradio Entry Point
3
+ شامل: دانلود خودکار رانتایم + چک‌پوینت‌ها + رابط کاربری Gradio
 
 
4
  """
5
  import os
6
  import sys
7
+ import subprocess
8
  from pathlib import Path
9
 
10
+ # ============================================================
11
+ # ✅ ۱. تنظیم مسیرهای قابل نوشتن (رفع PermissionError)
12
+ # ============================================================
13
  os.environ["HF_HOME"] = "/tmp/huggingface"
14
  os.environ["XDG_CACHE_HOME"] = "/tmp/cache"
15
  os.environ["JOYOMNI_CKPT_ROOT"] = "/tmp/checkpoints/JoyAI-Video-Edit"
16
+ os.environ["JOYAI_REPO"] = "/tmp/JoyAI-Video-Edit"
17
 
18
+ REQUIRED_DIRS = [
 
19
  os.environ["HF_HOME"],
20
  os.environ["JOYOMNI_CKPT_ROOT"],
21
+ os.environ["JOYAI_REPO"],
22
+ f"{os.environ['JOYOMNI_CKPT_ROOT']}/dit",
23
+ f"{os.environ['JOYOMNI_CKPT_ROOT']}/vae",
24
+ f"{os.environ['JOYOMNI_CKPT_ROOT']}/text_encoder",
25
+ ]
26
+ for d in REQUIRED_DIRS:
27
+ Path(d).mkdir(parents=True, exist_ok=True)
28
 
29
+ print("📁 Writable directories initialized in /tmp/")
30
+
31
+
32
+ # ============================================================
33
+ # ✅ ۲. دانلود خودکار رانتایم xvideo از گیت‌هاب
34
+ # ============================================================
35
+ def setup_runtime():
36
+ """کلون کردن و نصب رانتایم JoyAI-Video-Edit"""
37
+ repo_path = Path(os.environ["JOYAI_REPO"])
38
+
39
+ if not (repo_path / "deploy").exists():
40
+ print("📥 Cloning JoyAI-Video-Edit runtime from GitHub...")
41
+ result = subprocess.run(
42
+ ["git", "clone", "--depth", "1",
43
+ "https://github.com/jd-opensource/JoyAI-Video-Edit.git",
44
+ str(repo_path)],
45
+ capture_output=True, text=True
46
+ )
47
+ if result.returncode != 0:
48
+ print(f"❌ Git clone failed: {result.stderr}")
49
+ return False
50
+ print("✅ Runtime cloned successfully.")
51
+ else:
52
+ print("ℹ️ Runtime already exists, skipping clone.")
53
+
54
+ # اضافه کردن deploy به Python path
55
+ deploy_path = str(repo_path / "deploy")
56
+ if deploy_path not in sys.path:
57
+ sys.path.insert(0, deploy_path)
58
+ print(f"🔗 Added to sys.path: {deploy_path}")
59
+
60
+ return True
61
+
62
+
63
+ # ============================================================
64
+ # ✅ ۳. دانلود خودکار چک‌پوینت‌ها از HuggingFace
65
+ # ============================================================
66
+ def download_checkpoints():
67
+ """دانلود وزن‌های مدل از HF Hub"""
68
+ ckpt_root = Path(os.environ["JOYOMNI_CKPT_ROOT"])
69
+
70
+ # بررسی اینکه آیا چک‌پوینت‌ها قبلاً دانلود شده‌اند
71
+ dit_path = ckpt_root / "dit" / "joyai_video_edit_dit_0811.pth"
72
+ vae_config = ckpt_root / "vae" / "config.json"
73
+
74
+ if dit_path.exists() and vae_config.exists():
75
+ print("ℹ️ Checkpoints already downloaded.")
76
+ return True
77
+
78
+ try:
79
+ from huggingface_hub import hf_hub_download, snapshot_download
80
+
81
+ print("📥 Downloading JoyAI-Video-Edit checkpoints (~30GB)...")
82
+ print(" This may take 10-20 minutes on first run.")
83
+
84
+ # دانلود کل پوشه چک‌پوینت
85
+ snapshot_download(
86
+ repo_id="jdopensource/JoyAI-Video-Edit",
87
+ local_dir=str(ckpt_root),
88
+ allow_patterns=["dit/**", "vae/**", "text_encoder/**"],
89
+ ignore_patterns=["*.md", "*.txt", ".git*"],
90
+ )
91
+
92
+ print("✅ Checkpoints downloaded successfully.")
93
+ return True
94
+
95
+ except Exception as e:
96
+ print(f"❌ Checkpoint download failed: {e}")
97
+ print("💡 You may need to manually upload checkpoints to this Space.")
98
+ return False
99
+
100
+
101
+ # ============================================================
102
+ # ✅ ۴. بارگذاری مدل روی ZeroGPU
103
+ # ============================================================
104
  import spaces
105
 
106
+ runtime = None
107
+ load_error = None
108
+
109
+ @spaces.GPU(duration=120, gpu_size="xlarge")
110
  def load_model():
111
+ """بارگذاری JoyAI-Video-Edit روی GPU"""
112
+ global runtime, load_error
113
+
114
+ # مرحله ۱: نصب رانتایم
115
+ if not setup_runtime():
116
+ load_error = "Failed to setup runtime. Check git clone logs."
117
+ return
118
+
119
+ # مرحله ۲: دانلود چک‌پوینت‌ها
120
+ if not download_checkpoints():
121
+ load_error = "Failed to download checkpoints."
122
+ return
123
+
124
+ # مرحله ۳: بارگذاری مدل
125
  try:
126
+ print("🔄 Loading model into GPU memory...")
127
+ from xvideo.inductor_autotune_fix import install as _fix
128
  from xvideo.serving.joyomni_streaming import JoyOmniRuntime
129
 
130
+ _fix()
131
+ ckpt = Path(os.environ["JOYOMNI_CKPT_ROOT"])
132
 
133
+ runtime = JoyOmniRuntime.load(
134
+ ckpt / "dit" / "joyai_video_edit_dit_0811.pth",
135
+ vae_ckpt=ckpt / "vae",
136
+ text_encoder_ckpt=ckpt / "text_encoder",
 
137
  device="cuda",
138
  seed=42,
139
  warmup_height=480,
140
  warmup_width=840,
141
  )
142
+ load_error = None
143
+ print("✅ Model loaded successfully! Ready for inference.")
144
+
145
  except ImportError as e:
146
+ load_error = f"xvideo module import failed: {e}\n" \
147
+ f"sys.path includes: {[p for p in sys.path if 'JoyAI' in p]}"
148
+ print(f"❌ {load_error}")
149
  except Exception as e:
150
+ load_error = f"Model loading error: {str(e)}"
151
+ print(f"❌ {load_error}")
 
 
 
 
 
 
 
152
 
 
 
153
 
154
+ # ============================================================
155
+ # ✅ ۵. تابع ویرایش ویدیو (با GPU decorator)
156
+ # ============================================================
157
+ @spaces.GPU(duration=60, gpu_size="xlarge")
158
  def edit_video(video_path, prompt):
159
+ """ویرایش ویدیو با دستور متنی"""
160
  if runtime is None:
161
+ return None, f"❌ Model not available:\n{load_error}"
 
162
  if not video_path:
163
  return None, "❌ Please upload a video first."
164
+ if not prompt or not prompt.strip():
 
165
  return None, "❌ Please enter an editing instruction."
166
 
167
  try:
168
+ # TODO: جایگزینی با استریمینگ واقعی JoyAI
169
+ # مثال استفاده از runtime:
170
+ # output_frames = runtime.edit(video_path, prompt)
171
+ # output_path = save_frames(output_frames)
172
+ # return output_path, "✅ Done!"
173
+
174
+ return video_path, (
175
+ f"✅ Instruction received: '{prompt}'\n"
176
+ f"🟢 Model is loaded and ready.\n"
177
+ f"⚠️ Streaming inference pipeline not yet wired.\n"
178
+ f"💡 See TODO in app.py line ~150 to connect runtime.edit()"
179
+ )
180
  except Exception as e:
181
  return None, f"❌ Editing failed: {str(e)}"
182
 
183
+
184
+ # ============================================================
185
+ # ✅ ۶. رابط کاربری Gradio
186
+ # ============================================================
187
+ import gradio as gr
188
+
189
+ # بارگذاری اولیه (قبل از ساخت UI)
190
+ print("\n" + "="*60)
191
+ print("🚀 JoyAI-Video-Edit — Initializing...")
192
+ print("="*60)
193
+ load_model()
194
+
195
+ with gr.Blocks(
196
+ title="JoyAI Video Edit",
197
+ theme=gr.themes.Soft(),
198
+ ) as demo:
199
+ gr.Markdown("""
200
+ # 🎬 JoyAI-Video-Edit
201
+ ### Real-Time Open-Ended Video Editing with Autoregressive Diffusion (16B)
202
+ """)
203
 
204
  with gr.Row():
205
+ with gr.Column(scale=1):
206
+ input_video = gr.Video(
207
+ label="📹 Input Video",
208
+ sources=["upload", "webcam"],
209
+ height=360,
210
+ )
211
  edit_prompt = gr.Textbox(
212
+ label="✏️ Editing Instruction",
213
+ placeholder="Examples:\n• Transform into watercolor style\n• Add sunglasses to the person\n• Replace background with beach\n• Remove the cat on the left",
214
+ lines=3,
215
+ )
216
+ submit_btn = gr.Button(
217
+ "🚀 Edit Video",
218
+ variant="primary",
219
+ size="lg",
220
  )
 
221
 
222
+ with gr.Column(scale=1):
223
+ output_video = gr.Video(label="🎞️ Edited Output", height=360)
224
+ status_log = gr.Textbox(
225
+ label="📋 Status",
226
+ interactive=False,
227
+ lines=6,
228
+ value=f"{'✅ Model Ready' if runtime else '⚠️ ' + (load_error or 'Loading...')}",
229
+ )
230
 
231
  submit_btn.click(
232
  fn=edit_video,
233
  inputs=[input_video, edit_prompt],
234
+ outputs=[output_video, status_log],
235
  )
236
 
237
  gr.Markdown("""
238
+ ---
239
+ ### ℹ️ About
240
+ | Item | Detail |
241
+ |------|--------|
242
+ | **Model** | JoyAI-Video-Edit (16B Autoregressive Diffusion) |
243
+ | **Hardware** | ZeroGPU xlarge (RTX Pro 6000 Blackwell, 96GB) |
244
+ | **Capabilities** | Style transfer, object edit, subject add/remove/replace, background change |
245
+ | **Paper** | [arXiv:2608.03974](https://arxiv.org/abs/2608.03974) |
246
+ | **Source** | [jd-opensource/JoyAI-Video-Edit](https://github.com/jd-opensource/JoyAI-Video-Edit) |
247
+
248
+ ⏱️ **First run:** Model download (~30GB) + warmup may take 15-25 minutes.
249
  """)
250
 
251
+
252
+ # ============================================================
253
+ # ✅ ۷. راه‌اندازی سرور
254
+ # ============================================================
255
  if __name__ == "__main__":
256
+ demo.launch(
257
+ server_name="0.0.0.0",
258
+ server_port=7860,
259
+ ssr_mode=False,
260
+ show_api=False,
261
+ )