Skip to content

Commit c7c48d6

Browse files
committed
feat(pipeline): improve progress emission and dashboard integration in master pipeline
Refactor the progress emission logic in the master pipeline to enhance real-time feedback during asset processing. Introduce a new `_emit` function to streamline the emission of progress updates, ensuring that the dashboard accurately reflects the current state of each stage. This update addresses issues with dashboard freezing during long-running stages and improves the handling of progress data, including the preservation of original IDs for sub-tools. Overall, these changes enhance the user experience and visibility of the asset processing workflow.
1 parent a4cb63e commit c7c48d6

1 file changed

Lines changed: 64 additions & 11 deletions

File tree

GameAssets/src/gameassets/pipeline_master.py

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,36 @@ def _stage(
146146
from gamedev_shared.progress import emit_progress
147147

148148
profiler_tool = name.replace("-", "_")
149-
if item_id:
150-
emit_progress(item_id, profiler_tool, phase="run", percent=0)
149+
150+
def _emit(phase: str, percent: float, status: str = "progress", **meta: object) -> None:
151+
"""Emite progresso E alimenta o dashboard directamente.
152+
153+
``emit_progress`` escreve no stdout do processo gameassets, que NÃO
154+
passa pelo callback ``on_progress_line`` do dashboard (esse só vê
155+
stdout dos sub-processos via ``run_cmd_streaming``). Sem este
156+
encaminhamento manual o dashboard congela em "Paint3D 100%" durante
157+
os stages do master pipeline (que duram dezenas de segundos cada).
158+
"""
159+
if not item_id:
160+
return
161+
emit_progress(item_id, profiler_tool, phase=phase, percent=percent, **meta)
162+
if on_progress_line is not None:
163+
import json as _json
164+
165+
data: dict = {
166+
"id": item_id,
167+
"tool": profiler_tool,
168+
"status": status,
169+
"phase": phase,
170+
"percent": round(percent, 1),
171+
}
172+
data.update(meta)
173+
try:
174+
on_progress_line(_json.dumps(data))
175+
except Exception: # noqa: BLE001
176+
pass
177+
178+
_emit("run", 0)
151179

152180
t0 = _time.perf_counter()
153181
try:
@@ -158,13 +186,39 @@ def _stage(
158186
):
159187
if on_progress_line is not None and _run_cmd_streaming is not None:
160188
# Stream stdout para callback (dashboard) E acumula resultado.
189+
# Sub-tools (text3d/rigging3d/animator3d) emitem events com
190+
# ``id`` derivado do filename (ex.: "goblin_lod0"); o
191+
# dashboard chaveia por ``row.id`` ("goblin"), portanto
192+
# reescrevemos o ``id`` em cada linha JSON antes de
193+
# encaminhar para que a célula do asset reflicta a fase
194+
# corrente. ``phase`` ganha o nome do stage para distinguir
195+
# entre rigging-merge-lod0/lod1/animate-lod0/etc.
196+
import json as _json
197+
161198
stdout_buf: list[str] = []
162199
stderr_buf: list[str] = []
163200

164201
def _on_out(line: str) -> None:
165202
stdout_buf.append(line)
166203
try:
167-
on_progress_line(line)
204+
forwarded = line
205+
s = line.strip()
206+
if item_id and s.startswith("{") and s.endswith("}"):
207+
try:
208+
data = _json.loads(s)
209+
except (ValueError, _json.JSONDecodeError):
210+
data = None
211+
if isinstance(data, dict) and "id" in data:
212+
# Preserva o id original em sub_id e mostra
213+
# o ``name`` (stage do master) como tool.
214+
data["sub_id"] = data.get("id")
215+
data["sub_tool"] = data.get("tool", "")
216+
data["id"] = item_id
217+
data["tool"] = profiler_tool
218+
if "phase" not in data and data.get("sub_tool"):
219+
data["phase"] = data["sub_tool"]
220+
forwarded = _json.dumps(data)
221+
on_progress_line(forwarded)
168222
except Exception: # noqa: BLE001
169223
pass
170224

@@ -183,22 +237,21 @@ def _on_err(line: str) -> None:
183237
r = run_cmd(argv, extra_env=env, cwd=cwd)
184238
except Exception as exc: # noqa: BLE001
185239
dt = _time.perf_counter() - t0
186-
if item_id:
187-
emit_progress(item_id, profiler_tool, phase="run", percent=100, status="error")
240+
_emit("run", 100, status="error")
188241
return StageResult(name, False, dt, f"ProfilerSession: {exc}", output)
189242

190243
dt = _time.perf_counter() - t0
191244
if r.returncode != 0:
192245
err = merge_subprocess_output(r, max_chars=400) or f"{name} falhou (rc={r.returncode})"
193-
if item_id:
194-
emit_progress(item_id, profiler_tool, phase="run", percent=100, status="error")
246+
_emit("run", 100, status="error")
195247
return StageResult(name, False, dt, err, output)
196248
if output is not None and not output.is_file():
197-
if item_id:
198-
emit_progress(item_id, profiler_tool, phase="run", percent=100, status="error")
249+
_emit("run", 100, status="error")
199250
return StageResult(name, False, dt, f"{name}: output não foi criado", output)
200-
if item_id:
201-
emit_progress(item_id, profiler_tool, phase="run", percent=100, status="ok")
251+
# Emite como ``progress`` (não ``ok``) — ``ok`` no dashboard sinaliza
252+
# conclusão do asset INTEIRO; usá-lo aqui faria a célula piscar OK entre
253+
# cada stage e contar duplicado no progresso global.
254+
_emit("run", 100, status="progress", seconds=round(dt, 2))
202255
return StageResult(name, True, dt, output=output)
203256

204257

0 commit comments

Comments
 (0)