feat(product-suite): add prompt template settings

This commit is contained in:
chengma
2026-07-16 16:18:11 +08:00
parent 613950c9f3
commit eea3fdd0a9
14 changed files with 1017 additions and 35 deletions
+65 -13
View File
@@ -40,9 +40,18 @@ from PySide6.QtWidgets import (
QWidget,
)
from ... import accounts, appconfig, diagnostics, image_studio, image_studio_images, product_suite
from ... import (
accounts,
appconfig,
diagnostics,
image_studio,
image_studio_images,
product_suite,
prompts,
)
from .. import file_manager
from ..image_preview import ImagePreviewDialog
from ..product_suite_prompt_dialog import ProductSuitePromptDialog
from ..widgets import _emit_status, run_worker
from ..workers import (
ImageStudioDownloadOriginalWorker,
@@ -57,13 +66,6 @@ ORIGINAL_DOWNLOAD_CONCURRENCY = 2
ORIGINAL_CHECK_STATE_ROLE = Qt.UserRole + 1
_PRODUCT_SUITE_THREAD_REFS = {}
_URL_RE = re.compile(r"https?://[^\s,,;;))\]]+", re.IGNORECASE)
FIXED_CATEGORY_HELPERS = {
"白底图": "白底主图,多角度呈现商品细节",
"场景图": "生活化场景展示商品使用方式",
"卖点图": "突出核心卖点和差异化优势",
}
def _asset_usable(asset):
path = str(getattr(asset, "local_path", "") or "")
return (
@@ -663,6 +665,7 @@ class ProductSuiteTab(QWidget):
self.db_path = db_path or appconfig.db_path(self.config)
self.config_path = config_path or self.config.get("config_path") or appconfig.CONFIG_PATH
self.cmhub_config_path = self.config.get("cmhub_config_path") or appconfig.cmhub_config_file_path(self.config)
self.product_suite_prompt_path = appconfig.product_suite_prompt_path(self.config)
self.status_callback = status_callback
self.accounts = []
self._states = {}
@@ -673,6 +676,12 @@ class ProductSuiteTab(QWidget):
self._original_list_context = None
self._loading = False
self._result_refresh_pending = False
self._prompt_template_init_error = ""
try:
prompts.ensure_default_product_suite_prompt(self.product_suite_prompt_path)
except prompts.PromptError as exc:
self._prompt_template_init_error = str(exc)
self._build_ui()
self._connect_signals()
@@ -684,6 +693,8 @@ class ProductSuiteTab(QWidget):
self.elapsed_timer.setInterval(1000)
self.elapsed_timer.timeout.connect(self._refresh_elapsed)
self.elapsed_timer.start()
if self._prompt_template_init_error:
self._status(self._prompt_template_init_error, "danger")
def _build_ui(self):
root = QVBoxLayout(self)
@@ -956,17 +967,23 @@ class ProductSuiteTab(QWidget):
layout = QVBoxLayout(frame)
layout.setContentsMargins(0, 0, 0, 0)
title_row = QHBoxLayout()
self.prompt_title_layout = title_row
title = QLabel("商品卖点与要求")
self.prompt_title_label = title
title.setStyleSheet("font-weight: 600;")
title_row.addWidget(title)
title_row.addStretch(1)
self.ai_write_button = QPushButton("AI 帮写")
self.ai_write_button.setObjectName("suiteAiWriteButton")
title_row.addWidget(self.ai_write_button)
self.ai_cancel_button = QPushButton("取消")
self.ai_cancel_button.setObjectName("suiteAiCancelButton")
self.ai_cancel_button.hide()
title_row.addWidget(self.ai_cancel_button)
self.ai_write_button = QPushButton("AI 帮写")
self.ai_write_button.setObjectName("suiteAiWriteButton")
title_row.addWidget(self.ai_write_button)
title_row.addStretch(1)
self.prompt_settings_button = QPushButton("提示词设置")
self.prompt_settings_button.setObjectName("suitePromptSettingsButton")
self.prompt_settings_button.setToolTip("编辑并预览套图最终提示词")
title_row.addWidget(self.prompt_settings_button)
layout.addLayout(title_row)
self.prompt_edit = QPlainTextEdit()
self.prompt_edit.setObjectName("suitePromptEdit")
@@ -1098,6 +1115,7 @@ class ProductSuiteTab(QWidget):
self.prompt_edit.textChanged.connect(self._on_prompt_changed)
self.ai_write_button.clicked.connect(self.start_ai_write)
self.ai_cancel_button.clicked.connect(self.cancel_ai_write)
self.prompt_settings_button.clicked.connect(self.open_prompt_settings)
self.add_category_button.clicked.connect(self.add_custom_category)
self.custom_category_edit.returnPressed.connect(self._commit_custom_category)
self.custom_category_edit.editingFinished.connect(self._finish_custom_category_edit)
@@ -1638,6 +1656,27 @@ class ProductSuiteTab(QWidget):
state = self._displayed_state
state.prompt = self.prompt_edit.toPlainText()
def open_prompt_settings(self, checked=False):
state = self._displayed_state
if state is not None:
self._save_controls_to_state(state)
settings = state.settings
base_prompt = state.prompt
item_id = state.item_id or "未绑定商品"
else:
settings = product_suite.default_suite_settings()
base_prompt = ""
item_id = "未绑定商品"
dialog = ProductSuitePromptDialog(
prompt_path=self.product_suite_prompt_path,
base_prompt=base_prompt,
settings=settings,
item_id=item_id,
parent=self,
)
self.prompt_settings_dialog = dialog
dialog.exec()
def _update_context_actions(self, state):
is_draft = self._is_draft_state(state)
self.pull_button.setEnabled(
@@ -2093,7 +2132,7 @@ class ProductSuiteTab(QWidget):
row = SuiteCategoryRow(
name,
categories.get(name, 0),
helper=FIXED_CATEGORY_HELPERS.get(name, ""),
helper=product_suite.category_helper(name),
custom=custom,
)
row.countChangeRequested.connect(self.change_category_count)
@@ -2327,6 +2366,18 @@ class ProductSuiteTab(QWidget):
return False
if state is self._displayed_state:
self._save_controls_to_state(state)
template_text = None
if specs is None:
try:
template_text = prompts.load_product_suite_prompt(
self.product_suite_prompt_path
)
except prompts.PromptError:
self._message(
"套图提示词模板无效",
"套图提示词模板无效,请在提示词设置中修复或恢复默认。",
)
return False
if self._ensure_project_for_local_work(state) is None:
return False
local_assets = [asset for asset in self._original_assets(state) if _asset_usable(asset)]
@@ -2341,6 +2392,7 @@ class ProductSuiteTab(QWidget):
state.prompt,
state.settings,
state.item_id or "未绑定商品",
template_text=template_text,
))
if not specs:
self._message("生成数量为0", "请至少把一个套图分类的数量设为1。")