docs: define outfit image concurrency
This commit is contained in:
+11
-9
@@ -81,6 +81,7 @@ C 列除了单张图片文件,**也可以是一个目录**(如 `d:/images/a/
|
||||
共用本行的标题/货号与话术。
|
||||
- 输出落到 `AI 穿搭输出目录/<目录叶子名>/`(默认是程序旁的 `穿搭图片\`,见 §9.1);Excel 回写仍是**整行一个状态**:
|
||||
D=子目录绝对路径、E=全部成功才 `完成` 否则 `失败`、F=失败张数/原因。
|
||||
- Excel 行本身按顺序处理;并发只发生在当前目录行内部(见 §8 / §9.1)。
|
||||
- 目录不存在或目录内没有图片 → 该行 `失败` 并记录原因,不中断其它行。
|
||||
|
||||
## 5. 内部数据模型
|
||||
@@ -212,10 +213,12 @@ Excel 行 → `OutfitTask` 列表的转换由 `excel_service` 完成;核心只
|
||||
|
||||
## 8. 并发、限速、重试、停止
|
||||
|
||||
复用旧项目策略(`docs/旧ai穿搭项目.md` §5.3):
|
||||
复用旧项目的限速、重试、心跳与温和停止策略(`docs/旧ai穿搭项目.md` §5.3),但并发语义改为更适合「一行一个目录」的模型:
|
||||
|
||||
- **并发由 Python 线程负责,PySide6 不参与**:`requests` 在等网络响应时释放 GIL,所以 `ThreadPoolExecutor` 起多线程跑行任务时多个 HTTP 请求是真并发。Qt 只负责把进度/结果通过 **signal 跨线程排队回主线程**刷新 UI——**子线程绝不直接操作控件**(违反会崩溃/随机出错)。默认并发 1 是迁就中转 API 限流(429),非框架限制,可在界面调高。
|
||||
- `ThreadPoolExecutor(max_workers=并发数)` 调度行任务;`RateLimiter(新请求间隔)` 限制请求开始间隔;任务间 `单任务冷却`。
|
||||
- **Excel 行并发固定为 1**:批次按 Excel 行顺序处理。这样一行一个目录时,D/E/F 仍按行聚合写回,避免多行同时写表或同时刷状态导致排查困难。
|
||||
- 界面参数命名为**图片并发数**,只控制**当前目录行内部**同时生成多少张图片。默认 1;调到 2/3 时,同一目录内最多同时发起对应数量的图片请求。单文件行不参与图片并发,仍一行一张顺序处理。
|
||||
- **并发由 Python 线程负责,PySide6 不参与**:`requests` 在等网络响应时释放 GIL,所以目录内 `ThreadPoolExecutor(max_workers=图片并发数)` 的多个 HTTP 请求是真并发。Qt 只负责把进度/结果通过 **signal 跨线程排队回主线程**刷新 UI——**子线程绝不直接操作控件**(违反会崩溃/随机出错)。
|
||||
- `RateLimiter(新请求间隔)` 限制同一目录内每个新图片请求的启动间隔;任务间 `单任务冷却` 作用于 Excel 行之间。因为行并发固定为 1,批次的最大 HTTP 并发约等于图片并发数。
|
||||
- 每行最多「首次 + 重试次数」尝试;限流/429 用短阶梯等待,普通错误短等待。
|
||||
- 单次请求放子线程 + 主线程秒级检查,**等待 >30 秒持续打心跳日志**;超时按分辨率动态决定(512/1K/2K/4K → 180/240/360/600 秒,可被 `timeout_seconds` 覆盖)。
|
||||
- **温和停止**:置位停止后不再提交新任务,已发请求收尾后正常写回。
|
||||
@@ -238,9 +241,8 @@ Excel 行 → `OutfitTask` 列表的转换由 `excel_service` 完成;核心只
|
||||
- **不加 `_1`/`_2` 去重后缀**:目标文件已存在视为「已生成」并**跳过**,使整行可
|
||||
幂等重试——重试只补做缺失/失败的那几张,已成功的不重复调 API。
|
||||
- 整行回写 Excel 时,D 列写**子目录**绝对路径(而非单个文件)。
|
||||
- 目录内逐张**顺序**生成(同一 worker 内);为避免压垮中转 API,逐张之间按
|
||||
「新请求间隔」本地 sleep 节流。并发=1(默认)时即等于全局节流;并发>1 时为近似。
|
||||
进度条按 Excel 行前进(一个目录=1 格),逐张进度通过实时日志反馈。
|
||||
- 目录内按**图片并发数**生成;默认 1 时等同旧的逐张顺序生成。为避免压垮中转 API,每个新图片请求启动前仍按「新请求间隔」节流。图片并发数 >1 时,完成日志和缩略图出现顺序不保证与文件名排序完全一致。
|
||||
- 进度条按 Excel 行前进(一个目录=1 格),逐张进度通过实时日志与最近结果缩略图反馈。整行全部图片收尾后才写回 Excel D/E/F。
|
||||
|
||||
## 10. 界面(「2 AI 穿搭」页签)
|
||||
|
||||
@@ -250,7 +252,7 @@ Excel 行 → `OutfitTask` 列表的转换由 `excel_service` 完成;核心只
|
||||
|
||||
- **左栏(数据源 + 话术创作,~360px)**:`Excel` / `输出` 各为**行内一行**(标签 + 路径 + 浏览,省纵向空间);数据源概览(共 N 行 / 完成 / 待处理 / 失败);**加大的**穿搭生成话术编辑 +「保存话术」+「插入标题」;下方常驻**加大的最终生成要求预览**(内嵌、实时,标题行右侧放样本行下拉,含 §7.1 自动附加的输出要求)。AI 模型下拉不在此(见右栏)。
|
||||
- **中栏(结果 + 明细)**:顶部「最近结果」缩略图条——**只展示已完成的人物效果图**,新图自动加到最左、首图标「最新」,单击看大图、右键开所在文件夹;下方「处理明细」表(行 / 标题 / 货号 / 衣服图 / 状态 / 结果或原因),按 Excel 行顺序,状态用 完成 / 失败 / 生成中 / 待处理 / 跳过 徽章。
|
||||
- **右栏(设置 + 运行,~400px)**:生成设置标题与「重试上次失败的行」同排;并发数 / 新请求间隔 / 单任务冷却 / 失败重试 / 分辨率 / JPG 质量保持 **3 列 × 2 行**;`AI 模型` 标签与下拉框同排;本次进度 + 统计(完成 / 失败 / 待处理);开始生成 / 停止生成同排;导出失败清单 / 打开输出目录同排;节省的纵向空间给实时日志(含 §8 心跳行)。
|
||||
- **右栏(设置 + 运行,~400px)**:生成设置标题与「重试上次失败的行」同排;图片并发数 / 新请求间隔 / 单任务冷却 / 失败重试 / 分辨率 / JPG 质量保持 **3 列 × 2 行**;`AI 模型` 标签与下拉框同排;本次进度 + 统计(完成 / 失败 / 待处理);开始生成 / 停止生成同排;导出失败清单 / 打开输出目录同排;节省的纵向空间给实时日志(含 §8 心跳行)。
|
||||
|
||||
> **设计取舍:不做"实时单图大预览"。** 这是"开了走人、回头抽查"的批量工具;单图实时预览在并发时会产生"该显示哪一行"的歧义。改为「最近结果缩略图条」——只展示已落地成品,既保留"早发现话术/模型不对、及时停掉改话术"的价值,又因只显示成品而消除并发歧义。
|
||||
|
||||
@@ -357,7 +359,7 @@ Excel 行 → `OutfitTask` 列表的转换由 `excel_service` 完成;核心只
|
||||
## 13. 安全考量
|
||||
|
||||
- AI 中转 API key 为明文,仅放 `~/.cmbot`,**不入库、不随包分发到公网**;内部使用可接受(与更新凭据一致)。
|
||||
- 中转 API 会 429 限流:并发默认 1,阶梯重试。
|
||||
- 中转 API 会 429 限流:图片并发数默认 1,阶梯重试。
|
||||
- 衣服图为本机路径;不存在/打不开/非图片 → 该行失败并记录,继续下一行。
|
||||
|
||||
## 14. 实现阶段建议
|
||||
@@ -384,6 +386,6 @@ Excel 行 → `OutfitTask` 列表的转换由 `excel_service` 完成;核心只
|
||||
- 按行处理:跳过「完成」、按设置重试「失败」、空字段行安全跳过。
|
||||
- 衣服图 + 提示词 → 生成人物上身 JPG(1:1、≤2MB、命名去重)。
|
||||
- 每行实时写回 D/E/F 并保存 Excel;Excel 被占用时明确提示。
|
||||
- 并发/限速/重试/温和停止生效;实时日志 + 进度 + 结束摘要 + 失败清单导出。
|
||||
- Excel 行顺序处理、图片并发/限速/重试/温和停止生效;实时日志 + 进度 + 结束摘要 + 失败清单导出。
|
||||
- 日志写入 `~/.cmbot/logs`;AI 密钥不入库。
|
||||
- 核心逻辑单测通过、不依赖 GUI、Python 3.7 可运行。
|
||||
|
||||
@@ -340,7 +340,7 @@
|
||||
<div class="rt">生成设置</div>
|
||||
<div class="ckline" style="margin-bottom:10px"><span class="cbox on"></span>重试上次失败的行(失败 3)</div>
|
||||
<div class="sgrid">
|
||||
<div class="fl"><label>并发数</label><div class="inp"><input value="1"></div></div>
|
||||
<div class="fl"><label>图片并发数</label><div class="inp"><input value="1"></div></div>
|
||||
<div class="fl"><label>新请求间隔</label><div class="inp"><input value="2"><span class="u">秒</span></div></div>
|
||||
<div class="fl"><label>单任务冷却</label><div class="inp"><input value="1"><span class="u">秒</span></div></div>
|
||||
<div class="fl"><label>失败重试</label><div class="inp"><input value="2"><span class="u">次</span></div></div>
|
||||
@@ -377,7 +377,7 @@
|
||||
<div class="logbody">
|
||||
<div class="l"><span class="ts">15:42:01</span><span>读取 商品表.xlsx:60 行,待处理 47</span></div>
|
||||
<div class="l"><span class="ts">15:42:01</span><span class="warn">跳过第 9 行:标题/货号为空</span></div>
|
||||
<div class="l"><span class="ts">15:42:02</span><span>开始生成,并发 1,分辨率 1K</span></div>
|
||||
<div class="l"><span class="ts">15:42:02</span><span>开始生成,Excel 行并发 1,图片并发 1,分辨率 1K</span></div>
|
||||
<div class="l"><span class="ts">15:42:18</span><span class="ok">✓ TY027 完成 → TY027.jpg(1.6 MB)</span></div>
|
||||
<div class="l"><span class="ts">15:42:40</span><span class="ok">✓ TY028 完成 → TY028.jpg(1.8 MB)</span></div>
|
||||
<div class="l"><span class="ts">15:43:02</span><span class="erl">✕ TY029 失败:衣服图打不开(文件不存在)</span></div>
|
||||
|
||||
@@ -1215,3 +1215,20 @@
|
||||
- [x] `core/ai_outfit.py` 目录行输出保持 `AI 穿搭输出目录/<目录叶子名>/<源图名>.jpg`,单文件行仍按当前输出目录落盘
|
||||
- [x] 补测试:默认目录路径、不可写回退、AI 穿搭面板默认值、目录行输出到 `穿搭图片/<目录名>/`
|
||||
- [~] 验证:相关单测通过,离屏启动 AI 穿搭页时输出框默认显示 `穿搭图片`;全套 `python -m unittest discover -s tests` 当前被工作区未提交的 `packaging/default_config/ai_models.json` 改动阻塞(模型顺序/API key 与出厂模板规范不一致),待清理该文件后重跑
|
||||
|
||||
### 19.17 AI 穿搭并发语义改为「行顺序 + 图片并发」 — docs/11 §8 / §9.1 / §10
|
||||
|
||||
前置阅读:`docs/11-ai-outfit.md`(§4.1、§8、§9.1、§10)、`src/core/outfit_batch.py`、`src/core/ai_outfit.py`、`src/app/widgets/ai_outfit_panel.py`。
|
||||
|
||||
背景:当前「并发数」实际用于 Excel 行任务并发;但现在 C 列常见用法是一行一个图片目录,目录内有多张衣服图。用户期望 Excel 行按顺序处理、每行一次聚合写回,界面并发参数用于控制**当前目录内同时处理多少张图片**。这样既符合「一行=一个子目录」的数据结构,也能把提速点放在同一目录内的多图生成上。
|
||||
|
||||
设计取舍:外层 `OutfitBatchRunner` 固定 Excel 行并发为 1;界面文案改为「图片并发数」。配置字段可先兼容复用现有 `outfit_concurrency`,但业务含义改为目录内图片并发;若后续改字段名,需要迁移旧配置。
|
||||
|
||||
- [x] 文档更新:`docs/11-ai-outfit.md` 明确 Excel 行并发固定 1、图片并发数只作用于目录内部;`docs/ui-ai-outfit.html` 示例文案改为「图片并发数」
|
||||
- [ ] `ai_outfit_panel.py`:右侧生成设置 label 从「并发数」改为「图片并发数」,日志启动行同时显示「Excel 行并发 1 / 图片并发 N」
|
||||
- [ ] `_OutfitWorker` / `OutfitBatchRunner`:外层 Excel 行任务固定顺序处理,不再用界面并发值作为行 `max_workers`
|
||||
- [ ] `generate_outfit_image`:增加或接入 `image_concurrency` 参数;单文件行保持顺序单张处理
|
||||
- [ ] `core/ai_outfit.py` 目录分支:使用 `ThreadPoolExecutor(max_workers=图片并发数)` 并发生成目录内图片;已存在输出仍跳过,部分失败仍聚合到整行结果
|
||||
- [ ] 保留「新请求间隔」启动节流;图片并发数 >1 时日志/缩略图完成顺序允许与文件名排序不同
|
||||
- [ ] 补测试:Excel 行顺序处理、目录内图片并发、单文件行不并发、已存在跳过、部分失败聚合、UI label/default/config 兼容
|
||||
- [ ] 验证:相关单测通过;离屏启动 AI 穿搭页确认 label 和日志文案;如工作区清理后再跑全套测试
|
||||
|
||||
Reference in New Issue
Block a user