sdfafdfsdf commited on
Commit
deb6554
·
verified ·
1 Parent(s): 674481b

Add fresh RunPod setup script

Browse files
Files changed (1) hide show
  1. setup_runpod.py +291 -0
setup_runpod.py ADDED
@@ -0,0 +1,291 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ RunPod Fresh Setup Script for Qwen Image Edit
4
+ ==============================================
5
+ Downloads everything from YOUR OWN HuggingFace repos:
6
+ - App code: sdfafdfsdf/Qwen-Image-Edit-App
7
+ - Models: sdfafdfsdf/Phr00t-Qwen-Rapid-AIO (20GB)
8
+ sdfafdfsdf/Qwen-Image-Edit-2511 (16GB)
9
+ sdfafdfsdf/BFS-Best-Face-Swap (1.3GB)
10
+ sdfafdfsdf/Qwen-Image-Edit-2511-Multiple-Angles-LoRA (282MB)
11
+ sdfafdfsdf/vllm-flash-attn3 (807MB)
12
+
13
+ Usage:
14
+ 1. Upload this script to your RunPod
15
+ 2. Run: python3 setup_runpod.py
16
+ 3. The app will auto-start at the end
17
+
18
+ Set your HF token as an environment variable before running:
19
+ export HF_TOKEN="hf_your_token_here"
20
+
21
+ Or pass it as a command line argument:
22
+ python3 setup_runpod.py --token hf_your_token_here
23
+ """
24
+
25
+ import os
26
+ import sys
27
+ import subprocess
28
+ import argparse
29
+ import time
30
+
31
+ # ═══════════════════════════════════════════════════════
32
+ # CONFIGURATION — Change these if you rename your repos
33
+ # ═══════════════════════════════════════════════════════
34
+
35
+ HF_USERNAME = "sdfafdfsdf"
36
+
37
+ # App code repo (small files: app.py, qwenimage/, camera_control_ui, etc.)
38
+ APP_REPO = f"{HF_USERNAME}/Qwen-Image-Edit-App"
39
+
40
+ # Model repos (large files: transformer weights, VAE, text encoder, etc.)
41
+ MODEL_REPOS = [
42
+ f"{HF_USERNAME}/Phr00t-Qwen-Rapid-AIO", # 20GB - AIO transformer
43
+ f"{HF_USERNAME}/Qwen-Image-Edit-2511", # 16GB - Pipeline (VAE, text encoder)
44
+ f"{HF_USERNAME}/BFS-Best-Face-Swap", # 1.3GB - Face swap LoRA
45
+ f"{HF_USERNAME}/Qwen-Image-Edit-2511-Multiple-Angles-LoRA", # 282MB - Angles LoRA
46
+ f"{HF_USERNAME}/vllm-flash-attn3", # 807MB - Flash attention kernel
47
+ ]
48
+
49
+ # Directories
50
+ WORKSPACE_DIR = "/workspace"
51
+ APP_DIR = os.path.join(WORKSPACE_DIR, "Qwen-Image-Edit")
52
+ VENV_DIR = os.path.join(WORKSPACE_DIR, "venv")
53
+ CACHE_DIR = os.path.join(WORKSPACE_DIR, "cache")
54
+ HF_HOME = os.path.join(CACHE_DIR, "huggingface")
55
+ PIP_CACHE = os.path.join(CACHE_DIR, "pip")
56
+ TMP_DIR = os.path.join(WORKSPACE_DIR, "tmp")
57
+
58
+
59
+ # ═══════════════════════════════════════════════════════
60
+ # HELPERS
61
+ # ═══════════════════════════════════════════════════════
62
+
63
+ def log(msg, level="INFO"):
64
+ """Print a formatted log message."""
65
+ icons = {"INFO": "ℹ️ ", "OK": "✅", "WARN": "⚠️ ", "ERR": "❌", "DL": "📦", "RUN": "🚀"}
66
+ icon = icons.get(level, " ")
67
+ print(f"{icon} {msg}")
68
+
69
+
70
+ def run(command, cwd=None, env_extra=None, check=True):
71
+ """Run a shell command, stream output, return exit code."""
72
+ log(f"Running: {command}", "RUN")
73
+ env = os.environ.copy()
74
+ env["TMPDIR"] = TMP_DIR
75
+ env["PIP_CACHE_DIR"] = PIP_CACHE
76
+ env["HF_HOME"] = HF_HOME
77
+ if env_extra:
78
+ env.update(env_extra)
79
+
80
+ proc = subprocess.Popen(
81
+ command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
82
+ text=True, cwd=cwd, env=env
83
+ )
84
+ for line in proc.stdout:
85
+ print(line, end="")
86
+ proc.wait()
87
+
88
+ if proc.returncode != 0 and check:
89
+ log(f"Command failed (exit {proc.returncode}): {command}", "ERR")
90
+ return proc.returncode
91
+
92
+
93
+ def ensure_dirs():
94
+ """Create all necessary directories."""
95
+ for d in [APP_DIR, VENV_DIR, CACHE_DIR, HF_HOME, PIP_CACHE, TMP_DIR]:
96
+ os.makedirs(d, exist_ok=True)
97
+
98
+
99
+ # ═══════════════════════════════════════════════════════
100
+ # STEP 1: Download app code
101
+ # ═══════════════════════════════════════════════════════
102
+
103
+ def download_app_code(token):
104
+ """Download app code from your HF repo."""
105
+ log(f"Downloading app code from {APP_REPO}...", "DL")
106
+
107
+ pip = os.path.join(VENV_DIR, "bin", "pip")
108
+ python = os.path.join(VENV_DIR, "bin", "python")
109
+
110
+ # Use huggingface_hub to download
111
+ run(f"""{python} -c "
112
+ from huggingface_hub import snapshot_download
113
+ snapshot_download(
114
+ repo_id='{APP_REPO}',
115
+ repo_type='model',
116
+ local_dir='{APP_DIR}',
117
+ token='{token}'
118
+ )
119
+ print('App code downloaded successfully!')
120
+ " """)
121
+
122
+ if os.path.exists(os.path.join(APP_DIR, "app.py")):
123
+ log("App code downloaded successfully!", "OK")
124
+ else:
125
+ log("App code download may have failed — app.py not found!", "ERR")
126
+ sys.exit(1)
127
+
128
+
129
+ # ═════════════════════════════════���═════════════════════
130
+ # STEP 2: Download heavy models
131
+ # ═══════════════════════════════════════════════════════
132
+
133
+ def download_models(token):
134
+ """Download all model repos (cached in HF_HOME)."""
135
+ python = os.path.join(VENV_DIR, "bin", "python")
136
+
137
+ for repo in MODEL_REPOS:
138
+ log(f"Downloading model: {repo}...", "DL")
139
+ run(f"""{python} -c "
140
+ from huggingface_hub import snapshot_download
141
+ snapshot_download(
142
+ repo_id='{repo}',
143
+ repo_type='model',
144
+ token='{token}'
145
+ )
146
+ print('Downloaded: {repo}')
147
+ " """)
148
+
149
+ log("All models downloaded!", "OK")
150
+
151
+
152
+ # ═══════════════════════════════════════════════════════
153
+ # STEP 3: Set up Python venv
154
+ # ═══════════════════════════════════════════════════════
155
+
156
+ def setup_venv():
157
+ """Create virtual environment if it doesn't exist."""
158
+ if not os.path.exists(os.path.join(VENV_DIR, "bin", "python")):
159
+ log("Creating virtual environment...", "INFO")
160
+ run(f"python3 -m venv {VENV_DIR}")
161
+ else:
162
+ log("Virtual environment already exists.", "OK")
163
+
164
+ # Upgrade pip
165
+ pip = os.path.join(VENV_DIR, "bin", "pip")
166
+ run(f"{pip} install --upgrade pip")
167
+
168
+
169
+ # ═══════════════════════════════════════════════════════
170
+ # STEP 4: Install dependencies
171
+ # ═══════════════════════════════════════════════════════
172
+
173
+ def install_dependencies():
174
+ """Install Python packages from requirements.txt."""
175
+ pip = os.path.join(VENV_DIR, "bin", "pip")
176
+ req_file = os.path.join(APP_DIR, "requirements.txt")
177
+
178
+ if os.path.exists(req_file):
179
+ log("Installing dependencies from requirements.txt...", "DL")
180
+ run(f"{pip} install -r {req_file}")
181
+ log("Dependencies installed!", "OK")
182
+ else:
183
+ log("No requirements.txt found!", "WARN")
184
+
185
+ # Ensure huggingface_hub is available (needed for model downloads)
186
+ run(f"{pip} install huggingface_hub")
187
+
188
+
189
+ # ═══════════════════════════════════════════════════════
190
+ # STEP 5: Start the app
191
+ # ═══════════════════════════════════════════════════════
192
+
193
+ def start_app():
194
+ """Start the Gradio app."""
195
+ python = os.path.join(VENV_DIR, "bin", "python")
196
+ app_py = os.path.join(APP_DIR, "app.py")
197
+
198
+ if not os.path.exists(app_py):
199
+ log("app.py not found, cannot start!", "ERR")
200
+ return
201
+
202
+ log("Starting the Gradio app...", "RUN")
203
+
204
+ env_extra = {
205
+ "PYTHONPATH": APP_DIR,
206
+ "PYTHONUNBUFFERED": "1",
207
+ }
208
+
209
+ # Run in foreground so user can see output
210
+ run(f"{python} {app_py}", cwd=APP_DIR, env_extra=env_extra, check=False)
211
+
212
+
213
+ # ═══════════════════════════════════════════════════════
214
+ # MAIN
215
+ # ═══════════════════════════════════════════════════════
216
+
217
+ def main():
218
+ parser = argparse.ArgumentParser(description="Setup Qwen Image Edit on a fresh RunPod")
219
+ parser.add_argument("--token", type=str, default=None,
220
+ help="HuggingFace token (or set HF_TOKEN env var)")
221
+ parser.add_argument("--skip-models", action="store_true",
222
+ help="Skip model downloads (if already cached)")
223
+ parser.add_argument("--skip-app", action="store_true",
224
+ help="Skip app code download (if already present)")
225
+ parser.add_argument("--skip-deps", action="store_true",
226
+ help="Skip dependency installation")
227
+ parser.add_argument("--no-start", action="store_true",
228
+ help="Don't auto-start the app after setup")
229
+ args = parser.parse_args()
230
+
231
+ # Get token
232
+ token = args.token or os.environ.get("HF_TOKEN", "")
233
+ if not token:
234
+ log("No HuggingFace token provided!", "ERR")
235
+ log("Set HF_TOKEN environment variable or pass --token", "INFO")
236
+ sys.exit(1)
237
+
238
+ print("=" * 60)
239
+ print(" Qwen Image Edit — Fresh RunPod Setup")
240
+ print("=" * 60)
241
+ start_time = time.time()
242
+
243
+ # Step 0: Create directories
244
+ log("Creating directories...")
245
+ ensure_dirs()
246
+
247
+ # Step 1: Set up venv (needed before downloading, since we use huggingface_hub)
248
+ log("Setting up Python virtual environment...")
249
+ setup_venv()
250
+
251
+ # Step 2: Install huggingface_hub first (needed for downloads)
252
+ pip = os.path.join(VENV_DIR, "bin", "pip")
253
+ run(f"{pip} install huggingface_hub")
254
+
255
+ # Step 3: Download app code
256
+ if not args.skip_app:
257
+ download_app_code(token)
258
+ else:
259
+ log("Skipping app code download (--skip-app)", "INFO")
260
+
261
+ # Step 4: Install full dependencies
262
+ if not args.skip_deps:
263
+ install_dependencies()
264
+ else:
265
+ log("Skipping dependency installation (--skip-deps)", "INFO")
266
+
267
+ # Step 5: Download models
268
+ if not args.skip_models:
269
+ download_models(token)
270
+ else:
271
+ log("Skipping model downloads (--skip-models)", "INFO")
272
+
273
+ elapsed = time.time() - start_time
274
+ minutes = int(elapsed // 60)
275
+ seconds = int(elapsed % 60)
276
+
277
+ print("")
278
+ print("=" * 60)
279
+ log(f"Setup completed in {minutes}m {seconds}s!", "OK")
280
+ print("=" * 60)
281
+
282
+ # Step 6: Start the app
283
+ if not args.no_start:
284
+ start_app()
285
+ else:
286
+ log("Skipping app start (--no-start). To start manually:", "INFO")
287
+ log(f" bash /workspace/start_app.sh", "INFO")
288
+
289
+
290
+ if __name__ == "__main__":
291
+ main()