T-570 调整 cmhub 生图 submit 超时
This commit is contained in:
+1
-1
@@ -317,7 +317,7 @@ fetch_cmhub_models(base_url, api_key, connect_timeout=10, read_timeout=30) -> li
|
||||
- 标题提示词组装:`gen_title()` 的 direct 与 cmhub 路径共用标题 prompt 规则。若标题提示词包含 `{旧标题}`,生成前替换为该任务旧标题,不再自动追加旧标题块;若不包含 `{旧标题}`,保持旧行为自动追加“旧标题:...”块。两种情况都会追加“请只返回新标题,不要解释。”输出约束;其它 `{...}` 原样保留。
|
||||
- `fetch_cmhub_models()` 调 `GET /api/v1/models` 返回别名清单,供⑤设置页动态下拉使用;Base URL 会先规整为网关根,HTTP 404 映射为 `not_found` 并提示检查 Base URL 或实例是否部署 `/api/v1/models`。
|
||||
- `api_type=chat/auto` 走 OpenAI-compatible chat JSON;`api_type=images_edits` 走 multipart form。
|
||||
- direct 连接超时参考模型 `connect_timeout_seconds`;**返回超时 = 模型 `timeout_seconds` 或 `appconfig.response_timeout()`(随分辨率:512/1k/2k/4k → 180/240/360/600)**。cmhub 使用 `requests timeout=(connect, read)`,connect 来自 `ai.cmhub.connect_timeout`;cmhub 生文读取等待固定 600s。②批量生图异步 submit 读取等待 30s、poll 单次读取等待 15s、本地总预算 900s,图片下载读取等待 900s;`gen_cover()` 旧同步兼容路径仍用 900s 读取等待。
|
||||
- direct 连接超时参考模型 `connect_timeout_seconds`;**返回超时 = 模型 `timeout_seconds` 或 `appconfig.response_timeout()`(随分辨率:512/1k/2k/4k → 180/240/360/600)**。cmhub 使用 `requests timeout=(connect, read)`,connect 来自 `ai.cmhub.connect_timeout`;cmhub 生文读取等待固定 600s。②批量生图异步 submit 读取等待 36s、poll 单次读取等待 15s、本地总预算 900s,图片下载读取等待 900s;`gen_cover()` 旧同步兼容路径仍用 900s 读取等待。
|
||||
- 并发数/重试/分辨率/jpg 质量来自 `appconfig.ai_config()`;标题/图片并发会被夹到 1..5,失败重试次数会被夹到 0..10,兼容旧配置中的超限值;Key 本地明文存储,但不入日志、不导出。cmhub 响应的 `points_cost/points_balance/call_id` 不改变返回值,通过 `on_event` metadata 事件上报,GUI 余额/计费展示留给 T-528。
|
||||
- 标题快、图片慢:分两段、各用各自并发数;失败按 `retry` 重试,仍失败记 error 不阻塞其余。cmhub 批量生图使用内部实际并发 `min(image_concurrency, 5)` 约束 submit+poll 在途数;已有 `tasks.image_task_id` 时直接 GET 续查,不二次 submit;submit 前先持久化 `image_task_key`,submit 成功立即持久化 `image_task_id`;poll `failed/expired` 会清空二者,poll 超时/用户停止/程序退出则保留二者供下次续查。拿到 `image_url` 后交给独立下载/保存线程池,下载线程数与实际生图并发一致且最大 5;T-548 后图片下载后端由 `ai.cmhub.download_with_curl` 控制,默认 `auto`:Windows 且检测到系统 curl 时优先用 curl 下载,否则回退 requests;curl 失败也会自动回退 requests。下载前仍执行公网 URL 校验,curl 使用 `-K` 临时配置文件传入 URL,不把带 token 的 `image_url` 放进命令行参数;`use_system_proxy=false` 时 curl 加 `--noproxy "*"`。下载失败最多安全重试 3 次,只复用同一个 `image_url`,不会重新调用 cmhub 生图接口;下载总耗时超过 20 秒时写“图片下载较慢”警告;direct 兼容路径暂保持原 `image_concurrency` 语义。
|
||||
- cmhub 图片地址兼容:优先递归读取 `image_url` / `image_url.url` / `images[]` / `image_urls[]` 等字段;若返回 `/generated/...` 或 `generated/...` 相对路径,先按 cmhub Base URL 补全为完整 `http(s)` URL,再进入原有公网 URL 安全校验和下载。
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
| 生图请求 | `images_edits` multipart 或 vision chat | `{prompt, model:别名, image_base64?/image_url?, resolution?, aspect_ratio?, parameters?}` |
|
||||
| 生图响应 | 直接返回 image bytes | ②批量:submit 返回 `{task_id, ...}`,poll 成功返回 `{result:{image_url}}`;兼容同步:`{image_url, ...}` → 需再下载 |
|
||||
| 错误 | HTTP error 文本 | `{error:{code,message}}`:`insufficient_points`(402)/`upstream_error`(502)/`rate_limited`(429)/`unauthorized`(401)/`account_disabled`(403)/`bad_request`(400)/`model_not_allowed`/`no_pricing_rule` |
|
||||
| 超时 | 按 `resolution_timeouts` | ②批量生图 submit 短读超时、poll 总预算 900s、下载 900s;旧同步兼容路径仍 900s |
|
||||
| 超时 | 按 `resolution_timeouts` | ②批量生图 submit 读取等待 36s、poll 总预算 900s、下载 900s;旧同步兼容路径仍 900s |
|
||||
| 幂等 | 直连一次成功一次 | **非幂等、无幂等键**:客户端超时 ≠ 未扣点,读超时后不可无脑重发 |
|
||||
|
||||
关键差异(决定改造点):
|
||||
@@ -100,7 +100,7 @@
|
||||
- **单独 `gen_cover()` 兼容**:公开函数没有本地 `task.id/db_path` 上下文,第一版继续调用旧同步 `POST /api/v1/generate/image`,保持返回值和旧调用方兼容;②批量生成才使用完整持久化、幂等键和重启续查。
|
||||
- `resolution` 归一为**大写** `512/1K/2K/4K`(cmshopee 内部用小写 `1k`,发请求前转 `1K`);`aspect_ratio` 默认 `1:1`(Shopee 封面)。
|
||||
- **下载**:拿 `image_url` 后下载该图字节(cmhub 自家对象存储公网 URL)→ 交给现有 `_save_jpeg(image_bytes, out_path, resolution, quality)` 落盘。cmshopee 兼容 `image_url` / `image_url.url` / `images[]` / `image_urls[]` 等返回结构;若 cmhub 返回相对路径(如 `/generated/...`),先按 cmhub Base URL 补全为完整 `http(s)` URL。下载 helper 必须校验 URL scheme 只允许 `http/https`,拒绝内网/回环/本机地址,并校验域名解析后的 IP 仍不属于内网/回环/本机地址,设置超时和大小上限;生成后**立即下载**(对象存储 URL 可能有有效期)。`points_cost`/`points_balance`/`call_id` 通过事件回调传播,不改变 `gen_cover` 返回值。
|
||||
- **超时(关键)**:②批量生图 submit 读取等待约 30 秒,poll 单次读取等待约 15 秒,本地总预算 900 秒;撞预算、用户停止或程序退出都保留 `image_task_id/image_task_key`,下次直接续查,不重新 submit。下载读取等待 900 秒;旧同步兼容路径也使用 900 秒。绝不用 30s/60s 同步死等旧生图,否则客户端超时但服务端仍在算并扣点。
|
||||
- **超时(关键)**:②批量生图 submit 读取等待 36 秒,poll 单次读取等待约 15 秒,本地总预算 900 秒;撞预算、用户停止或程序退出都保留 `image_task_id/image_task_key`,下次直接续查,不重新 submit。下载读取等待 900 秒;旧同步兼容路径也使用 900 秒。绝不用 30s/60s 同步死等旧生图,否则客户端超时但服务端仍在算并扣点。
|
||||
- **并发(T-545/T-564 已实现)**:最近实测 `/media/generated/images/*.png` 下载链路在 10 并发下明显慢且有连接失败。cmhub 模式下采用内置保护:实际 submit+poll 在途并发 = `min(ai.image_concurrency, 5)`;下载/保存使用独立线程池,线程数与实际生图并发一致,同样最大 5;不新增用户可见配置项。运行日志必须同时显示用户设置和实际并发,避免用户误解设置 10 就会对 cmhub 打 10 并发。下载失败记为该任务失败,不得重新调用生图接口导致重复扣点。
|
||||
- **下载后端(T-548 已实现)**:cmhub 生成/models/balance 仍走共享 requests Session;仅 `image_url` 图片下载可按 `ai.cmhub.download_with_curl` 选择系统 curl。默认 `auto` 在 Windows 且检测到系统 curl 时优先 curl,非 Windows、无 curl 或 curl 失败自动回退 requests。curl 调用前仍做公网 URL 校验,用 `-K` 临时配置文件传 URL,避免 token 出现在进程命令行;`use_system_proxy=false` 时加 `--noproxy "*"`。
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: T-570
|
||||
title: cmhub 异步生图 submit 读取等待调整为 36 秒
|
||||
phase: 7
|
||||
deps: [T-564]
|
||||
status: DONE
|
||||
created: 2026-07-09
|
||||
---
|
||||
|
||||
## 问题 / 背景
|
||||
|
||||
T-564 后,②批量生图已改为异步任务接口:先 `POST /api/v1/generate/image/tasks` 提交任务,再轮询 `GET /api/v1/generate/image/tasks/{task_id}` 获取图片地址。当前 submit 阶段单次 read timeout 是 30 秒。
|
||||
|
||||
真实使用中,cmhub submit 可能因为上游排队、网关抖动或服务端首次调度稍慢,30 秒边界略紧,容易在服务端可能已受理任务但客户端未拿到 `task_id` 的窗口报超时。为降低边界抖动,本任务把 submit 阶段单次 read timeout 从 30 秒调到 36 秒。
|
||||
|
||||
## 方案
|
||||
|
||||
- `app/ai.py`
|
||||
- 将 `CMHUB_IMAGE_SUBMIT_READ_TIMEOUT_SECONDS` 从 `30` 改为 `36`。
|
||||
- 只影响 `POST /api/v1/generate/image/tasks` 的读取等待。
|
||||
- 不改 poll 单次 15 秒、本地总预算 900 秒、图片下载 900 秒。
|
||||
- `tests/test_ai.py`
|
||||
- 补充/更新 cmhub 异步生图测试,断言 submit 请求实际使用 `timeout=(connect_timeout, 36)`。
|
||||
- 文档
|
||||
- 同步 `docs/api.md` 和 `docs/cmhub-integration-design.md` 中关于 submit 读取等待的精确说明。
|
||||
|
||||
## 验收要点
|
||||
|
||||
- `POST /api/v1/generate/image/tasks` 的 read timeout 为 36 秒。
|
||||
- poll 单次读取等待仍为 15 秒,本地总预算仍为 900 秒。
|
||||
- 下载读取等待仍为 900 秒。
|
||||
- 不改 cmhub submit/poll 状态机、DB schema、幂等键和重启续查逻辑。
|
||||
- 验证命令:
|
||||
- `py -3.10 -m unittest tests.test_ai`
|
||||
- `python -m ruff check app tests main.py`
|
||||
- `py -3.10 -m compileall app main.py`
|
||||
- `py -3.10 -m unittest discover -s tests`
|
||||
- `git diff --check`
|
||||
|
||||
## 边界(不改什么)
|
||||
|
||||
- 不改 `ai.cmhub.connect_timeout` 默认值 66 秒。
|
||||
- 不改生图 poll 总等待 900 秒、poll 单次 15 秒和轮询间隔。
|
||||
- 不改图片下载逻辑、curl/requests 选择、图片 URL 安全校验。
|
||||
- 不改 CDP/Shopee、Excel、GUI 布局或 DB schema。
|
||||
|
||||
## 执行记录
|
||||
|
||||
- 2026-07-09:完成 T-570。
|
||||
- `app/ai.py`:将 `CMHUB_IMAGE_SUBMIT_READ_TIMEOUT_SECONDS` 从 30 调整为 36,只影响 `POST /api/v1/generate/image/tasks` 的 submit 读取等待;poll 单次 15 秒、本地总预算 900 秒和下载 900 秒不变。
|
||||
- `tests/test_ai.py`:在 cmhub 异步 submit 落库测试中断言实际请求 timeout 为 `(connect_timeout, 36)`,防止后续回退。
|
||||
- 文档:同步 `docs/api.md` 与 `docs/cmhub-integration-design.md` 的 submit 读取等待口径。
|
||||
- 验证通过:`py -3.10 -m unittest tests.test_ai`、`python -m ruff check app tests main.py`、`py -3.10 -m compileall app main.py`、`py -3.10 -m unittest discover -s tests`、`git diff --check`。
|
||||
Reference in New Issue
Block a user