feat(gui): replace AI studio with product suite

This commit is contained in:
chengma
2026-07-14 09:53:13 +08:00
parent fb873aae90
commit bc115ba0d7
27 changed files with 3453 additions and 81 deletions
+25 -6
View File
@@ -355,9 +355,9 @@ render_prompt(template_text, task) -> str
- `list_cover_templates()` 不会在启动时创建文件;只有保存/新建/另存为才写 `data/prompts/cover/*.txt`。
- 模板名不可为空,不允许路径分隔符、`..` 或 Windows 非法文件名字符;重命名时目标重名会报错。
## AI工场模块(`app/image_studio*.py`,已建)
## 商品套图模块(`app/product_suite.py` + `app/image_studio*.py`,已建)
AI工场是 ⑥ Tab 的本地图片项目工作区,不自动上传蝦皮、不修改线上商品。
商品套图是 ⑥ Tab 的本地图片项目工作区,不自动上传蝦皮、不修改线上商品。底层继续复用旧 AI工场的数据表与生成服务,避免迁移既有项目数据。
```python
# app/image_studio.py
@@ -365,9 +365,13 @@ ImageStudioProject / ImageStudioAsset / ImageStudioJob / ImageStudioSelection
create_or_get_project(account_or_fields, item_id, ...) -> ImageStudioProject
list_projects(path=None) -> list[ImageStudioProject]
update_project_prompt(project_id, draft_prompt, path=None) -> ImageStudioProject
project_suite_settings(project) -> dict
update_project_suite_settings(project_id, settings, path=None) -> ImageStudioProject
sync_original_asset_urls(project_id, image_urls, path=None) -> list[ImageStudioAsset]
list_assets(project_id, kind=None, include_missing=True, path=None) -> list[ImageStudioAsset]
reorder_original_assets(project_id, asset_ids, path=None) -> list[ImageStudioAsset]
create_job(project_id, source_asset_id=None, job_type="main", prompt="", ...) -> ImageStudioJob
list_jobs(project_id, statuses=None, path=None) -> list[ImageStudioJob]
list_resumable_jobs(project_id=None, include_failed_downloads=False, path=None) -> list[ImageStudioJob]
replace_selections(project_id, selection_type, asset_ids, path=None) -> list[ImageStudioSelection]
pull_remote_main_image_urls(account_or_alias, item_id, path=None, config=None) -> dict
@@ -376,6 +380,16 @@ pull_remote_main_image_urls(account_or_alias, item_id, path=None, config=None) -
download_remote_image(url, max_bytes=..., timeout=(connect, read)) -> RemoteImage
load_thumbnail(url, key=None, max_size=220) -> ThumbnailResult
download_original_asset(asset_id, path=None, config=None) -> ImageStudioAsset
import_original_files(project_id, file_paths, path=None, config=None) -> dict
import_original_bytes(project_id, content, filename_hint="clipboard.png", ...) -> ImageStudioAsset
trash_generated_asset(asset_id, path=None, config=None) -> dict
restore_trashed_asset(record, path=None, config=None) -> ImageStudioAsset
# app/product_suite.py
normalize_suite_settings(value=None) -> dict
suite_total_count(settings, image_count) -> int
build_suite_prompt(base_prompt, settings, category, item_id, source_index=1) -> str
build_job_specs(source_assets, base_prompt, settings, item_id) -> list[dict]
# app/image_studio_generation.py
generate_image_jobs(project_id, source_asset_id, prompt, count, job_type="main", aspect_ratio="1:1", ...) -> dict
@@ -387,10 +401,11 @@ export_project_selection(project_id, parent_dir, existing_mode="fail", path=None
要点:
- 项目唯一键为账号别名 + 商品 ID;图片文件默认在 `data/images/pool/<slug>/<item_id>/` 下分 `originals/generated/exports`。
- 项目唯一键为账号别名 + 商品 ID;图片文件默认在 `data/images/pool/<slug>/<item_id>/` 下分 `originals/generated/exports`,删除生成图进入项目内 `.trash` 并可撤销。
- `image_studio_projects.suite_settings_json` 保存平台/国家/语言/比例/逐图主图/分类数量;`draft_prompt` 保存商品卖点。有效原图上限16张,missing 历史不占名额。
- 拉取蝦皮原主图只读:复用 `editor.open_product(..., bring_to_front=False)` 和 `editor.read_product_image_urls()`,不上传、不拖拽、不点击更新。
- 原图下载走 `image_studio_images` 的公网 URL、大小、Content-Type、重定向和 PIL 解码校验;只在用户单击时落盘。
- cmhub 托管生图每张都是独立 job:保存 `task_key/task_id/status/call_id/points_cost/points_balance`;已有 `task_id` 时只 poll/download,不重复 submit。AI工场生成区只展示托管档位、生图别名、扣点和余额,不展示 Provider URL、OpenAI Key 或上游接口路径。
- cmhub 托管生图每张都是独立 job:保存 `task_key/task_id/status/call_id/points_cost/points_balance`;已有 `task_id` 时只 poll/download,不重复 submit。商品套图把平台/国家/语言/比例等上下文写入每个 job prompt,并把比例实参传到 cmhub;界面不展示 Provider URL、OpenAI Key 或上游接口路径。
- `include_failed_downloads=True` 允许 failed 但已有 `task_id`、无输出 asset 的任务继续查询,用于下载失败或本地保存失败恢复。
- 终选顺序由 `replace_selections()` 事务替换,主图/详情图同类别去重、跨类别可复用。
- 导出只写 JPEG 图片文件,透明图铺白底;商品目录已存在时只能覆盖受管命名文件或新建带时间目录,不合并、不递归清空。
@@ -406,7 +421,8 @@ class CollectTab(QWidget) # ① 导入采集:导入 Excel +
class GenerateTab(QWidget) # ② AI生成:提示词管理 + 筛选任务 + 生成封面图片成本开关 + 开始/停止生成 + 新旧封面预览 + AI生成运行日志
class ApplyTab(QWidget) # ③ 更新蝦皮:筛选已生成任务 + 检查本轮更新 + 缺失内容校验 + 确认后分批真实更新 + 运行日志
class SettingsTab(QWidget) # ⑤ 设置:cmhub 网关配置 + 响应式三列布局 + 角色/生成参数/路径端口 + 蝦皮更新安全 + 未保存状态追踪
class ImageStudioTab(QWidget) # ⑥ AI工场:项目、原图、照片池、终选、cmhub托管生成、导出
class ProductSuiteTab(QWidget) # ⑥ 商品套图:多任务、原图、结构配置、AI帮写、cmhub生成、历史结果
class ImageStudioTab(QWidget) # 旧AI工场兼容实现;主窗口不再创建
class CollectWorker(BaseWorker) # ① 后台采集:账号就绪预检 -> editor.collect -> db.set_collected/mark_skipped/mark_failed
class GenerateWorker(BaseWorker) # ② 后台生成:ai.generate_batch -> db.set_generated/set_generated_cover/mark_failed + 进度
class ApplyWorker(BaseWorker) # ③ 后台更新:账号就绪预检 -> 检查或按批调用 editor.apply_task(...) -> db.set_applied/mark_skipped
@@ -417,6 +433,9 @@ class ImageStudioDownloadOriginalWorker(BaseWorker)# ⑥ 后台下载远程原
class ImageStudioGenerateJobsWorker(BaseWorker) # ⑥ 后台提交/查询/下载 cmhub 生图 job
class ImageStudioResumeJobsWorker(BaseWorker) # ⑥ 后台恢复已有 task_id 的生图 job
class ImageStudioExportWorker(BaseWorker) # ⑥ 后台导出终选 JPEG
class ProductSuiteImportImagesWorker(BaseWorker) # ⑥ 后台校验并复制本地/剪贴板商品原图
class ProductSuiteGenerateWorker(BaseWorker) # ⑥ 按套图job规划提交/查询/下载
class ProductSuiteAiWriteWorker(BaseWorker) # ⑥ 后台生成商品卖点与画面要求
class TaskTableModel(QAbstractTableModel) # 任务表格模型:账号/别名/商品ID/阶段;未匹配别名显示“略过”
class GenerateTaskTableModel(QAbstractTableModel) # ② 任务表格模型:店铺/商品ID/旧标题/新标题/状态;generated/未提交/非运行中新标题可本地编辑
class ApplyTaskTableModel(QAbstractTableModel) # ③ 任务表格模型:店铺/商品ID/新标题/新封面/阶段/结果;保持只读,重置更新状态走右键菜单
@@ -428,7 +447,7 @@ TAB_STYLE: str # 顶层 Tab 栏防误点样式:
T-523 后 GUI 已从旧 `app/gui.py` 拆为 `app/gui/` 包:`__init__.py` 负责旧导入路径兼容与 `main()`;`main_window.py` 放 `MainWindow`;`models.py` 放 3 个 TableModel;`widgets.py` 放色板、空状态卡、批次总览和日志 helper;`workers.py` 放具体 GUI worker;`tabs/` 下按 ①~⑥ 拆分各 Tab。对外仍保留 `from app import gui`、`from app.gui import MainWindow/CollectTab/GenerateWorker/...`。
`MainWindow` 已实现六 Tab、① 导入采集任务列表、② AI生成布局/提示词/开始生成/停止/封面对照预览、③ 更新蝦皮筛选列表与检查/确认后分批真实更新、④ 账号管理、⑤ cmhub 设置、⑥ AI工场图片候选生成。缺 PySide6 时 `main()` 返回 1 并输出明确提示。
`MainWindow` 已实现六 Tab、① 导入采集任务列表、② AI生成布局/提示词/开始生成/停止/封面对照预览、③ 更新蝦皮筛选列表与检查/确认后分批真实更新、④ 账号管理、⑤ cmhub 设置、⑥ 商品套图生成。缺 PySide6 时 `main()` 返回 1 并输出明确提示。
主 Tab 栏必须在 `MainWindow` 初始化时应用 `TAB_STYLE`:6 个 Tab 不使用 Qt 默认紧凑宽度,需保证点击区域稳定、间距清晰、当前 Tab 高亮明显。该样式属于全局导航基础,不归后续业务 Tab 任务重复实现。