AdhyanshVerma commited on
Commit
9e2b20e
·
verified ·
1 Parent(s): 1ac18a2

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +177 -3
main.py CHANGED
@@ -164,6 +164,172 @@ def trigger_kaggle_test():
164
 
165
  return "\n".join(logs)
166
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  with gr.Blocks() as app:
168
  gr.Markdown("# YouTube Video Orchestrator Host")
169
  gr.Markdown("Deploy this to Hugging Face Spaces or run locally. It fetches pending links from your database and delegates them to FastAPI workers or Kaggle.")
@@ -182,10 +348,18 @@ with gr.Blocks() as app:
182
 
183
  with gr.Tab("Kaggle Workers"):
184
  gr.Markdown("Trigger Kaggle notebook workers. Note: You must mount `kaggle.json` to `~/.kaggle/kaggle.json` in the container for this to work.")
185
- test_run_btn = gr.Button("Run Simple Kaggle Test Worker", variant="secondary")
186
- kaggle_log = gr.Textbox(label="Kaggle Logs", lines=10)
187
 
188
- test_run_btn.click(fn=trigger_kaggle_test, inputs=[], outputs=kaggle_log)
 
 
 
 
 
 
 
 
 
 
189
 
190
  if __name__ == "__main__":
191
  app.launch(server_name="0.0.0.0", server_port=7860)
 
164
 
165
  return "\n".join(logs)
166
 
167
+ def create_worker_notebook(worker_dir, config_name):
168
+ notebook_content = {
169
+ "cells": [
170
+ {
171
+ "cell_type": "code",
172
+ "execution_count": None,
173
+ "metadata": {},
174
+ "outputs": [],
175
+ "source": [
176
+ "!pip install openai huggingface_hub yt-dlp opencv-python-headless\n"
177
+ ]
178
+ },
179
+ {
180
+ "cell_type": "code",
181
+ "execution_count": None,
182
+ "metadata": {},
183
+ "outputs": [],
184
+ "source": [
185
+ "import json\n",
186
+ "import os\n",
187
+ "import subprocess\n",
188
+ "import sys\n",
189
+ "\n",
190
+ f"with open('{config_name}') as f:\n",
191
+ " config = json.load(f)\n",
192
+ "\n",
193
+ "links = config['links']\n",
194
+ "api_key = config['api_key']\n",
195
+ "os.environ['FEATHERLESS_API_KEY'] = api_key\n",
196
+ "\n",
197
+ "print(f'Starting worker with {len(links)} links using API Key: {api_key[:5]}...')\n",
198
+ "\n",
199
+ "for link in links:\n",
200
+ " print(f'\\n[+] Processing: {link}')\n",
201
+ " # 1. Download Video\n",
202
+ " dl_cmd = [sys.executable, 'worker/youtube_worker/downloader.py', link, '--resolution', 'HD', '-o', 'test_output']\n",
203
+ " res = subprocess.run(dl_cmd, capture_output=True, text=True)\n",
204
+ " if res.returncode != 0:\n",
205
+ " print(f'Download failed:\\n{res.stderr}')\n",
206
+ " continue\n",
207
+ " \n",
208
+ " # Find the downloaded video path from stdout (last line)\n",
209
+ " lines = res.stdout.strip().split('\\n')\n",
210
+ " video_path = lines[-1]\n",
211
+ " if not os.path.exists(video_path):\n",
212
+ " print(f'Could not find downloaded video at: {video_path}')\n",
213
+ " continue\n",
214
+ " \n",
215
+ " print(f'[+] Video downloaded to: {video_path}')\n",
216
+ " \n",
217
+ " # 2. Curate Model (Video Worker)\n",
218
+ " prompt = 'Analyze this video comprehensively. Focus on visuals, objects, and text.'\n",
219
+ " vw_cmd = [sys.executable, 'worker/models_worker/video_worker.py', '--video-url', video_path, '--prompt', prompt, '--api-key', api_key]\n",
220
+ " print('[+] Running model curation...')\n",
221
+ " subprocess.run(vw_cmd)\n",
222
+ " \n",
223
+ " # 3. Optional: Upload to HF\n",
224
+ " # hf_cmd = [sys.executable, 'worker/hf_uploader.py', 'test_output']\n",
225
+ " # subprocess.run(hf_cmd)\n",
226
+ "\n",
227
+ "print('\\nAll tasks completed!')\n"
228
+ ]
229
+ }
230
+ ],
231
+ "metadata": {
232
+ "kernelspec": {
233
+ "display_name": "Python 3",
234
+ "language": "python",
235
+ "name": "python3"
236
+ },
237
+ "language_info": {
238
+ "name": "python"
239
+ }
240
+ },
241
+ "nbformat": 4,
242
+ "nbformat_minor": 4
243
+ }
244
+
245
+ with open(worker_dir / "notebook.ipynb", "w") as f:
246
+ json.dump(notebook_content, f, indent=2)
247
+
248
+ def trigger_kaggle_workers(db_path, links_per_worker, max_workers):
249
+ api_keys, links = fetch_data(db_path, limit_links=int(links_per_worker) * int(max_workers))
250
+ if not api_keys:
251
+ return "Error: No API keys found in DB."
252
+ if not links:
253
+ return "Error: No pending links found in DB."
254
+
255
+ username = get_kaggle_username()
256
+ workers_dir = Path("kaggle_workers_out")
257
+ if workers_dir.exists():
258
+ shutil.rmtree(workers_dir)
259
+ workers_dir.mkdir(parents=True)
260
+
261
+ logs = []
262
+ logs.append(f"Loaded {len(api_keys)} API keys and {len(links)} links.")
263
+
264
+ link_chunks = [links[i:i + int(links_per_worker)] for i in range(0, len(links), int(links_per_worker))]
265
+ logs.append(f"Divided into {len(link_chunks)} worker chunks.")
266
+
267
+ for idx, chunk in enumerate(link_chunks):
268
+ worker_id = f"worker-{uuid.uuid4().hex[:8]}"
269
+ worker_title = f"yt-worker-{idx+1}-{uuid.uuid4().hex[:4]}"
270
+
271
+ api_key = api_keys[idx % len(api_keys)]
272
+ worker_path = workers_dir / worker_id
273
+ worker_path.mkdir(parents=True)
274
+
275
+ # Copy worker if exists locally
276
+ if Path("worker").exists():
277
+ shutil.copytree("worker", worker_path / "worker")
278
+ else:
279
+ # We copy from parent directory if this is running locally, otherwise it's an error on HF unless packed
280
+ parent_worker = Path("../hf_space_worker/worker")
281
+ if parent_worker.exists():
282
+ shutil.copytree(parent_worker, worker_path / "worker")
283
+ else:
284
+ logs.append("Warning: 'worker' directory not found. Kaggle notebook may fail.")
285
+
286
+ if Path("cookies.txt").exists():
287
+ shutil.copy("cookies.txt", worker_path / "cookies.txt")
288
+ elif Path("../cookies.txt").exists():
289
+ shutil.copy("../cookies.txt", worker_path / "cookies.txt")
290
+
291
+ config_name = "worker_config.json"
292
+ config_data = {
293
+ "links": chunk,
294
+ "api_key": api_key,
295
+ }
296
+ with open(worker_path / config_name, "w") as f:
297
+ json.dump(config_data, f, indent=2)
298
+
299
+ create_worker_notebook(worker_path, config_name)
300
+
301
+ metadata = {
302
+ "id": f"{username}/{worker_title}",
303
+ "title": worker_title,
304
+ "code_file": "notebook.ipynb",
305
+ "language": "python",
306
+ "kernel_type": "notebook",
307
+ "is_private": True,
308
+ "enable_gpu": False,
309
+ "enable_internet": True,
310
+ "dataset_sources": [],
311
+ "competition_sources": [],
312
+ "kernel_sources": []
313
+ }
314
+ with open(worker_path / "kernel-metadata.json", "w") as f:
315
+ json.dump(metadata, f, indent=2)
316
+
317
+ logs.append(f"Prepared Worker {idx+1}: {worker_title} with {len(chunk)} links.")
318
+
319
+ command = ["kaggle", "kernels", "push", "-p", str(worker_path)]
320
+ logs.append(f"Pushing {worker_title} to Kaggle...")
321
+ try:
322
+ res = subprocess.run(command, capture_output=True, text=True)
323
+ if res.returncode == 0:
324
+ logs.append("Push successful.")
325
+ else:
326
+ logs.append("Push failed.")
327
+ logs.append(res.stderr)
328
+ except Exception as e:
329
+ logs.append(f"Error: {e}")
330
+
331
+ return "\n".join(logs)
332
+
333
  with gr.Blocks() as app:
334
  gr.Markdown("# YouTube Video Orchestrator Host")
335
  gr.Markdown("Deploy this to Hugging Face Spaces or run locally. It fetches pending links from your database and delegates them to FastAPI workers or Kaggle.")
 
348
 
349
  with gr.Tab("Kaggle Workers"):
350
  gr.Markdown("Trigger Kaggle notebook workers. Note: You must mount `kaggle.json` to `~/.kaggle/kaggle.json` in the container for this to work.")
 
 
351
 
352
+ with gr.Row():
353
+ k_db_input = gr.Textbox(label="DB Path", value="/data/db/accounts.db")
354
+ k_links_per_worker = gr.Number(label="Links per worker", value=2)
355
+ k_max_workers = gr.Number(label="Max Workers", value=5)
356
+
357
+ k_run_btn = gr.Button("Run Kaggle Orchestration", variant="primary")
358
+ k_test_run_btn = gr.Button("Run Simple Kaggle Test Worker", variant="secondary")
359
+ kaggle_log = gr.Textbox(label="Kaggle Logs", lines=15)
360
+
361
+ k_run_btn.click(fn=trigger_kaggle_workers, inputs=[k_db_input, k_links_per_worker, k_max_workers], outputs=kaggle_log)
362
+ k_test_run_btn.click(fn=trigger_kaggle_test, inputs=[], outputs=kaggle_log)
363
 
364
  if __name__ == "__main__":
365
  app.launch(server_name="0.0.0.0", server_port=7860)