- New docs/ui-ai-outfit.html + ui-ai-outfit.png: 「2 AI 穿搭」page mockup, same chrome/palette/components as docs/ui-v1 (blue-only). - Center = recent-results thumbnail strip (finished outputs only) + detail table; dropped the live single-image preview to avoid the concurrent "which row" ambiguity. - §7: 保存话术 persists template via config_service; 预览最终提示词 is a button opening a read-only QDialog rendered from a sample row. - §8: concurrency is Python threads (ThreadPoolExecutor); Qt only signals back to the main thread to refresh UI; default 1 for API limit. - §10: three-column layout, results-strip rationale, settings 3-col. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
14 KiB
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":...}。
- chat(OpenAI 兼容
- 传图:本地衣服图 →
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}(货号);界面提供「插入标题」「插入货号」按钮,把占位符插入光标处。 - 「保存话术」按钮:把当前编辑的模板原文(占位符原样保留,不存替换后的结果)经
config_service写入outfit_prompt.txt。用途是"改完先存、暂不开跑"并给用户明确反馈;与"开始前自动保存"并存、互为兜底(保留按钮是有意为之,对非技术用户更安心)。 - 「预览最终提示词」是按钮,点击弹只读预览窗(
QDialog):取一条样本行把占位符替换成真值,显示最终要发送给 AI 的完整提示词。样本行默认取明细表当前选中行、没选则取第一条待处理行;窗内可切换样本行、可复制;缺{title}占位符时在窗内提示。预览只读,不改话术本身。 - 缺标题占位符时开始前弹窗询问是否继续。
- 默认话术方向(穿搭/上身,区别于旧项目的主图场景,需另调):人物上身实穿、保留衣服款式/版型/颜色/印花、合适身材与场景、电商可用、默认纯净不加促销牛皮癣。
8. 并发、限速、重试、停止
复用旧项目策略(docs/旧ai穿搭项目.md §5.3):
- 并发由 Python 线程负责,PySide6 不参与:
requests在等网络响应时释放 GIL,所以ThreadPoolExecutor起多线程跑行任务时多个 HTTP 请求是真并发。Qt 只负责把进度/结果通过 signal 跨线程排队回主线程刷新 UI——子线程绝不直接操作控件(违反会崩溃/随机出错)。默认并发 1 是迁就中转 API 限流(429),非框架限制,可在界面调高。 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 穿搭」页签)
界面效果图见 docs/ui-ai-outfit.html(浏览器打开)/ docs/ui-ai-outfit.png,完全沿用 cmbot 现有视觉、与「1 添加印花」严格统一(同 docs/ui-v1:浅灰底、#0067c0 蓝单一主色、12px 雅黑、3px 圆角、pill 状态徽章;不引入第二识别色)。「生成中」状态用蓝,与印花页「导出中」同色。把主窗口当前禁用的「2 AI 穿搭」页签启用,做成独立工作页(与「1 添加印花」并列、互不干扰)。
三栏布局:
- 左栏(较宽,设置区):选择 Excel 文件、输出目录(记住上次,存
app_config.json);数据源概览(共 N 行 / 完成 / 待处理 / 失败);AI 模型下拉(来自 AI 模型配置);通用话术编辑 +「保存话术」+「插入标题/货号」+「预览最终提示词」(均见 §7);生成设置 3 列(重试失败行、并发数、新请求间隔、单任务冷却、失败重试、分辨率、JPG 质量)。 - 中栏(结果 + 明细):顶部「最近结果」缩略图条——只展示已完成的人物效果图,新图自动加到最左、首图标「最新」,单击看大图、右键开所在文件夹;下方「处理明细」表(行 / 标题 / 货号 / 衣服图 / 状态 / 结果或原因),按 Excel 行顺序,状态用 完成 / 失败 / 生成中 / 待处理 / 跳过 徽章。
- 右栏(运行区):本次进度环 + 统计(完成 / 失败 / 跳过 / 待处理);开始生成 / 停止生成;导出失败清单 / 打开输出目录;实时日志(含 §8 心跳行)。
设计取舍:不做"实时单图大预览"。 这是"开了走人、回头抽查"的批量工具;单图实时预览在并发时会产生"该显示哪一行"的歧义。改为「最近结果缩略图条」——只展示已落地成品,既保留"早发现话术/模型不对、及时停掉改话术"的价值,又因只显示成品而消除并发歧义。
- 后台用
QThread+Worker(QObject)+ 信号回主线程(与 cmbot 更新检查/导出一致;并发细节见 §8)。
页签内容切换:当前页签栏不切换内容面板(见
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/054.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. 实现阶段建议
分步落地,每步可独立验证:
- 核心与服务(无 GUI,可测):
core.models.OutfitTask/OutfitResult、services/excel_service.py(读/写回/占用检测)、services/ai_image_service.py(移植 ImageApiClient)、core/ai_outfit.py(单行编排)+ 单测(Excel 读写、提示词渲染、取图、命名去重;API 用 mock)。 - 批量编排:并发/限速/重试/停止的
Worker,纯逻辑部分尽量可测。 - UI 页签:页签
QStackedWidget+ai_outfit_panel,接线后台线程、日志、进度、失败清单。 - 配置与提示词:
ai_models.json/outfit_prompt.txt/app_config.json接入,集中读写。 - 真机联调:用真实中转 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 可运行。