feat: add async image task API

This commit is contained in:
QiuSW
2026-07-08 22:08:48 +08:00
parent c98f713762
commit 25a4080177
26 changed files with 1531 additions and 48 deletions
+31
View File
@@ -1703,3 +1703,34 @@
- 测试期仍保留 allauth `account.EmailAddress` 条件唯一约束在 MySQL 上不可创建的既有 `models.W036` 警告。
- 决策:T-613 不改旧同步接口成功 / 失败响应契约,不新增异步任务表或新路由;只把生成 pipeline 拆成后续 T-614 可复用的准备、预扣、已预扣执行三个阶段。
- 下一步:领取 T-614,新增生图异步提交 / 轮询接口,并复用 T-613 的核心阶段。
## 2026-07-08 实施:T-614 生图异步任务化接口
- 状态:DONE。
- 代码变更:
- `apps/api/models.py` / `apps/api/migrations/0001_initial.py`:新增 `ImageGenerationTask`,公开 UUID `task_id`,关联 `user`、`api_key`、已预扣 `CallRecord`,记录状态、请求哈希、输入文件引用、结果 URL、错误、租约、心跳、worker 和尝试次数;幂等键使用 `(api_key, idempotency_key_hash)` 唯一约束,兼容 MySQL,不使用条件唯一约束。
- `apps/api/image_tasks.py`:新增异步任务 service,提交阶段同步审核 prompt、处理图片输入、预扣点并建 queued 任务;支持 `Idempotency-Key` 去重和 payload 冲突;worker 抢任务后复用 T-613 的 `execute_precharged_generation()`,成功写稳定 URL,失败 / 超时走计费层幂等退款;reaper 处理租约或心跳过期的 running 任务。
- `apps/api/views.py` / `apps/api/urls.py`:新增 `POST /api/v1/generate/image/tasks` 与 `GET /api/v1/generate/image/tasks/{task_id}`;旧 `POST /api/v1/generate/image` 保留。
- `apps/api/management/commands/run_image_tasks.py`:新增 DB worker 命令,支持循环处理、`--once` 和 `--reap-only`。
- `config/settings.py` / `.env.example`:新增 `PUBLIC_BASE_URL`、`MEDIA_PUBLIC_BASE_URL`、`IMAGE_TASK_RETENTION_HOURS`、`GENERATED_IMAGE_RETENTION_HOURS`、`IMAGE_TASK_REAPER_INTERVAL_SECONDS`、`IMAGE_TASK_LEASE_SECONDS`。
- `apps/api/admin.py`:注册图片生成任务只读排障 admin。
- `apps/api/tests.py`:新增异步生图目标测试,覆盖审核拦截、余额不足、幂等、worker 成功、跨用户拒绝、失败退款、reaper 和迟到 worker 幂等。
- 文档变更:
- `docs/api.md`:新增异步提交 / 轮询接口合约、响应示例、错误码和幂等说明。
- `docs/routes.md`:新增两条异步生图 API 路由和 admin 管理项。
- `docs/04-architecture.md`:同步 `ImageGenerationTask` schema、异步计费时序、worker/reaper 语义和 exactly-once 账务终态。
- `docs/deployment.md`:新增 worker 运行 / systemd 示例、Nginx 对 `/api/v1/generate/image/tasks*` 的优先短请求分流、上线验证和检查项。
- `docs/env.md`、`docs/03-tech-stack.md`、`docs/02-requirements.md`:同步异步生图配置与“旧同步 + 新异步并存”口径。
- `README.md`、`docs/00-ai-start-here.md`、`docs/current-state.md`、`docs/project-brief.md`、`docs/project-onepager.md`:同步当前阶段和下一步为 T-615。
- `docs/06-tasks.md`:T-614 标记为 DONE。
- 验证:
- `py -3.12 manage.py makemigrations api`:通过,生成 `apps/api/migrations/0001_initial.py`。
- `py -3.12 manage.py test apps.api.tests.GenerateApiTests -v 2 --keepdb`:通过,28 tests OK。
- 测试环境现象:
- 首次运行 `py -3.12 manage.py test apps.api.tests.GenerateApiTests -v 2` 时,已有测试库 `test_cmhub` 触发交互式删除确认,非交互环境 EOF 中断;改用 `--keepdb` 后迁移并通过。
- 测试期仍保留 allauth `account.EmailAddress` 条件唯一约束在 MySQL 上不可创建的既有 `models.W036` 警告。
- 决策:
- T-614 不引入 Celery / Redis;第一版异步用 MySQL 任务表 + management command worker + systemd。
- 本期不暴露 cancel 路由;后续如需取消,仅允许取消 queued 并单独拆任务。
- `image_base64` 不进 DB 原文,提交阶段解码为输入文件引用;异步结果不透传上游临时链接,只返回 cmhub 托管 URL。
- 下一步:领取 T-615,给旧同步生图接口和新异步路径补结构化遥测,并形成旧同步接口弃用条件。