Files

96 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: T-679a
title: 商品套图自定义网关多来源任务状态机
phase: 7
deps: [T-678]
status: DONE
created: 2026-07-20
---
# T-679a 商品套图自定义网关多来源任务状态机
## 问题 / 背景
**本任务组有意放宽 T-677 的既定边界。** T-677 明确写了「不给商品套图和图片理解新增自定义网关路径,本任务只做入口拦截与提示」。放宽的理由是:来源切换后,商品套图是唯一完全断链的模块——②生文生图在自定义网关下可用,只有⑥不可用,用户切走后套图功能整体消失。图片理解(AI 帮写)不在放宽范围内,继续保持默认网关独占。记录这一点是为了避免后续回看时误判 T-677 与本任务组互相矛盾。
**发布门禁:T-679a、T-679b、T-679c 与集成验收 T-679 未全部完成前不得发布。** 拆分只为控制单次改动面,不构成可独立发布的中间态。重复计费的二次确认提示定义在 T-679c,而两来源混合回归定义在 T-679;任一缺失都会形成资金或恢复语义缺口。
`app/image_studio_generation.py` 当前把运行时、提交、轮询和 job 来源硬编码为 cmhub。自定义网关是无 task ID 的同步图片编辑请求,不能复用 cmhub 的异步恢复模型;若只在现有分支上打补丁,停止、超时或程序中断时会出现已扣费图片丢失、误轮询或重复生成。
## 方案
### 1. 来源与运行快照
- 按 worker 启动时冻结的配置解析来源,不能读取运行中被⑤保存的新配置。
- 固定持久化语义:默认网关为 `generation_source="cmhub"`、`provider="cmhub"`;自定义网关为 `generation_source="direct"`、`provider="openai_images_edits"`。不得把用户填写的 URL、模型名或密钥写入来源字段、SQLite、日志或 UI。
- 自定义网关 job 的 `task_id` 必须为空;默认网关 job 的 task ID 只能由 cmhub 提交返回后写入。
### 2. 同步直连执行
- 复用 T-678 的有序多图图片编辑请求;每个 job 固定 `n=1`,直接取得图片字节后保存资产,不调用 `_poll_job()`。
- 默认网关路径的提交、轮询、下载和幂等键保持不变。分派必须按 job 的持久化来源而非当前设置判断,避免混合项目误走错误通道。
- 直连结果资产可不填 `remote_url`;不得为了填该字段额外拼接、记录或暴露上游地址。
- 将 `MAX_CMHUB_IMAGE_STUDIO_WORKERS` 改名为来源中立的并发常量,数值仍为 5;默认和直连共用全局上限,防止一次生成压垮本机或上游。
### 3. 停止、失败与不确定计费
- 停止只取消尚未发起的 job。已发出的同步请求不可强杀;如果已收到图片字节,必须先保存资产并标成功,停止只阻止后续 job。
- 直连请求提交后发生读超时、连接中断或进程退出时,客户端无法确认服务商是否已受理或计费:不自动重试,不自动恢复,不把该 job 放入“继续查询”。标失败并提供后续手动“重新生成”入口。
- 只在**程序启动后的单次陈旧任务恢复流程**处理遗留 `running` 的 direct job,绝不能在“进入项目”、切换任务或刷新结果时清理;用户可在生成中切换任务,误清理会把仍在运行的 worker 标为失败。
- direct job 进入 `running` 时持久化本次运行会话标识;恢复流程只能处理不属于当前活动会话的 job。若应用未建立可靠的单实例锁或本地运行租约,恢复流程必须跳过状态修改并记录诊断,不能猜测另一实例是否仍在运行。
- 被确认陈旧的 direct job 标为失败,中文原因说明“程序中断,无法确认生成结果,请手动重新生成”;不得自动补发。
- 直连超时取冻结模型的 `connect_timeout_seconds` 和 `timeout_seconds`;若后者未设置,使用项目已有的受限默认值。不得使用 cmhub submit/poll/read timeout 常量。
### 4. 比例与参考图
- 套图比例固定映射:`1:1 -> 1024x1024`;`3:4`、`9:16 -> 1024x1536`;`4:3`、`16:9 -> 1536x1024`。映射覆盖 `product_suite.RATIOS` 的全部五个取值;后四种为近似映射。
- `image_studio_assets.aspect_ratio` 继续表示用户选择的比例,禁止改变其历史语义。新增可空的 `requested_output_size TEXT`、`rendered_width INTEGER`、`rendered_height INTEGER`:前者记录比例映射出的请求尺寸,后两者在文件保存后从真实图片读取。
- 新生成资产无论来源均写入这三项字段;存量资产保持 `NULL`,不回填、不阻塞预览、历史、导出或上传。迁移必须附加式、幂等,并同步更新 `ImageStudioAsset`、`add_asset()` 与读取映射。
- 任务层向调用方返回“是否近似比例”的结构化结果,T-679b 负责在确认框中告知用户;不得静默伪造精确比例。
- 首图主体与其余参考图的规则必须使用已冻结、已持久化的 job prompt;不能在 HTTP 调用层临时拼接,避免确认预览、历史 prompt 与实际请求不一致。
## 验收要点
- [ ] 可创建并执行 direct job,字段值精确为 `direct` / `openai_images_edits` / 空 `task_id`。
- [ ] direct 请求不调用 cmhub 提交、轮询、余额、价格或下载路径;cmhub job 行为不变。
- [ ] 已返回字节的 direct job 即使用户点击停止也会保存成功;未开始 job 才会取消。
- [ ] direct 不发生自动重试;仅启动期确认陈旧的 `running` direct job 会失败,当前活动 worker、切换项目和刷新结果均不会被误清理,也不会进入继续查询。
- [ ] 比例映射、近似标记、`n=1`、多图顺序和 prompt 一致性有纯逻辑测试。
- [ ] 生成资产保留用户比例,并分别记录请求尺寸和文件真实像素尺寸;新增字段的迁移为附加式且幂等,存量资产缺该字段时不报错、不阻塞历史展示。
- [ ] 直连模型 URL、密钥与原始响应不进入 SQLite、事件日志或异常面向用户的文案。
## 测试与文档
- `tests/test_image_studio_generation.py`:来源分派、状态转移、停止边界、超时、启动期陈旧任务恢复、生成中切换/刷新不误清理、比例映射、混合 job 防串路与无自动重试。
- `tests/test_image_studio.py`:来源字段、运行会话标识、请求/真实尺寸字段迁移与中断恢复的数据访问。
- 更新 `docs/04-architecture.md`、`docs/api.md`:记录两种来源 job 生命周期。
## 验证
```bash
py -3.10 -m unittest tests.test_image_studio_generation tests.test_image_studio tests.test_ai
py -3.10 -m ruff check app tests main.py
py -3.10 -m compileall app main.py
git diff --check
```
## 边界(不改什么)
- 不修改⑥按钮可用性、确认框、价格展示、历史 UI;见 T-679b/T-679c。
- 不改 cmhub 协议、幂等键和点数账本;不新增自动重试、provider 私有适配或接口探测。
- 不改图片理解、Chrome/CDP、Excel 或蝦皮更新流程。
## 关联
- T-678:直连图片编辑请求和多图契约。
- T-679b:消费本任务返回的来源、比例与停止语义。
- T-679c:消费本任务的中断状态与重试语义。
## 执行记录
- 已实现双来源任务状态机:默认网关固定持久化为 `cmhub/cmhub` 并保留异步 submit/poll/download;自定义网关固定为 `direct/openai_images_edits`,复用 T-678 同步多图编辑,`task_id` 始终为空、固定 `n=1`、不轮询且不自动重试。执行按 job 已保存来源分派,不读取运行中设置。
- `image_studio_jobs` 新增 `run_session_id`,`image_studio_assets` 新增请求尺寸与真实像素字段;迁移附加式且幂等。启动期在单进程恢复租约下仅清理陈旧 direct `running` job,切换项目/刷新不触发恢复;已收到 direct 图片字节时停止信号不丢弃成果。
- 新增比例映射和近似比例结构化结果;直连输出保存用户原比例、请求尺寸及真实图片尺寸。直连 URL、密钥、原始响应均不写入 SQLite、日志或用户错误文案。
- 已更新 `docs/04-architecture.md`、`docs/api.md`,明确两来源生命周期和 T-679 发布门禁。
- 验证:`py -3.10 -m unittest tests.test_image_studio_generation tests.test_image_studio tests.test_ai`(99 项)、`py -3.10 -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`git diff --check` 均通过;完整 `py -3.10 -m unittest discover -s tests` 通过(646 项)。