From 43d50ca62960012ded61f12d0f0b69c14eb5a102 Mon Sep 17 00:00:00 2001 From: chengma Date: Fri, 17 Jul 2026 16:12:03 +0800 Subject: [PATCH] feat(product-suite): include category in target prompt --- app/default_prompts/product_suite/base.txt | 2 +- docs/04-architecture.md | 2 +- docs/api.md | 2 +- docs/routes.md | 2 +- docs/tasks/T-656.md | 5 ++++- tests/test_packaging.py | 1 + tests/test_product_suite.py | 8 ++++---- tests/test_product_suite_gui.py | 2 +- 8 files changed, 14 insertions(+), 10 deletions(-) diff --git a/app/default_prompts/product_suite/base.txt b/app/default_prompts/product_suite/base.txt index a6da51c..9c13f71 100644 --- a/app/default_prompts/product_suite/base.txt +++ b/app/default_prompts/product_suite/base.txt @@ -1,4 +1,4 @@ -生成目标:{生成目标} +生成目标:{套图名称},{生成目标} 平台:{平台};国家地区:{国家地区};输出语言:{输出语言}。 {尺寸与长图规则} {禁用内容规则} diff --git a/docs/04-architecture.md b/docs/04-architecture.md index d5fce32..9f0a4b9 100644 --- a/docs/04-architecture.md +++ b/docs/04-architecture.md @@ -455,7 +455,7 @@ data/images///__new. # AI 生成的新 - **标题提示词**:`data/title_prompt.txt` 是当前工作文本,「保存标题提示词」写入该文件;软件启动时加载该文件回显到输入框(缺失则空)。标题命名模板另存于 `data/prompts/title/*.txt`,左侧模板行提供下拉、新建、保存模板、另存为、重命名、删除;模板只负责被用户选中后载入编辑框,或把当前编辑框内容保存为命名模板,不改变生成读取路径,也不在启动时覆盖 `title_prompt.txt`。T-549 后标题提示词支持 `{旧标题}` 占位符:若提示词含 `{旧标题}`,生成前替换为该任务旧标题且不再自动追加旧标题块;若不含,则保持旧行为自动追加“旧标题:...”块。两种情况都会保留“请只返回新标题,不要解释。”输出约束。 - **封面提示词**:多模板。左侧模板行提供下拉(读 `data/prompts/cover/*.txt`)、新建、保存模板、模板操作(另存为/重命名/删除);重名校验、删除二次确认、删空给默认。 -- **商品套图提示词**:单一全局基础模板,用户文件为 `data/prompts/product_suite/base.txt`,内置恢复源为 `app/default_prompts/product_suite/base.txt`。商品套图中的「商品卖点与要求」标题行提供「提示词设置」;弹窗左侧编辑模板、右侧按白底图或其他当前分类只读预览最终请求,默认模板首行是“生成目标:{生成目标}”,编辑使用 200ms 防抖。保存与「恢复默认」共用同一个 UTF-8 原子写入服务;恢复默认会先校验内置资源并经确认立即落盘。用户可移动只读规则占位符位置,但不能修改规则内容或删除必需变量;预览和新 job prompt 必须逐字一致。旧版用户模板中的 `{套图名称}` 与 `{补充描述}` 继续兼容,不被启动升级静默替换。 +- **商品套图提示词**:单一全局基础模板,用户文件为 `data/prompts/product_suite/base.txt`,内置恢复源为 `app/default_prompts/product_suite/base.txt`。商品套图中的「商品卖点与要求」标题行提供「提示词设置」;弹窗左侧编辑模板、右侧按白底图或其他当前分类只读预览最终请求,默认模板首行是“生成目标:{套图名称},{生成目标}”,编辑使用 200ms 防抖。保存与「恢复默认」共用同一个 UTF-8 原子写入服务;恢复默认会先校验内置资源并经确认立即落盘。用户可移动只读规则占位符位置,但不能修改规则内容或删除必需变量;预览和新 job prompt 必须逐字一致。旧版用户模板中的 `{套图名称}` 与 `{补充描述}` 继续兼容,不被启动升级静默替换。 - **变量**:标题提示词本阶段只支持 `{旧标题}`,左侧按钮「插入旧标题」在标题提示词光标处插入 `{旧标题}`。封面提示词支持占位符 `{旧标题}`、`{新标题}`、`{商品id}`、`{店铺}`,生成前用该任务真实值替换(`render_prompt`)。「插入标题」= 在封面提示词光标处插入 `{新标题}`;「预览」= 用某条任务的值替换封面变量后展示,确认实际发送给 AI 的内容。 ### 6.3 应用更新(③ Tab) diff --git a/docs/api.md b/docs/api.md index 4a9f646..9310d5b 100644 --- a/docs/api.md +++ b/docs/api.md @@ -435,7 +435,7 @@ export_generation_round(project_id, generation_round_key, parent_dir, path=None, - 终选顺序由 `replace_selections()` 事务替换,主图/详情图同类别去重、跨类别可复用。 - 导出只写 JPEG 图片文件,透明图铺白底;商品目录已存在时只能覆盖受管命名文件或新建带时间目录,不合并、不递归清空。 - 所有真实网络/CDP/图片生成/下载/转码由 GUI worker 调用;Widget slot 不直接执行长耗时操作。 -- 商品套图默认提示词首行使用 `{生成目标}`;五个内置分类使用固定目标描述,自定义分类使用“生成自定义分类图片:分类名称。”并注入实际分类名称。旧模板同时包含 `{套图名称}` 和 `{补充描述}` 时继续兼容,预览和 `build_job_specs()` 使用同一 renderer,job 保存最终提示词快照。 +- 商品套图默认提示词首行使用 `{套图名称}` 与 `{生成目标}`,结构为“生成目标:{套图名称},{生成目标}”;五个内置分类使用固定目标描述,自定义分类使用“生成自定义分类图片:分类名称。”并注入实际分类名称。旧模板同时包含 `{套图名称}` 和 `{补充描述}` 时继续兼容,预览和 `build_job_specs()` 使用同一 renderer,job 保存最终提示词快照。 - `product_suite_prompt_context()` 按 `per_image_primary` 生成 `{参考图规则}`:开启时返回“当前上传图片是本任务唯一主参考图;保持商品主体、款式、颜色和关键细节准确;不编造用户与参考图均未提供的信息。”,关闭时返回“使用第一張上傳圖作為主商品圖,其餘圖片只作為參考。”;变量值不包含重复标签和序号。 ## gui 模块(`app/gui/` 包,已建,PySide6) diff --git a/docs/routes.md b/docs/routes.md index d819d8f..8e2ec5d 100644 --- a/docs/routes.md +++ b/docs/routes.md @@ -204,7 +204,7 @@ - 每张真实原图左上角提供独立勾选框,标题行显示「已选 N 张 / 全选 / 反选」;添加占位图不参与选择。勾选只在当前任务界面内临时保留,普通刷新和排序按资产 ID 保留,切换任务或删除成功后清空。右键或 Delete 可批量移除,确认框说明准确数量、主图变化及非破坏性边界;生成中或勾选项仍在下载时整批阻断。移除只删除当前项目的本地资产记录,不删除本地源文件或蝦皮线上图片。 - 「拉取蝦皮主图」复用只读 CDP,读取 URL 后由最多2个下载 worker 后台落盘;不改标题/封面、不拖拽、不点击更新。拉取、下载期间其余界面和其他任务仍可操作。 - 套图按分类配置生成图片,固定分类顺序为白底图、场景图、模特场景图、细节说明图、卖点图,之后是自定义分类;默认数量为白底图1、场景图2、模特场景图0、细节说明图0、卖点图2。新增分类默认数量为0,用户未主动配置时不增加生成任务或点数消耗。自定义分类名称非空、无空格、最多10字且不可重名。逐图主图开启后,白底图只生成一次,其余分类按每张有效原图展开。 -- 套图提示词设置弹窗默认模板首行使用“生成目标:{生成目标}”。五个内置分类使用统一固定目标描述;自定义分类使用“生成自定义分类图片:分类名称。”,实际分类名称必须进入最终提示词。旧模板若仍使用 `{套图名称}` 与 `{补充描述}` 会继续读取和渲染,不静默覆盖用户文件;新模板与旧模板都由同一个 renderer 提供预览和 job prompt。 +- 套图提示词设置弹窗默认模板首行使用“生成目标:{套图名称},{生成目标}”。五个内置分类使用统一固定目标描述;自定义分类使用“生成自定义分类图片:分类名称。”,实际分类名称必须进入最终提示词。旧模板若仍使用 `{套图名称}` 与 `{补充描述}` 会继续读取和渲染,不静默覆盖用户文件;新模板与旧模板都由同一个 renderer 提供预览和 job prompt。 - `{参考图规则}` 根据“每张上传图分别作为主图生成”切换:勾选时使用“当前上传图片是本任务唯一主参考图;保持商品主体、款式、颜色和关键细节准确;不编造用户与参考图均未提供的信息。”;未勾选时使用“使用第一張上傳圖作為主商品圖,其餘圖片只作為參考。”。变量值不重复“参考图规则:”标签,也不追加参考图序号。 - 平台、国家地区、语言和比例以四个带独立标签的同行下拉展示,选项只显示真实值;四项都写进每个 job 的完整提示词,比例还透传到 cmhub 生图请求,不是装饰字段。已有项目保存自己的完整设置;未绑定商品的新任务在重启后采用 `config.json` 的最近四项选择。生成仍走 `image_studio_generation.run_jobs()` 的 submit → poll → download 管线。 - 平台、站点、语言和比例四个生成设置下拉仅在闭合时拦截自身滚轮改值,并把滚动交给 `suiteConfigScroll`;展开时滚轮只浏览候选列表,不静默提交当前值。鼠标点击、方向键、回车和 `Alt+↓` 保持原有显式选择语义;账号、历史筛选和设置页等其它下拉不受影响。 diff --git a/docs/tasks/T-656.md b/docs/tasks/T-656.md index 88f17f8..c158519 100644 --- a/docs/tasks/T-656.md +++ b/docs/tasks/T-656.md @@ -3,7 +3,7 @@ id: T-656 title: 在生成目标首行同时显示分类名称和目标描述 phase: 7 deps: [T-655] -status: TODO +status: DONE created: 2026-07-17 --- @@ -60,3 +60,6 @@ created: 2026-07-17 ## 执行记录 - 2026-07-17:根据用户要求创建任务,待实现。 +- 2026-07-17:任务文档先行提交,提交号 `ff0ad8b`。 +- 2026-07-17:完成默认模板首行改为“生成目标:{套图名称},{生成目标}”,同步更新预览、测试及路由、架构、API 文档;旧用户模板仍保持兼容且不自动覆盖。 +- 2026-07-17:验证通过 `python -m ruff check app tests main.py`、`python -m compileall app main.py`、`python -m unittest discover -s tests`,共 580 个测试通过。 diff --git a/tests/test_packaging.py b/tests/test_packaging.py index fce4eb9..6ff7d3d 100644 --- a/tests/test_packaging.py +++ b/tests/test_packaging.py @@ -33,6 +33,7 @@ class PackagingTests(unittest.TestCase): self.assertIn("COLLECT(", spec) self.assertIn('name="cmshopee"', normalized) suite_prompt = self.read_text("app/default_prompts/product_suite/base.txt") + self.assertIn("生成目标:{套图名称},{生成目标}", suite_prompt) self.assertIn("{生成目标}", suite_prompt) self.assertNotIn("套图名称:", suite_prompt) self.assertIn("{尺寸与长图规则}", suite_prompt) diff --git a/tests/test_product_suite.py b/tests/test_product_suite.py index 69c2f47..1abee1e 100644 --- a/tests/test_product_suite.py +++ b/tests/test_product_suite.py @@ -117,11 +117,11 @@ class ProductSuiteTests(unittest.TestCase): ) self.assertIn( - "生成目标:生成 Shopee 台灣商品白底主圖,純白背景,商品清晰置中,不添加多餘文字。", + "生成目标:白底图,生成 Shopee 台灣商品白底主圖,純白背景,商品清晰置中,不添加多餘文字。", specs[0]["prompt"], ) self.assertIn( - "生成目标:生成生活化使用場景圖,展示商品在真實情境中的用途與氛圍,畫面自然可信。", + "生成目标:场景图,生成生活化使用場景圖,展示商品在真實情境中的用途與氛圍,畫面自然可信。", specs[1]["prompt"], ) white_prompt = specs[0]["prompt"] @@ -205,12 +205,12 @@ class ProductSuiteTests(unittest.TestCase): "draft_hidden", ) rendered = product_suite.render_product_suite_prompt(default_text, context) - self.assertIn("生成目标:生成自定义分类图片:尺寸图。", rendered) + self.assertIn("生成目标:尺寸图,生成自定义分类图片:尺寸图。", rendered) self.assertNotIn("draft_", rendered) self.assertNotIn("套图名称:", rendered) legacy_template = default_text.replace( - "生成目标:{生成目标}", + "生成目标:{套图名称},{生成目标}", "套图名称:{套图名称}{补充描述}", ) self.assertEqual([], product_suite.product_suite_prompt_errors(legacy_template)) diff --git a/tests/test_product_suite_gui.py b/tests/test_product_suite_gui.py index e3f76a8..812a78a 100644 --- a/tests/test_product_suite_gui.py +++ b/tests/test_product_suite_gui.py @@ -331,7 +331,7 @@ class ProductSuiteGuiTests(TempDirMixin, unittest.TestCase): self.assertEqual("白底图", dialog.category_combo.currentData()) self.assertTrue(dialog.preview_edit.isReadOnly()) self.assertIn( - "生成目标:生成 Shopee 台灣商品白底主圖,純白背景,商品清晰置中,不添加多餘文字。", + "生成目标:白底图,生成 Shopee 台灣商品白底主圖,純白背景,商品清晰置中,不添加多餘文字。", dialog.preview_edit.toPlainText(), ) self.assertIn("40小时续航", dialog.preview_edit.toPlainText())