agrim12345 commited on
Commit
7b51f04
·
1 Parent(s): 4ef9c2c

Keep ZeroGPU lease active during pipeline; add per-run GPU env overrides

Browse files
Files changed (3) hide show
  1. app.py +151 -60
  2. pipelines/smart_keyframes_and_classify.py +5 -1
  3. run_manager.py +10 -1
app.py CHANGED
@@ -37,6 +37,73 @@ def _err_payload(message: str) -> Dict[str, Any]:
37
  return {"status": "error", "message": message}
38
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  def start_pipeline(
41
  variant: str,
42
  input_mode: str,
@@ -59,50 +126,33 @@ def start_pipeline(
59
  log_heartbeat_sec: float,
60
  ) -> Tuple[str, Dict[str, Any], str, str]:
61
  try:
62
- chosen_video_file = None
63
- chosen_video_url = None
64
- mode = (input_mode or "").strip().lower()
65
-
66
- if mode == "upload file":
67
- chosen_video_file = _clean_optional(video_file_path)
68
- if not chosen_video_file:
69
- raise ValueError("Select a video file for Upload File mode.")
70
- elif mode == "video url":
71
- chosen_video_url = _clean_optional(video_url)
72
- if not chosen_video_url:
73
- raise ValueError("Provide video_url for Video URL mode.")
74
- else:
75
- raise ValueError("Invalid input mode.")
76
-
77
- result = start_run(
78
- variant=variant,
79
- video_file_path=chosen_video_file,
80
- video_url=chosen_video_url,
81
- out_dir=_clean_optional(out_dir),
82
- python_bin=_clean_optional(python_bin),
83
- deepgram_model=deepgram_model,
84
- deepgram_language=_clean_optional(deepgram_language),
85
- deepgram_request_timeout_sec=float(deepgram_request_timeout_sec),
86
- deepgram_connect_timeout_sec=float(deepgram_connect_timeout_sec),
87
- deepgram_retries=int(deepgram_retries),
88
- deepgram_retry_backoff_sec=float(deepgram_retry_backoff_sec),
89
- force_deepgram=bool(force_deepgram),
90
- force_keyframes=bool(force_keyframes),
91
- pre_roll_sec=float(pre_roll_sec),
92
- gemini_model=gemini_model,
93
- similarity_threshold=float(similarity_threshold),
94
- temperature=float(temperature),
95
- log_heartbeat_sec=float(log_heartbeat_sec),
96
  )
97
- run_id = str(result["run_id"])
98
- logs = get_logs(run_id, tail_lines=120)
99
- return run_id, result, logs, run_id
100
  except Exception as e:
101
  msg = f"{type(e).__name__}: {e}"
102
  return "", _err_payload(msg), msg, ""
103
 
104
 
105
- @spaces.GPU
106
  def start_pipeline_gpu(
107
  variant: str,
108
  input_mode: str,
@@ -124,27 +174,68 @@ def start_pipeline_gpu(
124
  temperature: float,
125
  log_heartbeat_sec: float,
126
  ) -> Tuple[str, Dict[str, Any], str, str]:
127
- return start_pipeline(
128
- variant,
129
- input_mode,
130
- video_file_path,
131
- video_url,
132
- out_dir,
133
- python_bin,
134
- deepgram_model,
135
- deepgram_language,
136
- deepgram_request_timeout_sec,
137
- deepgram_connect_timeout_sec,
138
- deepgram_retries,
139
- deepgram_retry_backoff_sec,
140
- force_deepgram,
141
- force_keyframes,
142
- pre_roll_sec,
143
- gemini_model,
144
- similarity_threshold,
145
- temperature,
146
- log_heartbeat_sec,
147
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
 
149
 
150
  def refresh_status_logs(run_id: str, tail_lines: int) -> Tuple[Dict[str, Any], str]:
@@ -343,4 +434,4 @@ if __name__ == "__main__":
343
  if "ssr_mode" in inspect.signature(gr.Blocks.launch).parameters:
344
  launch_kwargs["ssr_mode"] = False
345
 
346
- demo.queue(default_concurrency_limit=2).launch(**launch_kwargs)
 
37
  return {"status": "error", "message": message}
38
 
39
 
40
+ ZERO_GPU_DURATION_SEC = int(os.getenv("ZERO_GPU_DURATION_SEC", "7200"))
41
+ ZERO_GPU_POLL_SEC = float(os.getenv("ZERO_GPU_POLL_SEC", "2.0"))
42
+
43
+
44
+ def _start_pipeline_job(
45
+ variant: str,
46
+ input_mode: str,
47
+ video_file_path: Optional[str],
48
+ video_url: Optional[str],
49
+ out_dir: Optional[str],
50
+ python_bin: Optional[str],
51
+ deepgram_model: str,
52
+ deepgram_language: Optional[str],
53
+ deepgram_request_timeout_sec: float,
54
+ deepgram_connect_timeout_sec: float,
55
+ deepgram_retries: int,
56
+ deepgram_retry_backoff_sec: float,
57
+ force_deepgram: bool,
58
+ force_keyframes: bool,
59
+ pre_roll_sec: float,
60
+ gemini_model: str,
61
+ similarity_threshold: float,
62
+ temperature: float,
63
+ log_heartbeat_sec: float,
64
+ env_overrides: Optional[Dict[str, str]] = None,
65
+ ) -> Tuple[str, Dict[str, Any], str, str]:
66
+ chosen_video_file = None
67
+ chosen_video_url = None
68
+ mode = (input_mode or "").strip().lower()
69
+
70
+ if mode == "upload file":
71
+ chosen_video_file = _clean_optional(video_file_path)
72
+ if not chosen_video_file:
73
+ raise ValueError("Select a video file for Upload File mode.")
74
+ elif mode == "video url":
75
+ chosen_video_url = _clean_optional(video_url)
76
+ if not chosen_video_url:
77
+ raise ValueError("Provide video_url for Video URL mode.")
78
+ else:
79
+ raise ValueError("Invalid input mode.")
80
+
81
+ result = start_run(
82
+ variant=variant,
83
+ video_file_path=chosen_video_file,
84
+ video_url=chosen_video_url,
85
+ out_dir=_clean_optional(out_dir),
86
+ python_bin=_clean_optional(python_bin),
87
+ deepgram_model=deepgram_model,
88
+ deepgram_language=_clean_optional(deepgram_language),
89
+ deepgram_request_timeout_sec=float(deepgram_request_timeout_sec),
90
+ deepgram_connect_timeout_sec=float(deepgram_connect_timeout_sec),
91
+ deepgram_retries=int(deepgram_retries),
92
+ deepgram_retry_backoff_sec=float(deepgram_retry_backoff_sec),
93
+ force_deepgram=bool(force_deepgram),
94
+ force_keyframes=bool(force_keyframes),
95
+ pre_roll_sec=float(pre_roll_sec),
96
+ gemini_model=gemini_model,
97
+ similarity_threshold=float(similarity_threshold),
98
+ temperature=float(temperature),
99
+ log_heartbeat_sec=float(log_heartbeat_sec),
100
+ env_overrides=env_overrides or {},
101
+ )
102
+ run_id = str(result["run_id"])
103
+ logs = get_logs(run_id, tail_lines=120)
104
+ return run_id, result, logs, run_id
105
+
106
+
107
  def start_pipeline(
108
  variant: str,
109
  input_mode: str,
 
126
  log_heartbeat_sec: float,
127
  ) -> Tuple[str, Dict[str, Any], str, str]:
128
  try:
129
+ return _start_pipeline_job(
130
+ variant,
131
+ input_mode,
132
+ video_file_path,
133
+ video_url,
134
+ out_dir,
135
+ python_bin,
136
+ deepgram_model,
137
+ deepgram_language,
138
+ deepgram_request_timeout_sec,
139
+ deepgram_connect_timeout_sec,
140
+ deepgram_retries,
141
+ deepgram_retry_backoff_sec,
142
+ force_deepgram,
143
+ force_keyframes,
144
+ pre_roll_sec,
145
+ gemini_model,
146
+ similarity_threshold,
147
+ temperature,
148
+ log_heartbeat_sec,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  )
 
 
 
150
  except Exception as e:
151
  msg = f"{type(e).__name__}: {e}"
152
  return "", _err_payload(msg), msg, ""
153
 
154
 
155
+ @spaces.GPU(duration=ZERO_GPU_DURATION_SEC)
156
  def start_pipeline_gpu(
157
  variant: str,
158
  input_mode: str,
 
174
  temperature: float,
175
  log_heartbeat_sec: float,
176
  ) -> Tuple[str, Dict[str, Any], str, str]:
177
+ try:
178
+ run_id, start_result, _, _ = _start_pipeline_job(
179
+ variant,
180
+ input_mode,
181
+ video_file_path,
182
+ video_url,
183
+ out_dir,
184
+ python_bin,
185
+ deepgram_model,
186
+ deepgram_language,
187
+ deepgram_request_timeout_sec,
188
+ deepgram_connect_timeout_sec,
189
+ deepgram_retries,
190
+ deepgram_retry_backoff_sec,
191
+ force_deepgram,
192
+ force_keyframes,
193
+ pre_roll_sec,
194
+ gemini_model,
195
+ similarity_threshold,
196
+ temperature,
197
+ log_heartbeat_sec,
198
+ env_overrides={
199
+ "OCR_MODE": "gpu",
200
+ "OCR_BACKEND_GPU": "easyocr",
201
+ "YOLO_DEVICE": "0",
202
+ "CUDA_VISIBLE_DEVICES": "0",
203
+ },
204
+ )
205
+
206
+ started = time.time()
207
+ deadline = started + float(ZERO_GPU_DURATION_SEC)
208
+ sleep_sec = max(1.0, float(ZERO_GPU_POLL_SEC))
209
+ final_status: Dict[str, Any] = {}
210
+ while True:
211
+ final_status = get_status(run_id)
212
+ state = str(final_status.get("status", "running")).lower()
213
+ if state in {"succeeded", "failed"}:
214
+ break
215
+ if time.time() >= deadline:
216
+ logs = get_logs(run_id, tail_lines=500)
217
+ return run_id, {
218
+ "status": "running",
219
+ "run_id": run_id,
220
+ "message": (
221
+ f"Run is still active after {ZERO_GPU_DURATION_SEC}s. "
222
+ "Continue monitoring in Track Run."
223
+ ),
224
+ "start_response": start_result,
225
+ "latest_status": final_status,
226
+ }, logs, run_id
227
+ time.sleep(sleep_sec)
228
+
229
+ logs = get_logs(run_id, tail_lines=600)
230
+ return run_id, {
231
+ "status": str(final_status.get("status", "unknown")),
232
+ "run_id": run_id,
233
+ "start_response": start_result,
234
+ "final_status": final_status,
235
+ }, logs, run_id
236
+ except Exception as e:
237
+ msg = f"{type(e).__name__}: {e}"
238
+ return "", _err_payload(msg), msg, ""
239
 
240
 
241
  def refresh_status_logs(run_id: str, tail_lines: int) -> Tuple[Dict[str, Any], str]:
 
434
  if "ssr_mode" in inspect.signature(gr.Blocks.launch).parameters:
435
  launch_kwargs["ssr_mode"] = False
436
 
437
+ demo.queue(default_concurrency_limit=1).launch(**launch_kwargs)
pipelines/smart_keyframes_and_classify.py CHANGED
@@ -360,7 +360,11 @@ def _resolve_ocr_backend_for_mode(mode: str) -> Tuple[str, bool]:
360
  mode = _choose_ocr_mode(mode)
361
  gpu_available = _has_cuda()
362
 
363
- if mode == "gpu":
 
 
 
 
364
  candidates = [OCR_BACKEND_GPU, "easyocr", "paddle", "rapidocr"]
365
  else:
366
  candidates = [OCR_BACKEND_CPU, "rapidocr", "easyocr", "paddle"]
 
360
  mode = _choose_ocr_mode(mode)
361
  gpu_available = _has_cuda()
362
 
363
+ # If GPU mode is requested but CUDA is not visible in this process,
364
+ # prefer CPU-first backends to avoid expensive GPU-oriented model downloads.
365
+ if mode == "gpu" and not gpu_available:
366
+ candidates = [OCR_BACKEND_CPU, "rapidocr", OCR_BACKEND_GPU, "easyocr", "paddle"]
367
+ elif mode == "gpu":
368
  candidates = [OCR_BACKEND_GPU, "easyocr", "paddle", "rapidocr"]
369
  else:
370
  candidates = [OCR_BACKEND_CPU, "rapidocr", "easyocr", "paddle"]
run_manager.py CHANGED
@@ -412,6 +412,7 @@ def start_run(
412
  similarity_threshold: float,
413
  temperature: float,
414
  log_heartbeat_sec: float = 10.0,
 
415
  ) -> Dict[str, Any]:
416
  script_name = {
417
  "full": "run_pipeline_all.py",
@@ -487,6 +488,12 @@ def start_run(
487
  child_env.setdefault("OCR_MODE", "cpu")
488
  child_env.setdefault("OCR_BACKEND_CPU", "rapidocr")
489
  child_env.setdefault("OCR_BACKEND_GPU", "easyocr")
 
 
 
 
 
 
490
 
491
  log_fh = open(logs_path, "a", encoding="utf-8", buffering=1)
492
  log_fh.write(
@@ -497,7 +504,8 @@ def start_run(
497
  f"[runner] python_unbuffered=1\n"
498
  f"[runner] ocr_mode={child_env.get('OCR_MODE')} "
499
  f"ocr_backend_cpu={child_env.get('OCR_BACKEND_CPU')} "
500
- f"ocr_backend_gpu={child_env.get('OCR_BACKEND_GPU')}\n\n"
 
501
  )
502
  log_fh.flush()
503
 
@@ -524,6 +532,7 @@ def start_run(
524
  "out_dir": str(out_path),
525
  "logs_path": str(logs_path),
526
  "heartbeat_interval_sec": float(log_heartbeat_sec),
 
527
  "output_files": _build_output_files(out_path, variant),
528
  }
529
  _write_json(_meta_path(run_id), meta)
 
412
  similarity_threshold: float,
413
  temperature: float,
414
  log_heartbeat_sec: float = 10.0,
415
+ env_overrides: Optional[Dict[str, str]] = None,
416
  ) -> Dict[str, Any]:
417
  script_name = {
418
  "full": "run_pipeline_all.py",
 
488
  child_env.setdefault("OCR_MODE", "cpu")
489
  child_env.setdefault("OCR_BACKEND_CPU", "rapidocr")
490
  child_env.setdefault("OCR_BACKEND_GPU", "easyocr")
491
+ child_env.setdefault("YOLO_DEVICE", "cpu")
492
+ for k, v in (env_overrides or {}).items():
493
+ key = str(k or "").strip()
494
+ if not key or v is None:
495
+ continue
496
+ child_env[key] = str(v)
497
 
498
  log_fh = open(logs_path, "a", encoding="utf-8", buffering=1)
499
  log_fh.write(
 
504
  f"[runner] python_unbuffered=1\n"
505
  f"[runner] ocr_mode={child_env.get('OCR_MODE')} "
506
  f"ocr_backend_cpu={child_env.get('OCR_BACKEND_CPU')} "
507
+ f"ocr_backend_gpu={child_env.get('OCR_BACKEND_GPU')} "
508
+ f"yolo_device={child_env.get('YOLO_DEVICE')}\n\n"
509
  )
510
  log_fh.flush()
511
 
 
532
  "out_dir": str(out_path),
533
  "logs_path": str(logs_path),
534
  "heartbeat_interval_sec": float(log_heartbeat_sec),
535
+ "env_overrides": {k: str(v) for k, v in (env_overrides or {}).items() if v is not None},
536
  "output_files": _build_output_files(out_path, variant),
537
  }
538
  _write_json(_meta_path(run_id), meta)