Commit ·
3cbe3bf
1
Parent(s): 4dba567
Heartbeat progress during long subprocess runs (keeps SSE stream alive)
Browse files
app.py
CHANGED
|
@@ -18,6 +18,8 @@ import os
|
|
| 18 |
import shutil
|
| 19 |
import subprocess
|
| 20 |
import sys
|
|
|
|
|
|
|
| 21 |
import uuid
|
| 22 |
from dataclasses import dataclass
|
| 23 |
from pathlib import Path
|
|
@@ -108,6 +110,10 @@ def _write_input_image(run_dir: Path, image: Image.Image) -> Path:
|
|
| 108 |
|
| 109 |
def _run_subprocess(cmd: list[str], *, cwd: Path, progress: gr.Progress,
|
| 110 |
progress_fraction: float, phase_label: str) -> None:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
progress(progress_fraction, desc=phase_label)
|
| 112 |
log.info("[%s] %s (cwd=%s)", phase_label, " ".join(cmd), cwd)
|
| 113 |
env = os.environ.copy()
|
|
@@ -122,10 +128,34 @@ def _run_subprocess(cmd: list[str], *, cwd: Path, progress: gr.Progress,
|
|
| 122 |
bufsize=1,
|
| 123 |
)
|
| 124 |
assert proc.stdout is not None
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 129 |
if rc != 0:
|
| 130 |
raise gr.Error(f"{phase_label} failed with exit code {rc}. Check Space logs for details.")
|
| 131 |
|
|
|
|
| 18 |
import shutil
|
| 19 |
import subprocess
|
| 20 |
import sys
|
| 21 |
+
import threading
|
| 22 |
+
import time
|
| 23 |
import uuid
|
| 24 |
from dataclasses import dataclass
|
| 25 |
from pathlib import Path
|
|
|
|
| 110 |
|
| 111 |
def _run_subprocess(cmd: list[str], *, cwd: Path, progress: gr.Progress,
|
| 112 |
progress_fraction: float, phase_label: str) -> None:
|
| 113 |
+
"""Invoke a long-running Lyra-2 subprocess while emitting periodic progress
|
| 114 |
+
updates. Heartbeats matter: HF's SSE proxy drops connections when no events
|
| 115 |
+
flow for ~60s, and Lyra-2's model-load phase can be silent for 2+ min.
|
| 116 |
+
"""
|
| 117 |
progress(progress_fraction, desc=phase_label)
|
| 118 |
log.info("[%s] %s (cwd=%s)", phase_label, " ".join(cmd), cwd)
|
| 119 |
env = os.environ.copy()
|
|
|
|
| 128 |
bufsize=1,
|
| 129 |
)
|
| 130 |
assert proc.stdout is not None
|
| 131 |
+
|
| 132 |
+
# Background heartbeat to keep the Gradio SSE stream alive during long
|
| 133 |
+
# silent phases (model load + diffusion steps don't flush to our stdout).
|
| 134 |
+
stop_heartbeat = threading.Event()
|
| 135 |
+
t_start = time.monotonic()
|
| 136 |
+
|
| 137 |
+
def _heartbeat() -> None:
|
| 138 |
+
while not stop_heartbeat.wait(20.0):
|
| 139 |
+
elapsed = time.monotonic() - t_start
|
| 140 |
+
try:
|
| 141 |
+
progress(progress_fraction, desc=f"{phase_label} — {elapsed:.0f}s elapsed")
|
| 142 |
+
except Exception:
|
| 143 |
+
# Progress updates can raise if the client disconnects; don't
|
| 144 |
+
# kill the subprocess just because the browser went away.
|
| 145 |
+
pass
|
| 146 |
+
|
| 147 |
+
hb = threading.Thread(target=_heartbeat, daemon=True)
|
| 148 |
+
hb.start()
|
| 149 |
+
|
| 150 |
+
try:
|
| 151 |
+
for line in proc.stdout:
|
| 152 |
+
sys.stdout.write(line)
|
| 153 |
+
sys.stdout.flush()
|
| 154 |
+
rc = proc.wait()
|
| 155 |
+
finally:
|
| 156 |
+
stop_heartbeat.set()
|
| 157 |
+
hb.join(timeout=1.0)
|
| 158 |
+
|
| 159 |
if rc != 0:
|
| 160 |
raise gr.Error(f"{phase_label} failed with exit code {rc}. Check Space logs for details.")
|
| 161 |
|