ArsVie commited on
Commit
5d7d394
Β·
verified Β·
1 Parent(s): 3d673f0

casting UX + batching

Browse files
Files changed (1) hide show
  1. comfy_embed.py +37 -16
comfy_embed.py CHANGED
@@ -485,16 +485,11 @@ def _validate(prompt: dict, prompt_id: str):
485
  return # validation is optional; stay quiet
486
 
487
 
488
- @_gpu
489
- def run_workflow(workflow: dict, client_id: str) -> Optional[dict]:
490
- """Execute one workflow graph in-process and return the first SaveImage
491
- output as an img_info dict (shaped like the HTTP _comfy_wait return), or
492
- None on failure. Runs entirely inside one @spaces.GPU allocation.
493
- """
494
- if not _ensure():
495
- return None
496
  executor = _STATE["executor"]
497
-
498
  prompt_id = f"{client_id}-{int(time.time() * 1000)}"
499
  self_outputs = _output_node_ids(workflow)
500
  prefixes = _save_prefixes(workflow)
@@ -502,7 +497,6 @@ def run_workflow(workflow: dict, client_id: str) -> Optional[dict]:
502
  started = time.time()
503
 
504
  _validate(workflow, prompt_id)
505
-
506
  try:
507
  # execute(prompt, prompt_id, extra_data, execute_outputs) β€” the stable
508
  # core signature across the versions we pin.
@@ -527,12 +521,39 @@ def run_workflow(workflow: dict, client_id: str) -> Optional[dict]:
527
  f"(prefixes={prefixes})")
528
  return None
529
  newest = max(candidates, key=os.path.getmtime)
530
- return {
531
- "filename": os.path.basename(newest),
532
- "subfolder": "",
533
- "type": "output",
534
- "_path": newest,
535
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
536
 
537
 
538
  # ═══════════════════════════════════════════════════════════════════════
 
485
  return # validation is optional; stay quiet
486
 
487
 
488
+ def _execute_one(workflow: dict, client_id: str) -> Optional[dict]:
489
+ """Run ONE workflow on the (already-initialised) executor and return its
490
+ first-image info dict. NOT decorated β€” call only from inside an @spaces.GPU
491
+ function (run_workflow / run_batch) so the CUDA work is in a GPU window."""
 
 
 
 
492
  executor = _STATE["executor"]
 
493
  prompt_id = f"{client_id}-{int(time.time() * 1000)}"
494
  self_outputs = _output_node_ids(workflow)
495
  prefixes = _save_prefixes(workflow)
 
497
  started = time.time()
498
 
499
  _validate(workflow, prompt_id)
 
500
  try:
501
  # execute(prompt, prompt_id, extra_data, execute_outputs) β€” the stable
502
  # core signature across the versions we pin.
 
521
  f"(prefixes={prefixes})")
522
  return None
523
  newest = max(candidates, key=os.path.getmtime)
524
+ return {"filename": os.path.basename(newest), "subfolder": "",
525
+ "type": "output", "_path": newest}
526
+
527
+
528
+ @_gpu
529
+ def run_workflow(workflow: dict, client_id: str) -> Optional[dict]:
530
+ """Execute one workflow graph in-process and return its first-image info
531
+ dict (shaped like the HTTP _comfy_wait return), or None. Runs inside one
532
+ @spaces.GPU allocation."""
533
+ if not _ensure():
534
+ return None
535
+ return _execute_one(workflow, client_id)
536
+
537
+
538
+ @_gpu
539
+ def run_batch(items: list) -> list:
540
+ """Execute several workflows in ONE @spaces.GPU allocation and return a
541
+ list of their first-image info dicts (None for any that failed), in order.
542
+
543
+ This is the ZeroGPU cost win: each GPU call carries ~tens of seconds of
544
+ allocation/attach overhead, so baking a character's whole expression set in
545
+ one call instead of one-call-per-image collapses that overhead. `items` is
546
+ a list of (workflow, client_id) tuples."""
547
+ if not _ensure():
548
+ return [None] * len(items)
549
+ results = []
550
+ for workflow, client_id in items:
551
+ try:
552
+ results.append(_execute_one(workflow, client_id))
553
+ except Exception as e:
554
+ print(f"[comfy-embed] batch item '{client_id}' failed: {e}")
555
+ results.append(None)
556
+ return results
557
 
558
 
559
  # ═══════════════════════════════════════════════════════════════════════