fix(product-suite): keep retries in current results

This commit is contained in:
chengma
2026-07-16 18:15:24 +08:00
parent 25a08decdc
commit becfed81cd
3 changed files with 421 additions and 39 deletions
+160 -37
View File
@@ -697,6 +697,9 @@ class SuiteTaskState:
settings: dict = field(default_factory=product_suite.default_suite_settings)
current_job_ids: list = field(default_factory=list)
show_history: bool = False
generation_job_ids: list = field(default_factory=list)
generation_mode: str = "batch"
generation_retry_job_id: int = None
worker: object = None
thread: object = None
generation_run_token: str = ""
@@ -1582,6 +1585,9 @@ class ProductSuiteTab(QWidget):
state.project_binding_state = ""
state.last_saved_prompt = ""
state.current_job_ids = []
state.generation_job_ids = []
state.generation_mode = "batch"
state.generation_retry_job_id = None
state.done = state.failed = state.total = 0
state.started_at = None
if state is self._displayed_state:
@@ -2517,12 +2523,22 @@ class ProductSuiteTab(QWidget):
if state is None:
return
if state.generation_running():
retrying = state.generation_mode == "retry"
if state.generation_stop_requested:
self._status("正在停止当前套图任务", "warning")
self._status(
"正在停止当前图片重试"
if retrying
else "正在停止当前套图任务",
"warning",
)
return
if self._confirm(
"停止生成套图",
"确认取消当前任务吗?已提交任务会在安全边界停止。",
"停止图片重试" if retrying else "停止生成套图",
(
"确认停止当前图片重试吗?已提交任务会在安全边界停止。"
if retrying
else "确认取消当前任务吗?已提交任务会在安全边界停止。"
),
destructive=True,
):
state.generation_stop_requested = True
@@ -2533,14 +2549,21 @@ class ProductSuiteTab(QWidget):
"stop_requested",
)
self._apply_running_state(state)
self._status("已请求停止当前套图任务", "warning")
self._status(
"已请求停止当前图片重试"
if retrying
else "已请求停止当前套图任务",
"warning",
)
return
self.start_generation(state)
def start_generation(self, state, specs=None):
def start_generation(self, state, specs=None, *, retry_job_id=None):
if state.generation_running():
self._status("当前套图任务仍在生成", "warning")
return False
retry_job_id = int(retry_job_id) if retry_job_id is not None else None
retrying = retry_job_id is not None
if state is self._displayed_state:
self._save_controls_to_state(state)
template_text = None
@@ -2595,12 +2618,16 @@ class ProductSuiteTab(QWidget):
state.generation_run_token = run_token
state.generation_stop_requested = False
state.generation_terminal_streak = 0
state.generation_job_ids = []
state.generation_mode = "retry" if retrying else "batch"
state.generation_retry_job_id = retry_job_id
state.done = 0
state.failed = 0
state.total = len(specs)
state.started_at = time.monotonic()
state.current_job_ids = []
state.show_history = False
if not retrying:
state.current_job_ids = []
state.show_history = False
self._generation_run_states[run_token] = state.key
worker.progress.connect(self._on_generation_progress_signal)
worker.finished.connect(self._on_generation_finished_signal)
@@ -2611,17 +2638,27 @@ class ProductSuiteTab(QWidget):
state,
run_token,
"started",
{"total": len(specs), "job_ids": 0},
{
"total": len(specs),
"job_ids": 0,
"mode": state.generation_mode,
},
)
if state is self._displayed_state:
if state is self._displayed_state and not retrying:
self._loading = True
try:
self.history_button.setChecked(False)
finally:
self._loading = False
if state is self._displayed_state:
self._apply_running_state(state)
self._refresh_results(state)
self._status("商品套图生成已开始,共%d张;可切换到其他任务" % len(specs), "info")
self._status(
"图片重试已开始;可切换到其他任务"
if retrying
else "商品套图生成已开始,共%d张;可切换到其他任务" % len(specs),
"info",
)
return True
def _generation_signal_token(self, payload=None):
@@ -2651,7 +2688,7 @@ class ProductSuiteTab(QWidget):
state.failed = int(payload.get("failed", state.failed) or 0)
job_ids = payload.get("job_ids")
if job_ids is not None:
state.current_job_ids = [int(job_id) for job_id in job_ids]
self._set_generation_job_ids(state, job_ids)
state.generation_terminal_streak = 0
if state is self._displayed_state:
self._refresh_results(state)
@@ -2670,7 +2707,15 @@ class ProductSuiteTab(QWidget):
{"has_error": True},
level="ERROR",
)
self._status("商品套图生成失败:%s" % _user_error(error), "danger")
self._status(
(
"图片重试失败:%s"
if state.generation_mode == "retry"
else "商品套图生成失败:%s"
)
% _user_error(error),
"danger",
)
@Slot(dict)
def _on_generation_finished_signal(self, result):
@@ -2678,6 +2723,8 @@ class ProductSuiteTab(QWidget):
state = self._generation_state(token)
if state is None:
return
if result.get("job_ids") is not None:
self._set_generation_job_ids(state, result.get("job_ids"))
self._log_generation_lifecycle(
state,
token,
@@ -2779,7 +2826,7 @@ class ProductSuiteTab(QWidget):
)
def _generation_job_ids(self, state):
job_ids = list(state.current_job_ids)
job_ids = list(state.generation_job_ids)
if not job_ids and state.worker is not None:
worker_job_ids = getattr(state.worker, "job_ids", [])
if not isinstance(worker_job_ids, (list, tuple, set)):
@@ -2789,9 +2836,30 @@ class ProductSuiteTab(QWidget):
for job_id in list(worker_job_ids or [])
]
if job_ids:
state.current_job_ids = job_ids
self._set_generation_job_ids(state, job_ids)
return job_ids
def _set_generation_job_ids(self, state, job_ids):
normalized = []
for job_id in job_ids or []:
value = int(job_id)
if value not in normalized:
normalized.append(value)
state.generation_job_ids = normalized
if state.generation_mode != "retry":
state.current_job_ids = list(normalized)
return
retry_job_id = state.generation_retry_job_id
current = [int(job_id) for job_id in state.current_job_ids]
if retry_job_id in current:
index = current.index(retry_job_id)
current[index:index + 1] = normalized
elif not state.show_history:
for job_id in normalized:
if job_id not in current:
current.append(job_id)
state.current_job_ids = current
def _generation_job_snapshot(self, state):
job_ids = self._generation_job_ids(state)
counts = {
@@ -2865,6 +2933,7 @@ class ProductSuiteTab(QWidget):
def _finalize_generation(self, state, run_token, result, *, source):
if self._generation_state(run_token) is not state:
return False
retrying = state.generation_mode == "retry"
snapshot = self._generation_job_snapshot(state)
if snapshot["job_ids"] and (
snapshot["all_terminal"]
@@ -2890,6 +2959,8 @@ class ProductSuiteTab(QWidget):
state.generation_run_token = ""
state.generation_stop_requested = False
state.generation_terminal_streak = 0
state.generation_job_ids = []
state.generation_retry_job_id = None
state.worker = None
state.thread = None
state.done = success + failed + cancelled
@@ -2912,6 +2983,7 @@ class ProductSuiteTab(QWidget):
"cancelled": cancelled,
"active": active,
"elapsed_seconds": elapsed,
"mode": "retry" if retrying else "batch",
},
level="WARNING" if active or result.get("ok") is False else "INFO",
)
@@ -2923,39 +2995,76 @@ class ProductSuiteTab(QWidget):
or "生成线程已结束,部分任务可稍后继续查询"
)
if state is self._displayed_state:
self._message("商品套图生成未完整结束", _user_error(message))
self._message(
"图片重试未完整结束"
if retrying
else "商品套图生成未完整结束",
_user_error(message),
)
else:
self._status(
"套图任务%d生成未完整结束" % state.serial,
(
"套图任务%d图片重试未完整结束"
if retrying
else "套图任务%d生成未完整结束"
)
% state.serial,
"danger",
)
return True
if stop_requested or cancelled:
if state is self._displayed_state:
self._message(
"商品套图生成已停止",
"本轮共%d张:成功%d张,失败%d张,停止%d张;"
"已提交任务可稍后继续查询;总用时%d秒。"
% (total, success, failed, cancelled, elapsed),
icon=QMessageBox.Information,
)
if retrying:
self._message(
"图片重试已停止",
"本次重试:成功%d张,失败%d张,停止%d张;"
"已提交任务可稍后继续查询;总用时%d秒。"
% (success, failed, cancelled, elapsed),
icon=QMessageBox.Information,
)
else:
self._message(
"商品套图生成已停止",
"本轮共%d张:成功%d张,失败%d张,停止%d张;"
"已提交任务可稍后继续查询;总用时%d秒。"
% (total, success, failed, cancelled, elapsed),
icon=QMessageBox.Information,
)
self._status(
"商品套图生成已停止:成功%d张,失败%d张,停止%d张"
(
"图片重试已停止:成功%d张,失败%d张,停止%d张"
if retrying
else "商品套图生成已停止:成功%d张,失败%d张,停止%d张"
)
% (success, failed, cancelled),
"warning",
)
return True
if state is self._displayed_state:
self._message(
"商品套图生成完成",
"本轮共%d张:成功%d张,失败%d张,停止%d张;总用时%d秒。"
% (total, success, failed, cancelled, elapsed),
icon=QMessageBox.Information,
if retrying:
self._message(
"图片重试成功" if success and not failed else "图片重试失败",
"本次重试:成功%d张,失败%d张,停止%d张;总用时%d秒。"
% (success, failed, cancelled, elapsed),
icon=QMessageBox.Information,
)
else:
self._message(
"商品套图生成完成",
"本轮共%d张:成功%d张,失败%d张,停止%d张;总用时%d秒。"
% (total, success, failed, cancelled, elapsed),
icon=QMessageBox.Information,
)
if retrying:
self._status(
"图片重试成功" if success and not failed else "图片重试失败,请查看失败卡片",
"success" if success and not failed else "danger",
)
else:
self._status(
"商品套图生成完成:成功%d张,失败%d张" % (success, failed),
"success",
)
self._status(
"商品套图生成完成:成功%d张,失败%d张" % (success, failed),
"success",
)
return True
def _log_generation_lifecycle(
@@ -3012,6 +3121,8 @@ class ProductSuiteTab(QWidget):
self.generate_button.setText(
"正在停止..."
if state.generation_stop_requested
else "停止重试"
if state.generation_mode == "retry"
else "停止生成"
)
self.generate_button.setStyleSheet(
@@ -3035,7 +3146,8 @@ class ProductSuiteTab(QWidget):
return
elapsed = int(max(0, time.monotonic() - state.started_at)) if state.started_at else 0
self.elapsed_label.setText(
"套图 %d/%d(%d秒) · 失败 %d" % (
"%s %d/%d(%d秒) · 失败 %d" % (
"重试" if state.generation_mode == "retry" else "套图",
state.done,
state.total,
elapsed,
@@ -3067,8 +3179,12 @@ class ProductSuiteTab(QWidget):
return []
if state.show_history:
return jobs
current = set(state.current_job_ids)
return [job for job in jobs if int(job.id) in current]
by_id = {int(job.id): job for job in jobs}
return [
by_id[int(job_id)]
for job_id in state.current_job_ids
if int(job_id) in by_id
]
def _refresh_results(self, state):
while self.result_grid.count():
@@ -3122,12 +3238,19 @@ class ProductSuiteTab(QWidget):
if state.generation_running():
self._message("当前任务正在生成", "请等待当前生成结束或停止后再重试单张图片。")
return
if str(getattr(job, "status", "") or "") not in {
"failed",
"expired",
"cancelled",
}:
self._status("当前图片无需重试", "warning")
return
spec = {
"source_asset_id": job.source_asset_id,
"job_type": job.job_type,
"prompt": job.prompt,
}
self.start_generation(state, specs=[spec])
self.start_generation(state, specs=[spec], retry_job_id=job.id)
def _show_job_menu(self, job, global_position):
menu = QMenu(self)