docs: add AI outfit module design (docs/11-ai-outfit.md)
Design for the "2 AI 穿搭" tab: Excel as the (fixed) data source → convert rows to OutfitTask → garment image + prompt → AI image API → person-wearing-clothes JPG → write result path back to Excel. Ports the old project's API client / batch / retry into cmbot's app/core/services layering, reusing config/log/ ~/.cmbot/output. Also fixes the 旧ai穿搭项目.md §6 recommendation (keep Excel). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,182 @@
|
|||||||
|
# AI 穿搭模块设计
|
||||||
|
|
||||||
|
## 1. 文档定位
|
||||||
|
|
||||||
|
本文档定义 cmbot「2 AI 穿搭」页签的设计。它是一项独立能力,按 `docs/09` 第 262 行「新能力单独成文」要求成文,不混入印花合成相关文档。
|
||||||
|
|
||||||
|
参考来源:同事旧项目「标题生成产品图工具」的分析见 `docs/旧ai穿搭项目.md`。本模块把该项目验证过的「本地图 + 提示词 → 调 AI 图像 API → 写回 Excel」机制,移植进 cmbot 的分层架构(`app` / `core` / `services`)。
|
||||||
|
|
||||||
|
一句话目标:**以 Excel 为数据源,按行读取「衣服图 + 标题/货号」,套提示词调 AI 图像 API 生成「人物穿着该衣服」的效果图,保存 JPG 并把结果路径写回 Excel。**
|
||||||
|
|
||||||
|
## 2. 目标与非目标
|
||||||
|
|
||||||
|
### 2.1 目标
|
||||||
|
|
||||||
|
- Excel 批量驱动:逐行读取标题、货号、衣服图路径,生成后把结果写回 Excel(与旧项目列约定一致)。
|
||||||
|
- AI 生成:衣服图作为图像输入 + 提示词(可插标题/货号占位符)→ 生成人物上身/穿搭效果图,保留款式、版型、颜色、印花。
|
||||||
|
- 复用 cmbot 现有设施:配置(`config_service` / `~/.cmbot`)、日志、输出目录、后台线程模式、打包/更新,不重造。
|
||||||
|
- 稳态批量:并发、限速、阶梯重试、温和停止、实时日志、进度与失败清单。
|
||||||
|
- 分层可测:AI 调用与 Excel 适配放 `services`,无 GUI 逻辑放 `core`,关键逻辑有单测。
|
||||||
|
|
||||||
|
### 2.2 非目标
|
||||||
|
|
||||||
|
- 不改变数据源形态:**输入固定为 Excel**(不在本期改为文件夹/队列;但核心对内部模型工作,将来加别的输入源不必改核心)。
|
||||||
|
- 不做模特/姿态/背景的精细可视化编辑(由提示词控制,不做画布微调)。
|
||||||
|
- 不内置 AI 模型,依赖外部中转 API。
|
||||||
|
- 不照搬旧项目的 bootstrap / offline_runtime / .bat(cmbot 已有自己的打包与更新体系)。
|
||||||
|
|
||||||
|
## 3. 总体架构
|
||||||
|
|
||||||
|
把 Excel 当作 **I/O 适配边界**,中间用 cmbot 内部数据模型,核心 AI 逻辑与数据源解耦:
|
||||||
|
|
||||||
|
```
|
||||||
|
Excel(数据源,固定)
|
||||||
|
│ services/excel_service:读行 → List[OutfitTask](转成内部模型)
|
||||||
|
▼
|
||||||
|
core/ai_outfit + services/ai_image_service:
|
||||||
|
衣服图 + 提示词 → 调 AI 图像 API → 人物上身图(JPG)
|
||||||
|
│ 复用:并发/日志/配置/进度/~/.cmbot
|
||||||
|
▼
|
||||||
|
services/excel_service:把结果写回 Excel(D 新图路径 / E 状态 / F 原因)
|
||||||
|
```
|
||||||
|
|
||||||
|
分层落点:
|
||||||
|
|
||||||
|
- `core/models.py`:新增 `OutfitTask` / `OutfitResult`(纯数据,无 PySide6)。
|
||||||
|
- `services/excel_service.py`:Excel 读取、写回、占用检测、跳过/重试判断。
|
||||||
|
- `services/ai_image_service.py`:移植旧项目 `ImageApiClient`(多模型、多请求格式、传图、取图、重试、超时)。
|
||||||
|
- `core/ai_outfit.py`(或 service 内):单行生成的纯逻辑编排(提示词渲染、调用、保存、产出结果),可单测。
|
||||||
|
- `app/widgets/ai_outfit_panel.py` + 主窗口「2 AI 穿搭」页签:界面与后台线程(`QThread` + `Worker(QObject)` + 信号)。
|
||||||
|
|
||||||
|
## 4. Excel 适配(数据源)
|
||||||
|
|
||||||
|
沿用旧项目列约定(固定,先不做可配置):
|
||||||
|
|
||||||
|
| 列 | 含义 | 读/写 |
|
||||||
|
|---|---|---|
|
||||||
|
| A | 标题 | 读 |
|
||||||
|
| B | 货号(商品 ID) | 读 |
|
||||||
|
| C | 衣服图路径(本机绝对路径) | 读 |
|
||||||
|
| D | 生成结果图片路径 | 写回 |
|
||||||
|
| E | 完成状态:`完成` / `失败`(空=未处理) | 写回 |
|
||||||
|
| F | 失败原因(仅人工查看) | 写回 |
|
||||||
|
|
||||||
|
规则:
|
||||||
|
|
||||||
|
- 默认读第一个工作表,第 1 行表头,从第 2 行开始。
|
||||||
|
- **跳过 E=`完成` 的行**;是否处理 E=`失败` 的行由界面「重试失败行」决定(勾选则处理「空白 + 失败」,否则只处理「空白」)。
|
||||||
|
- 标题/货号/衣服图任一为空 → 跳过该行,不写状态、不中断。
|
||||||
|
- 字段按原样读取,不清理空格、不回写清理值。
|
||||||
|
- **开始前检测 Excel 是否被占用**(Office 打开会锁文件,openpyxl 无法写回)→ 提示「请关闭 Excel 后再开始」。
|
||||||
|
- **每处理完一行即保存 Excel**(降低崩溃丢结果风险)。
|
||||||
|
- 成功 → D=新图绝对路径、E=`完成`;失败 → E=`失败`、F=原因(同步写日志)。
|
||||||
|
|
||||||
|
## 5. 内部数据模型
|
||||||
|
|
||||||
|
`core/models.py` 新增(纯 dataclass,Python 3.7 兼容,不依赖 PySide6):
|
||||||
|
|
||||||
|
- `OutfitTask`:`row_index:int`、`title:str`、`product_id:str`、`garment_path:str`、`status:str`(待处理/完成/失败)。
|
||||||
|
- `OutfitResult`:`task`、`success:bool`、`output_path:str`、`error:str`、`attempts:int`。
|
||||||
|
|
||||||
|
Excel 行 → `OutfitTask` 列表的转换由 `excel_service` 完成;核心只认 `OutfitTask`,因此将来换数据源只需另写适配器。
|
||||||
|
|
||||||
|
## 6. AI 图像服务(移植旧项目)
|
||||||
|
|
||||||
|
`services/ai_image_service.py` 移植旧项目 `ImageApiClient`,要点(详见 `docs/旧ai穿搭项目.md` §5.1/5.2):
|
||||||
|
|
||||||
|
- **多模型配置**:`url / model / api_key / api_type / timeout_seconds / connect_timeout_seconds / extra_body`,记住上次所选模型。
|
||||||
|
- **多请求格式**(按 `api_type`:`auto/chat/gemini/images/images_edits`):
|
||||||
|
- chat(OpenAI 兼容 `/v1/chat/completions`):`messages[].content` = `{type:text}` + `{type:image_url, image_url:{url:data_url}}`。
|
||||||
|
- gemini(`generateContent`):`contents[].parts` = `{text}` + `{inlineData:{mimeType,data}}`。
|
||||||
|
- images:`{model,prompt,image_urls:[data_url],aspect_ratio,resolution,n}`。
|
||||||
|
- images_edits:multipart `data` + `files={"image":...}`。
|
||||||
|
- **传图**:本地衣服图 → `data:<mime>;base64,...`(data-url)或 multipart 文件。
|
||||||
|
- **取图**:递归遍历响应 JSON 找 base64 / data-url / 图片 URL(再下载),对中转 API 结构差异强兼容。
|
||||||
|
- **URL 归一化**、`extra_body` 合并、字段校验(缺 `url/model/api_key` 时阻止开始)。
|
||||||
|
|
||||||
|
> Python 3.7 注意:旧项目用了 `dict[str, Any]` 等 PEP 585 写法,移植时需 `from __future__ import annotations` 或改用 `typing.Dict`,以兼容 cmbot 的 Python 3.7.9。
|
||||||
|
|
||||||
|
## 7. 提示词
|
||||||
|
|
||||||
|
- 提示词模板存 `~/.cmbot/config/outfit_prompt.txt`,界面可查看/编辑/保存;点「开始」前自动保存一次。
|
||||||
|
- 占位符:`{title}`(标题)、`{product_id}`(货号);界面提供「插入占位符」按钮与「最终提示词预览」。
|
||||||
|
- 缺标题占位符时开始前弹窗询问是否继续。
|
||||||
|
- 默认话术方向(穿搭/上身,区别于旧项目的主图场景,需另调):人物上身实穿、保留衣服款式/版型/颜色/印花、合适身材与场景、电商可用、默认纯净不加促销牛皮癣。
|
||||||
|
|
||||||
|
## 8. 并发、限速、重试、停止
|
||||||
|
|
||||||
|
复用旧项目策略(`docs/旧ai穿搭项目.md` §5.3):
|
||||||
|
|
||||||
|
- `ThreadPoolExecutor(max_workers=并发数)` 调度行任务;`RateLimiter(新请求间隔)` 限制请求开始间隔;任务间 `单任务冷却`。
|
||||||
|
- 每行最多「首次 + 重试次数」尝试;限流/429 用短阶梯等待,普通错误短等待。
|
||||||
|
- 单次请求放子线程 + 主线程秒级检查,**等待 >30 秒持续打心跳日志**;超时按分辨率动态决定(512/1K/2K/4K → 180/240/360/600 秒,可被 `timeout_seconds` 覆盖)。
|
||||||
|
- **温和停止**:置位停止后不再提交新任务,已发请求收尾后正常写回。
|
||||||
|
|
||||||
|
## 9. 输出
|
||||||
|
|
||||||
|
- 格式 JPG,1:1,压缩到 ≤2MB;质量三档(小文件 75 / 均衡 85 / 高清 92)。
|
||||||
|
- 默认输出目录沿用 cmbot `get_output_dir()`(程序旁的「合并后的图片」,见 `docs/10` §5),界面可改。
|
||||||
|
- 命名:`货号.jpg`,重名自动 `_1`/`_2`,非法字符替换为 `_`(不改 Excel 原始货号)。
|
||||||
|
- 成功后把**实际新图绝对路径**写回 Excel D 列。
|
||||||
|
|
||||||
|
## 10. 界面(「2 AI 穿搭」页签)
|
||||||
|
|
||||||
|
把主窗口当前禁用的「2 AI 穿搭」页签启用,做成独立工作页(与「1 添加印花」并列、互不干扰)。控件:
|
||||||
|
|
||||||
|
- 选择 Excel 文件、选择输出目录(记住上次,存 `app_config.json`)。
|
||||||
|
- 模型下拉(来自 AI 模型配置)。
|
||||||
|
- 通用话术编辑 + 保存 + 插入占位符 + 最终提示词预览。
|
||||||
|
- 设置:重试失败行、并发数、新请求间隔、单任务冷却、重试次数、分辨率、JPG 质量。
|
||||||
|
- 开始生成 / 停止生成;实时日志;进度与统计(完成/失败/跳过);结束摘要弹窗;导出失败清单。
|
||||||
|
- 后台用 `QThread` + `Worker(QObject)` + 信号回主线程(与 cmbot 更新检查/导出一致)。
|
||||||
|
|
||||||
|
> 页签内容切换:当前页签栏不切换内容面板(见 `docs/07` §4.2)。启用 AI 穿搭需要为页签接一个 `QStackedWidget`(「1 添加印花」=现有工作区,「2 AI 穿搭」=本面板);这部分在实现阶段一并补。
|
||||||
|
|
||||||
|
## 11. 配置与数据位置
|
||||||
|
|
||||||
|
遵循 cmbot「配置集中、放数据目录、凭据不入库」约定:
|
||||||
|
|
||||||
|
- **AI 模型与密钥** → `~/.cmbot/config/ai_models.json`(管理员预置或界面填写,**含明文 key、不提交 git**;与更新源凭据同等对待,见 `docs/10` §14)。
|
||||||
|
- **提示词** → `~/.cmbot/config/outfit_prompt.txt`。
|
||||||
|
- **批量设置 + 上次 Excel/输出路径** → 并入 `app_config.json`(`config_service` 集中读写,UI 不直接读写配置文件,遵守 `docs/04` 第 6 节 / `docs/05` 4.12)。
|
||||||
|
- 失败记录 / 日志沿用 `~/.cmbot/logs` 与现有日志服务。
|
||||||
|
|
||||||
|
## 12. 依赖与兼容
|
||||||
|
|
||||||
|
- 新增依赖:`requests`(HTTP)、`openpyxl`(Excel);`Pillow`、`PySide6` 已有。写入 `requirements.txt` 并锁版本(兼容 Python 3.7:`requests>=2.31,<3`、`openpyxl>=3.1,<4`、`urllib3<2`)。
|
||||||
|
- 所有新代码保持 **Python 3.7.9** 兼容(注意类型注解写法)。
|
||||||
|
- `docs/03-technical-stack.md` 增列上述依赖;`docs/02-prd.md`、`docs/07-ui-design.md` §4.2 加指针指向本文档。
|
||||||
|
|
||||||
|
## 13. 安全考量
|
||||||
|
|
||||||
|
- AI 中转 API key 为明文,仅放 `~/.cmbot`,**不入库、不随包分发到公网**;内部使用可接受(与更新凭据一致)。
|
||||||
|
- 中转 API 会 429 限流:并发默认 1,阶梯重试。
|
||||||
|
- 衣服图为本机路径;不存在/打不开/非图片 → 该行失败并记录,继续下一行。
|
||||||
|
|
||||||
|
## 14. 实现阶段建议
|
||||||
|
|
||||||
|
分步落地,每步可独立验证:
|
||||||
|
|
||||||
|
1. **核心与服务(无 GUI,可测)**:`core.models.OutfitTask/OutfitResult`、`services/excel_service.py`(读/写回/占用检测)、`services/ai_image_service.py`(移植 ImageApiClient)、`core/ai_outfit.py`(单行编排)+ 单测(Excel 读写、提示词渲染、取图、命名去重;API 用 mock)。
|
||||||
|
2. **批量编排**:并发/限速/重试/停止的 `Worker`,纯逻辑部分尽量可测。
|
||||||
|
3. **UI 页签**:页签 `QStackedWidget` + `ai_outfit_panel`,接线后台线程、日志、进度、失败清单。
|
||||||
|
4. **配置与提示词**:`ai_models.json` / `outfit_prompt.txt` / `app_config.json` 接入,集中读写。
|
||||||
|
5. **真机联调**:用真实中转 API + 小批量 Excel 跑通端到端,调穿搭提示词。
|
||||||
|
|
||||||
|
## 15. 暂不做
|
||||||
|
|
||||||
|
- 文件夹/队列作为输入源(保留扩展位,本期不做)。
|
||||||
|
- 模特/姿态/背景的可视化精细编辑。
|
||||||
|
- 多 Excel / 多工作表批处理、列映射可配置化。
|
||||||
|
- 生成结果的应用内预览画廊(先以写回 Excel + 输出目录为准)。
|
||||||
|
|
||||||
|
## 16. 验收要点
|
||||||
|
|
||||||
|
- 选 Excel + 输出目录并记住上次;能读/存提示词。
|
||||||
|
- 能校验 AI 配置缺失;缺 `url/model/api_key` 时阻止开始并提示。
|
||||||
|
- 按行处理:跳过「完成」、按设置重试「失败」、空字段行安全跳过。
|
||||||
|
- 衣服图 + 提示词 → 生成人物上身 JPG(1:1、≤2MB、命名去重)。
|
||||||
|
- 每行实时写回 D/E/F 并保存 Excel;Excel 被占用时明确提示。
|
||||||
|
- 并发/限速/重试/温和停止生效;实时日志 + 进度 + 结束摘要 + 失败清单导出。
|
||||||
|
- 日志写入 `~/.cmbot/logs`;AI 密钥不入库。
|
||||||
|
- 核心逻辑单测通过、不依赖 GUI、Python 3.7 可运行。
|
||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
# 旧「AI 生图」参考项目分析
|
||||||
|
|
||||||
|
> 来源:`D:\chengma\标题生成产品图工具源码`(同事编写)。本文用于为 cmbot 的「AI 穿搭」模块开发提供参考——分析它的功能与实现,提炼可复用点与注意事项。
|
||||||
|
>
|
||||||
|
> ⚠️ 说明:该项目实际名为**「标题生成产品图工具」**,不是字面上的「AI 穿搭」,但它是同事做过的**最接近的 AI 图像生成实现**(本地图 + 提示词 → 调中转 AI 图像 API → 生成电商主图),其 API 调用、传图、批量、并发重试等机制对「AI 穿搭」高度可复用。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 项目定位
|
||||||
|
|
||||||
|
一个 **PySide6 桌面批量生图工具**:读取 Excel 中的商品标题、货号、本地商品图路径,套用通用提示词,调用 **Nano Banana(Gemini 图像)/ GPT Image** 中转 API,为「台湾虾皮女装电商」生成 1:1 的 JPG 主图,并把结果实时写回 Excel。
|
||||||
|
|
||||||
|
面向非技术员工:一键启动、一键打包、离线运行、配置可迁移。
|
||||||
|
|
||||||
|
## 2. 技术栈与依赖
|
||||||
|
|
||||||
|
- **GUI**:PySide6(`requirements.txt`:`PySide6>=6.6,<7`)。
|
||||||
|
- **Excel**:`openpyxl`(读写 `.xlsx`,实时写回)。
|
||||||
|
- **图像**:`Pillow`(校验、压缩到 ≤2MB、转 JPG)。
|
||||||
|
- **HTTP**:`requests` + `urllib3<2`。
|
||||||
|
- **并发**:标准库 `concurrent.futures.ThreadPoolExecutor` + `threading`。
|
||||||
|
- **运行/打包**:`bootstrap.py` 自举 + `offline_runtime/windows-x64`(内置 `python.exe` + 预下载 wheels),`.bat` 一键启动/打包。
|
||||||
|
|
||||||
|
代码组织:**几乎全部逻辑集中在单文件 `app/main.py`(约 1643 行)**,GUI 与业务逻辑混在一起(与 cmbot 的 app/core/services 分层不同)。
|
||||||
|
|
||||||
|
## 3. 目录结构
|
||||||
|
|
||||||
|
```
|
||||||
|
标题生成产品图工具源码/
|
||||||
|
app/main.py # 全部逻辑:配置/Excel/API/并发/GUI
|
||||||
|
bootstrap.py # 启动自举:建 venv 或用离线 runtime,装依赖,起 main
|
||||||
|
api_config.json # 多模型 API 配置(含明文 api_key)
|
||||||
|
settings.json # 上次界面设置(Excel/输出/并发/间隔/分辨率/质量…)
|
||||||
|
prompt.txt # 通用话术(提示词模板,含 {title} {product_id} 占位符)
|
||||||
|
requirements.txt
|
||||||
|
offline_runtime/windows-x64/ # 内置 python + wheels(员工免装 Python)
|
||||||
|
runtime/ # 运行期 venv、日志、失败记录、requirements_state
|
||||||
|
logs/ # 带时间戳的运行日志(保留最近 20 个)
|
||||||
|
图片/ 输出图片/ # 示例输入/输出
|
||||||
|
标题生成产品图.xlsx # 示例 Excel
|
||||||
|
*.bat # win 一键启动/打包
|
||||||
|
需求规格说明.md 需求梳理草稿.md README_使用说明.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 功能概览(按需求规格)
|
||||||
|
|
||||||
|
- Excel 批量驱动:A 标题 / B 货号 / C 本地图路径 / D 结果图路径(写回) / E 状态(完成/失败,写回) / F 失败原因(写回)。
|
||||||
|
- 每处理一行**实时保存 Excel**,降低中途崩溃丢结果的风险;自动跳过 E=「完成」的行;是否重试 E=「失败」的行由界面复选框控制。
|
||||||
|
- 通用话术 `prompt.txt` 可在界面查看/编辑/保存,支持插入 `{title}` `{product_id}` 占位符,提供「最终提示词预览」。
|
||||||
|
- 图片作为**图像输入**随请求发送(不是文本占位符)。
|
||||||
|
- 输出 JPG,1:1,≤2MB,三档质量(小文件 75 / 均衡 85 / 高清 92);默认名 `货号.jpg`,重名自动 `_1`/`_2`,非法字符替换为 `_`。
|
||||||
|
- 并发 / 新请求间隔 / 单任务冷却 / 失败重试次数 / 分辨率(512/1K/2K/4K)/ JPG 质量,均可在界面设置并存 `settings.json`。
|
||||||
|
- 温和停止(不启新任务、已发请求收尾)、实时日志、进度统计(完成/失败/跳过)、结束摘要弹窗、导出失败清单。
|
||||||
|
|
||||||
|
## 5. 核心实现要点
|
||||||
|
|
||||||
|
### 5.1 多模型 API 抽象(最值得借鉴)
|
||||||
|
|
||||||
|
`api_config.json` 支持**多个模型**,每个含 `url / model / api_key / api_type / timeout_seconds / connect_timeout_seconds / extra_body`,界面记住 `last_selected_model`。当前预置两个:
|
||||||
|
|
||||||
|
- `gpt_image_2` → `.../v1/images/edits`,`api_type=images_edits`
|
||||||
|
- `nano_banana_2` → `.../v1/chat/completions`,`model=gemini-3.1-flash-image-preview`,`api_type=auto`
|
||||||
|
|
||||||
|
`ImageApiClient.generate()` 根据 `api_type`(`detect_api_type` 可从 URL 自动判断:`auto/chat/gemini/images/images_edits`)构造**四种请求格式**:
|
||||||
|
|
||||||
|
- **chat(OpenAI 兼容 `/v1/chat/completions`)**:
|
||||||
|
```json
|
||||||
|
{"model": "...", "messages": [{"role":"user","content":[
|
||||||
|
{"type":"text","text": prompt},
|
||||||
|
{"type":"image_url","image_url":{"url":"data:image/jpeg;base64,..."}}]}], "stream": false}
|
||||||
|
```
|
||||||
|
- **gemini(`generateContent`)**:`contents[].parts` = `{text}` + `{inlineData:{mimeType,data(base64)}}`,`generationConfig.responseModalities=["TEXT","IMAGE"]`。
|
||||||
|
- **images**:`{model, prompt, image_urls:[data_url], aspect_ratio:"1:1", resolution, n:1}`。
|
||||||
|
- **images_edits(multipart)**:`data={model,prompt,n,size}` + `files={"image": (name, handle, mime)}`,`Authorization: Bearer <key>`。
|
||||||
|
|
||||||
|
`normalize_api_url()` 把 URL 补全到正确端点(`/v1/chat/completions`、`/v1/images/edits` 等)。`extra_body` 可合并进 payload,便于适配不同接口。
|
||||||
|
|
||||||
|
### 5.2 传图与响应解析
|
||||||
|
|
||||||
|
- **传图**:`image_to_data_url()` 把本地图读成 `data:<mime>;base64,<...>` 的 data-url(chat/gemini/images 用),或 multipart 直接传文件(images_edits 用)。
|
||||||
|
- **取图**:`extract_image_from_response()` 递归遍历 JSON(`walk_json_values`),从多种字段里找图——`image_base64/base64/b64_json/inlineData.data`、或 `data:image/...;base64,` 内联、或图片 URL(再用 session 下载)。对中转 API 返回结构差异做了较强兼容。
|
||||||
|
- **保存**:`save_jpg_under_limit()` 用 Pillow 转 JPG、`ImageOps` 处理方向,循环降质量/尺寸直到 ≤2MB。
|
||||||
|
|
||||||
|
### 5.3 并发、限速、重试、超时
|
||||||
|
|
||||||
|
- `BatchWorker.run()` 用 `ThreadPoolExecutor(max_workers=concurrency)` 调度行任务。
|
||||||
|
- `RateLimiter(interval)`:保证任意两次请求开始间隔 ≥ 新请求间隔。
|
||||||
|
- `process_one()`:每行最多「首次 + retry_count 次」尝试;`retry_delay_seconds(error, attempt)` 对限流/429 用**短阶梯等待**,普通错误短等待,避免看起来卡死;任务间 `task_cooldown` 冷却。
|
||||||
|
- `call_generate_with_heartbeat()`:把单次请求放进子线程,主线程每秒检查,**等待超过 30 秒持续打「已等待 N 秒」心跳日志**;超时按分辨率动态决定(512=180s/1K=240s/2K=360s/4K=600s,可被 `timeout_seconds` 覆盖)。
|
||||||
|
- **温和停止**:`stop_event`(`threading.Event`)置位后不再提交新任务,已发请求等其完成再收尾。
|
||||||
|
|
||||||
|
### 5.4 Excel 写回与失败清单
|
||||||
|
|
||||||
|
- `check_excel_writable()` 开始前检测 Excel 是否被占用。
|
||||||
|
- 每行成功 → 写 D(结果路径)/E=完成;失败 → E=失败/F=原因;**每行处理完即保存**。
|
||||||
|
- `runtime/failure_records.json` 记录失败行;「导出失败清单」只导失败行 + 失败时间 + 重试次数。
|
||||||
|
|
||||||
|
### 5.5 配置、日志、设置
|
||||||
|
|
||||||
|
- `settings.json` 持久化界面设置(Excel/输出路径、并发、间隔、冷却、重试、分辨率、质量、是否重试失败行)。
|
||||||
|
- `logs/` 带时间戳日志,`cleanup_logs()` 只保留最近 20 个;界面实时日志用 Qt 信号 `log = Signal(str)`。
|
||||||
|
- `api_config_errors()` 校验缺失字段:启动时轻提示、点开始时严格阻止。
|
||||||
|
|
||||||
|
### 5.6 GUI 与线程模型
|
||||||
|
|
||||||
|
- `MainWindow(QMainWindow)` 构建界面;后台用 `QThread` + `BatchWorker(QObject)`,信号 `log / progress(done,total,success,failed,skipped) / finished(summary)` 回主线程更新。
|
||||||
|
- 这套「QThread + Worker(QObject) + 信号回主线程」与 cmbot 现有更新检查/导出的后台线程思路一致。
|
||||||
|
|
||||||
|
### 5.7 启动与离线打包
|
||||||
|
|
||||||
|
- `bootstrap.py`:优先用 `offline_runtime/windows-x64/python/python.exe` + 预置 wheels 建 venv 装依赖(员工电脑免装 Python),再启动 `app/main.py`;记录 `runtime/requirements_state.json` 避免重复装。
|
||||||
|
- `.bat`(`win一键启动.bat` / `启动软件.bat` / `start_windows.bat`)调 bootstrap。
|
||||||
|
|
||||||
|
## 6. 对 cmbot「AI 穿搭」模块的借鉴点
|
||||||
|
|
||||||
|
「AI 穿搭」预期是:输入衣服图 → 调 AI 图像 API → 生成模特上身/穿搭效果图。与本项目「本地图 + 提示词 → 生成主图」**核心相同**,可直接借鉴:
|
||||||
|
|
||||||
|
- ✅ **API 客户端抽象**(多模型、`api_type` 多格式、URL 归一化、`extra_body`)——几乎可整体移植成 cmbot 的 `services/ai_image_service.py`。
|
||||||
|
- ✅ **传图方式**(base64 data-url / multipart)与**响应取图**(递归找 base64/URL、下载)的兼容写法。
|
||||||
|
- ✅ **提示词模板 + 占位符 + 预览**(cmbot 可换成衣服相关占位符,如 `{garment}` 或风格参数)。
|
||||||
|
- ✅ **批量 + 并发 + 限速 + 阶梯重试 + 心跳超时**这套稳态调度(中转 API 易 429)。
|
||||||
|
- ✅ **温和停止、实时日志、进度统计、失败清单**的交互范式。
|
||||||
|
- ✅ **JPG 压缩到限值**的输出处理。
|
||||||
|
|
||||||
|
与 cmbot 的差异(落地时要调整):
|
||||||
|
|
||||||
|
- **数据源仍用 Excel(已确认不变)**:cmbot 的 AI 穿搭把 Excel 当作 I/O 适配边界——读行转成内部模型 `OutfitTask`、生成后把新图路径写回 Excel(D/E/F 列),核心对内部模型工作、与数据源解耦(将来再加文件夹/队列输入也不必改核心)。设计见 `docs/11-ai-outfit.md`。
|
||||||
|
- cmbot 走 **app/core/services 分层 + 单测**;本项目是单文件混排,移植时应拆进 `services`(API/网络/Excel)与 `core`(无 GUI 逻辑),便于测试。
|
||||||
|
- cmbot 已有数据目录(`~/.cmbot`)、配置(`config_service`)、日志、打包/更新体系,**不需要**照搬本项目的 bootstrap/offline_runtime/.bat 那一套。
|
||||||
|
- 注意 **Python 3.7 兼容**:旧项目用了 `dict[str, Any]` 等 PEP 585 写法,移植到 cmbot(Python 3.7.9)需 `from __future__ import annotations` 或改 `typing.Dict`。
|
||||||
|
|
||||||
|
## 7. 注意事项与风险
|
||||||
|
|
||||||
|
- 🔒 **`api_config.json` 含明文 API key**(vectorengine.ai 中转)。本文已脱敏,**切勿把真实 key 提交到仓库或外泄**;cmbot 接入时应像更新源凭据那样,放用户数据目录、不入库。
|
||||||
|
- 中转 API 稳定性未知,**会出现 429 上游繁忙**——并发默认 1,阶梯重试,必要时排队。
|
||||||
|
- 接口返回结构不统一,取图逻辑做了较强兼容,移植时保留这套「递归找图」的鲁棒性。
|
||||||
|
- 2K/4K 更慢更贵,界面有二次确认;cmbot 接入时也应提示成本/耗时。
|
||||||
|
- 该项目仅在「标题→主图」场景验证过,「穿搭」提示词与上身效果需另行调试。
|
||||||
|
|
||||||
|
## 8. 关键文件清单(移植时重点看)
|
||||||
|
|
||||||
|
| 文件 / 函数 | 作用 |
|
||||||
|
|---|---|
|
||||||
|
| `app/main.py` `ImageApiClient.generate/build_payload/build_multipart_fields` | API 请求构造(四种格式)⭐ |
|
||||||
|
| `app/main.py` `extract_image_from_response/walk_json_values/decode_image_data_url` | 响应取图(鲁棒)⭐ |
|
||||||
|
| `app/main.py` `image_to_data_url/save_jpg_under_limit` | 传图 / JPG 压缩 |
|
||||||
|
| `app/main.py` `BatchWorker.run/process_one/call_generate_with_heartbeat/RateLimiter` | 并发/限速/重试/心跳 ⭐ |
|
||||||
|
| `app/main.py` `detect_api_type/normalize_api_url/api_config_errors` | 多接口适配与校验 |
|
||||||
|
| `api_config.json` / `settings.json` / `prompt.txt` | 配置与提示词模板 |
|
||||||
|
| `bootstrap.py` + `offline_runtime/` | 离线运行/打包(cmbot 不需要照搬) |
|
||||||
|
| `需求规格说明.md` | 完整功能需求(最权威) |
|
||||||
Reference in New Issue
Block a user