feat(product-suite): complete multi-source recovery
This commit is contained in:
+126
-13
@@ -676,6 +676,11 @@ class SuiteResultCard(QFrame):
|
||||
title = QLabel(str(getattr(job, "job_type", "套图")))
|
||||
title.setStyleSheet("font-weight: 600; color: #24292f;")
|
||||
title_row.addWidget(title, 1)
|
||||
source_label = QLabel(_generation_source_label(job))
|
||||
source_label.setObjectName("suiteResultCardSource")
|
||||
source_label.setStyleSheet("color: #57606a; font-size: 11px;")
|
||||
source_label.setToolTip("生成来源:%s" % _generation_source_label(job))
|
||||
title_row.addWidget(source_label)
|
||||
if asset is not None and _asset_usable(asset):
|
||||
delete_button = QToolButton()
|
||||
delete_button.setText("×")
|
||||
@@ -791,7 +796,10 @@ class SuiteHistoryImageCard(QFrame):
|
||||
)
|
||||
layout.addWidget(image)
|
||||
|
||||
footer_text = self._status_text(status)
|
||||
footer_text = "%s · %s" % (
|
||||
_generation_source_label(job),
|
||||
self._status_text(status),
|
||||
)
|
||||
if self.retry_count:
|
||||
footer_text += " · 重试%d次" % self.retry_count
|
||||
footer = QLabel(footer_text)
|
||||
@@ -803,6 +811,7 @@ class SuiteHistoryImageCard(QFrame):
|
||||
|
||||
tooltip = [
|
||||
"类型:%s" % str(getattr(job, "job_type", "套图") or "套图"),
|
||||
"生成来源:%s" % _generation_source_label(job),
|
||||
"状态:%s" % self._status_text(status),
|
||||
"生成时间:%s" % _history_time_text(getattr(job, "created_at", "")),
|
||||
]
|
||||
@@ -856,6 +865,33 @@ def _history_time_text(value):
|
||||
return text[:19]
|
||||
|
||||
|
||||
def _generation_source_label(job):
|
||||
"""Return the persisted job source as a user-facing Chinese label."""
|
||||
|
||||
source = str(getattr(job, "generation_source", "") or "").strip().lower()
|
||||
provider = str(getattr(job, "provider", "") or "").strip().lower()
|
||||
if (
|
||||
source == image_studio.GENERATION_SOURCE_CMHUB
|
||||
and provider == image_studio.PROVIDER_CMHUB
|
||||
):
|
||||
return "默认网关"
|
||||
if (
|
||||
source == image_studio.GENERATION_SOURCE_DIRECT
|
||||
and provider == image_studio.PROVIDER_OPENAI_IMAGES_EDITS
|
||||
):
|
||||
return "自定义网关"
|
||||
return "来源未知"
|
||||
|
||||
|
||||
def _generation_source_summary(jobs):
|
||||
labels = []
|
||||
for job in jobs:
|
||||
label = _generation_source_label(job)
|
||||
if label not in labels:
|
||||
labels.append(label)
|
||||
return "、".join(labels) if labels else "来源未知"
|
||||
|
||||
|
||||
class ProductSuiteHistoryDialog(QDialog):
|
||||
"""Read-only, project-scoped generation history grouped by persisted rounds."""
|
||||
|
||||
@@ -1084,6 +1120,10 @@ class ProductSuiteHistoryDialog(QDialog):
|
||||
"border-radius: 6px; padding: 1px 6px;"
|
||||
)
|
||||
header.addWidget(legacy)
|
||||
source_label = QLabel("来源:%s" % _generation_source_summary(jobs))
|
||||
source_label.setObjectName("suiteHistoryRoundSource")
|
||||
source_label.setStyleSheet("color: #57606a;")
|
||||
header.addWidget(source_label)
|
||||
header.addStretch(1)
|
||||
stats = self._round_stats_text(round_info)
|
||||
stats_label = QLabel(stats)
|
||||
@@ -1268,9 +1308,10 @@ class SuiteGlobalHistoryThumbnail(QLabel):
|
||||
self.setAlignment(Qt.AlignCenter)
|
||||
self.setFixedSize(104, 78)
|
||||
self.setToolTip(
|
||||
"%s · %s"
|
||||
"%s · %s · %s"
|
||||
% (
|
||||
str(getattr(job, "job_type", "套图") or "套图"),
|
||||
_generation_source_label(job),
|
||||
SuiteHistoryImageCard._status_text(getattr(job, "status", "")),
|
||||
)
|
||||
)
|
||||
@@ -1348,6 +1389,10 @@ class SuiteGlobalHistoryRoundRow(QFrame):
|
||||
)
|
||||
meta.addWidget(QLabel("店铺:%s" % account))
|
||||
meta.addWidget(QLabel(item_text))
|
||||
source_label = QLabel("来源:%s" % _generation_source_summary(self.jobs))
|
||||
source_label.setObjectName("suiteGlobalHistorySource")
|
||||
source_label.setStyleSheet("color: #57606a;")
|
||||
meta.addWidget(source_label)
|
||||
layout.addLayout(meta, 0)
|
||||
|
||||
thumbnails = QHBoxLayout()
|
||||
@@ -4227,13 +4272,41 @@ class ProductSuiteTab(QWidget):
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _is_default_gateway_job(job):
|
||||
def _has_default_gateway_source(job):
|
||||
return (
|
||||
str(getattr(job, "generation_source", "") or "").strip().lower() == "cmhub"
|
||||
and str(getattr(job, "provider", "") or "").strip().lower() == "cmhub"
|
||||
and bool(str(getattr(job, "task_id", "") or "").strip())
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def _is_default_gateway_job(cls, job):
|
||||
return cls._has_default_gateway_source(job) and bool(
|
||||
str(getattr(job, "task_id", "") or "").strip()
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _is_direct_gateway_job(job):
|
||||
return (
|
||||
str(getattr(job, "generation_source", "") or "").strip().lower()
|
||||
== image_studio.GENERATION_SOURCE_DIRECT
|
||||
and str(getattr(job, "provider", "") or "").strip().lower()
|
||||
== image_studio.PROVIDER_OPENAI_IMAGES_EDITS
|
||||
)
|
||||
|
||||
def _retry_availability(self, job):
|
||||
if self._has_default_gateway_source(job):
|
||||
if self._is_default_gateway():
|
||||
return True, ""
|
||||
return False, "默认网关图片仅能在⑤设置切换为默认网关后重新生成"
|
||||
if self._is_direct_gateway_job(job):
|
||||
if not self._is_direct_gateway():
|
||||
return False, "自定义网关图片仅能在⑤设置切换为自定义网关后重新生成"
|
||||
error = self._direct_generation_config_error()
|
||||
if error:
|
||||
return False, "自定义网关配置不完整:%s" % error
|
||||
return True, ""
|
||||
return False, "当前图片的生成来源无法确认,不能重新生成"
|
||||
|
||||
def _resumable_default_gateway_jobs(self, state):
|
||||
if state is None or state.project_id is None:
|
||||
return []
|
||||
@@ -4648,7 +4721,14 @@ class ProductSuiteTab(QWidget):
|
||||
return
|
||||
self.start_generation(state)
|
||||
|
||||
def start_generation(self, state, specs=None, *, retry_job_id=None):
|
||||
def start_generation(
|
||||
self,
|
||||
state,
|
||||
specs=None,
|
||||
*,
|
||||
retry_job_id=None,
|
||||
confirm_direct_retry=False,
|
||||
):
|
||||
if not self._ensure_generation_gateway():
|
||||
return False
|
||||
if state.generation_running():
|
||||
@@ -4742,6 +4822,9 @@ class ProductSuiteTab(QWidget):
|
||||
generation_round_key,
|
||||
template_text,
|
||||
)
|
||||
if confirm_direct_retry:
|
||||
if not self._confirm_direct_retry(state, local_assets, specs):
|
||||
return False
|
||||
return self._start_generation_worker(
|
||||
state,
|
||||
specs,
|
||||
@@ -4750,6 +4833,29 @@ class ProductSuiteTab(QWidget):
|
||||
retry_job_id=retry_job_id,
|
||||
)
|
||||
|
||||
def _confirm_direct_retry(self, state, local_assets, specs):
|
||||
message = "\n".join(
|
||||
[
|
||||
"这张图片上次通过自定义网关生成但未完成。",
|
||||
"服务商可能对上次未确认请求已计费,本次重新生成可能再次收费。",
|
||||
"",
|
||||
self._generation_confirmation_message(
|
||||
state,
|
||||
local_assets,
|
||||
specs,
|
||||
estimate=None,
|
||||
),
|
||||
]
|
||||
)
|
||||
return self._confirm(
|
||||
"确认重新生成商品套图",
|
||||
message,
|
||||
destructive=True,
|
||||
confirm_text="确认重新生成",
|
||||
cancel_text="取消",
|
||||
default_cancel=True,
|
||||
)
|
||||
|
||||
def _start_generation_worker(
|
||||
self,
|
||||
state,
|
||||
@@ -5759,8 +5865,8 @@ class ProductSuiteTab(QWidget):
|
||||
card.retryRequested.connect(self.retry_job)
|
||||
card.menuRequested.connect(self._show_job_menu)
|
||||
card.deleteRequested.connect(self.delete_job_asset)
|
||||
if not self._is_default_gateway():
|
||||
card.set_retry_enabled(False, "商品套图重新生成仅支持默认网关")
|
||||
retry_enabled, retry_tooltip = self._retry_availability(job)
|
||||
card.set_retry_enabled(retry_enabled, retry_tooltip)
|
||||
self.result_grid.addWidget(card, index // columns, index % columns)
|
||||
self.result_summary_label.setText("共 %d 张 · 成功 %d 张" % (len(jobs), success))
|
||||
self.undo_button.setVisible(bool(state.undo_records))
|
||||
@@ -5831,8 +5937,6 @@ class ProductSuiteTab(QWidget):
|
||||
ProductSuitePreviewDialog(asset.local_path, "%s预览" % job.job_type, self).exec()
|
||||
|
||||
def retry_job(self, job):
|
||||
if not self._require_default_gateway("商品套图重新生成"):
|
||||
return
|
||||
state = self._displayed_state
|
||||
if state is None:
|
||||
return
|
||||
@@ -5846,6 +5950,10 @@ class ProductSuiteTab(QWidget):
|
||||
}:
|
||||
self._status("当前图片无需重试", "warning")
|
||||
return
|
||||
retry_enabled, retry_tooltip = self._retry_availability(job)
|
||||
if not retry_enabled:
|
||||
self._message("当前不可重新生成", retry_tooltip)
|
||||
return
|
||||
try:
|
||||
reference_asset_ids = image_studio.job_reference_asset_ids(job)
|
||||
except Exception as exc:
|
||||
@@ -5857,7 +5965,12 @@ class ProductSuiteTab(QWidget):
|
||||
"job_type": job.job_type,
|
||||
"prompt": job.prompt,
|
||||
}
|
||||
self.start_generation(state, specs=[spec], retry_job_id=job.id)
|
||||
self.start_generation(
|
||||
state,
|
||||
specs=[spec],
|
||||
retry_job_id=job.id,
|
||||
confirm_direct_retry=self._is_direct_gateway_job(job),
|
||||
)
|
||||
|
||||
def _show_job_menu(self, job, global_position):
|
||||
menu = QMenu(self)
|
||||
@@ -5865,9 +5978,9 @@ class ProductSuiteTab(QWidget):
|
||||
copy_action = menu.addAction("复制路径")
|
||||
folder_action = menu.addAction("打开文件夹")
|
||||
retry_action = menu.addAction("重新生成")
|
||||
if not self._is_default_gateway():
|
||||
retry_action.setEnabled(False)
|
||||
retry_action.setToolTip("商品套图重新生成仅支持默认网关")
|
||||
retry_enabled, retry_tooltip = self._retry_availability(job)
|
||||
retry_action.setEnabled(retry_enabled)
|
||||
retry_action.setToolTip(retry_tooltip)
|
||||
delete_action = menu.addAction("删除")
|
||||
action = menu.exec(global_position)
|
||||
asset = image_studio.get_asset(job.output_asset_id, path=self.db_path) if job.output_asset_id else None
|
||||
|
||||
Reference in New Issue
Block a user