feat(product-suite): enable direct generation flow

This commit is contained in:
chengma
2026-07-20 18:37:27 +08:00
parent aa000ff5e6
commit 2e6b93d7e0
8 changed files with 242 additions and 17 deletions
+91 -5
View File
@@ -69,6 +69,7 @@ from ... import (
cmhub_models,
diagnostics,
image_studio,
image_studio_generation,
image_studio_images,
product_suite,
prompts,
@@ -1865,6 +1866,7 @@ class SuiteTaskState:
generation_mode: str = "batch"
generation_retry_job_id: int = None
generation_round_key: str = ""
generation_source: str = ""
worker: object = None
thread: object = None
generation_run_token: str = ""
@@ -3195,8 +3197,10 @@ class ProductSuiteTab(QWidget):
def _update_context_actions(self, state):
is_draft = self._is_draft_state(state)
pull_running = bool(state and state.pull_running())
generation_running = bool(state and state.generation_running())
self.pull_button.setEnabled(
state is not None
and not generation_running
and (
pull_running
or is_draft
@@ -3204,7 +3208,9 @@ class ProductSuiteTab(QWidget):
)
)
self.pull_button.setToolTip(
"正在停止拉取"
"生成中不能拉取蝦皮主图"
if generation_running
else "正在停止拉取"
if pull_running and state.pull_stop_requested
else "停止拉取蝦皮主图"
if pull_running
@@ -4181,6 +4187,45 @@ class ProductSuiteTab(QWidget):
except Exception:
return False
def _is_direct_gateway(self):
try:
return appconfig.ai_backend(self.config) == "direct"
except Exception:
return False
def _direct_generation_config_error(self):
"""Return a user-safe direct image-model preflight error, if any."""
try:
ai_config = appconfig.ai_config(self.config)
model_name = str(ai_config.get("default_image_model") or "").strip()
if not model_name:
return "尚未选择图片模型"
model = appconfig.get_model(
model_name,
path=appconfig.ai_models_config_path(self.config),
)
except Exception:
return "当前图片模型不存在或无法读取"
if not model.get("enabled", True):
return "当前图片模型未启用"
return appconfig.image_model_config_error(model)
def _ensure_generation_gateway(self):
if self._is_default_gateway():
return True
if self._is_direct_gateway():
error = self._direct_generation_config_error()
if not error:
return True
self._message(
"自定义网关配置不完整",
"商品套图无法生成:%s。\n请到⑤设置补齐并保存图片模型配置。" % error,
)
return False
self._message("生成网关不可用", "请到⑤设置选择默认网关或配置自定义网关。")
return False
@staticmethod
def _is_default_gateway_job(job):
return (
@@ -4578,6 +4623,8 @@ class ProductSuiteTab(QWidget):
(
"确认停止当前图片重试吗?已提交任务会在安全边界停止。"
if retrying
else "确认停止当前任务吗?正在请求的自定义网关图片无法立即撤销;如果图片已返回,程序会先保存,再结束后续任务。"
if state.generation_source == image_studio.GENERATION_SOURCE_DIRECT
else "确认取消当前任务吗?已提交任务会在安全边界停止。"
),
destructive=True,
@@ -4593,6 +4640,8 @@ class ProductSuiteTab(QWidget):
self._status(
"已请求停止当前图片重试"
if retrying
else "正在停止,等待当前图片返回后结束"
if state.generation_source == image_studio.GENERATION_SOURCE_DIRECT
else "已请求停止当前套图任务",
"warning",
)
@@ -4600,7 +4649,7 @@ class ProductSuiteTab(QWidget):
self.start_generation(state)
def start_generation(self, state, specs=None, *, retry_job_id=None):
if not self._require_default_gateway("商品套图生成"):
if not self._ensure_generation_gateway():
return False
if state.generation_running():
self._status("当前套图任务仍在生成", "warning")
@@ -4711,6 +4760,7 @@ class ProductSuiteTab(QWidget):
retry_job_id,
):
self._persist_state(state)
source = image_studio_generation.generation_source_for_config(self.config)
run_token = uuid.uuid4().hex
worker = ProductSuiteGenerateWorker(
state.project_id,
@@ -4728,6 +4778,7 @@ class ProductSuiteTab(QWidget):
state.generation_terminal_streak = 0
state.generation_job_ids = []
state.generation_mode = "retry" if retrying else "batch"
state.generation_source = source["generation_source"]
state.generation_retry_job_id = retry_job_id
state.generation_round_key = generation_round_key
state.done = 0
@@ -4775,6 +4826,15 @@ class ProductSuiteTab(QWidget):
self._status("正在读取套图预计扣点", "info")
return False
snapshot = self._generation_plan_snapshot(state, local_assets, specs, template_text)
if self._is_direct_gateway():
return self._confirm_generation_price_request(
state,
local_assets,
specs,
generation_round_key,
snapshot,
None,
)
params = self._cmhub_catalog_params("image_alias")
cached_models = (
cmhub_models.cached_model_catalog(params["base_url"], params["alias"])
@@ -4861,6 +4921,7 @@ class ProductSuiteTab(QWidget):
"item_id": str(state.item_id or ""),
"template_text": str(template_text or ""),
"specs": self._generation_specs_signature(specs),
"generation_backend": appconfig.ai_backend(self.config),
}
def _generation_plan_is_current(self, state, snapshot):
@@ -4996,6 +5057,10 @@ class ProductSuiteTab(QWidget):
0,
len(local_assets) - 1 - reference_count,
)
output_spec = image_studio_generation.requested_output_spec(
state.settings.get("ratio") or "1:1"
)
direct_gateway = self._is_direct_gateway()
lines = [
"店铺:%s" % self._account_context_label(state),
"商品ID:%s" % (state.item_id or "未绑定商品"),
@@ -5030,7 +5095,25 @@ class ProductSuiteTab(QWidget):
"",
]
)
if estimate is None:
lines.extend(
[
"输出尺寸:%s%s"
% (
output_spec["requested_output_size"],
"(接近比例生成)" if output_spec["approximate_ratio"] else "",
),
"",
]
)
if direct_gateway:
lines.extend(
[
"生成来源:自定义网关",
"自定义网关不计点数,实际费用以服务商为准。",
"首图作为主要商品参考;参考图效果取决于模型,商品主体一致性可能弱于默认网关。",
]
)
elif estimate is None:
lines.append("本次会消耗 cmhub 点数,暂时无法取得预计扣点,实际以网关返回为准。")
else:
unit_cost, total_cost = estimate
@@ -5395,6 +5478,7 @@ class ProductSuiteTab(QWidget):
state.generation_job_ids = []
state.generation_retry_job_id = None
state.generation_round_key = ""
state.generation_source = ""
state.worker = None
state.thread = None
state.done = success + failed + cancelled
@@ -5535,6 +5619,7 @@ class ProductSuiteTab(QWidget):
generation_price_pending = state.generation_price_worker is not None
pull_running = state.pull_running()
default_gateway = self._is_default_gateway()
supported_gateway = default_gateway or self._is_direct_gateway()
self.pull_button.setText(
"正在停止..."
if pull_running and state.pull_stop_requested
@@ -5554,6 +5639,7 @@ class ProductSuiteTab(QWidget):
self.ratio_combo,
self.per_image_checkbox,
self.prompt_edit,
self.prompt_settings_button,
self.add_category_button,
self.custom_category_edit,
):
@@ -5561,7 +5647,7 @@ class ProductSuiteTab(QWidget):
for row in self.category_rows.values():
row.set_controls_enabled(not generation_running)
self.generate_button.setEnabled(
generation_running or generation_price_pending or default_gateway
generation_running or generation_price_pending or supported_gateway
)
if generation_running:
self.generate_button.setText(
@@ -5593,7 +5679,7 @@ class ProductSuiteTab(QWidget):
)
if not default_gateway and not ai_running:
self.ai_write_button.setToolTip("商品套图AI帮写仅支持默认网关")
self.generate_button.setToolTip("商品套图生成仅支持默认网关")
self.generate_button.setToolTip("自定义网关生成不计点数,实际费用以服务商为准")
else:
self.ai_write_button.setToolTip("")
self.generate_button.setToolTip("")