feat(product-suite): add direct job state machine

This commit is contained in:
chengma
2026-07-20 18:12:44 +08:00
parent 2a2cbad7bd
commit aa000ff5e6
11 changed files with 820 additions and 101 deletions
+9 -4
View File
@@ -392,9 +392,10 @@ sync_original_asset_urls(project_id, image_urls, path=None) -> list[ImageStudioA
list_assets(project_id, kind=None, include_missing=True, path=None) -> list[ImageStudioAsset]
reorder_original_assets(project_id, asset_ids, path=None) -> list[ImageStudioAsset]
remove_original_assets_if_unused(project_id, asset_ids, path=None) -> list[ImageStudioAsset]
create_job(project_id, source_asset_id=None, job_type="main", prompt="", ...) -> ImageStudioJob
create_job(project_id, source_asset_id=None, job_type="main", prompt="", generation_source="cmhub", provider="cmhub", ...) -> ImageStudioJob
list_jobs(project_id, statuses=None, path=None) -> list[ImageStudioJob]
list_resumable_jobs(project_id=None, include_failed_downloads=False, path=None) -> list[ImageStudioJob]
fail_stale_direct_jobs(active_run_session_ids=(), path=None) -> int
list_generation_rounds(project_id, limit=None, offset=0, path=None) -> list[ImageStudioGenerationRound]
get_successful_generation_history_summary(project_id, path=None) -> ImageStudioSuccessfulGenerationHistorySummary
list_global_history_accounts(path=None) -> list[ImageStudioHistoryAccount]
@@ -423,8 +424,10 @@ build_suite_prompt(base_prompt, settings, category, item_id, source_index=1) ->
build_job_specs(source_assets, base_prompt, settings, item_id) -> list[dict]
# app/image_studio_generation.py
generate_image_jobs(project_id, source_asset_id, prompt, count, job_type="main", aspect_ratio="1:1", ...) -> dict
resume_image_jobs(project_id=None, aspect_ratio="1:1", ...) -> dict
generate_image_jobs(project_id, source_asset_id, prompt, count, job_type="main", aspect_ratio="1:1", run_session_id=None, ...) -> dict
resume_image_jobs(project_id=None, aspect_ratio="1:1", run_session_id=None, ...) -> dict
requested_output_spec(aspect_ratio) -> dict
recover_stale_direct_jobs_at_startup(lease, path=None) -> int
# app/image_studio_export.py
export_project_selection(project_id, parent_dir, existing_mode="fail", path=None, config=None) -> ExportResult
@@ -443,7 +446,9 @@ export_generation_round(project_id, generation_round_key, parent_dir, path=None,
- 拉取蝦皮原主图只读:复用 `editor.open_product(..., bring_to_front=False)` 和 `editor.read_product_image_urls()`,不上传、不拖拽、不点击更新。
- 原图下载走 `image_studio_images` 的公网 URL、大小、Content-Type、重定向和 PIL 解码校验;只在用户单击时落盘。
- `remove_original_assets_if_unused()` 会先校验整批原图的项目归属、资产类型及 job/终选引用,再在单个事务中删除资产行并连续重排 `source_order`;任一图片不可删除时整批不变,本地源文件和蝦皮线上图片始终保留。
- 默认网关托管生图每张都是独立 job:保存 `task_key/task_id/status/call_id/points_cost/points_balance`;已有 `task_id` 时只 poll/download,不重复 submit。商品套图把平台/国家/语言/比例等上下文写入每个 job prompt,并把比例实参传到默认网关;界面不展示 Provider URL、OpenAI Key 或上游接口路径。`create_generation_jobs()` 与无 `task_id` 的提交分支均拒绝非默认网关;`run_jobs()` 只放行同时满足 `generation_source="cmhub"`、`provider="cmhub"` 与非空 `task_id` 的旧任务继续查询,其他来源不得借 task ID 触发轮询或新提交。
- T-679a 后,商品套图 job 固定持久化来源,不以运行时设置反推:默认网关为 `generation_source="cmhub"`、`provider="cmhub"`,沿用托管异步 `task_key/task_id/status/call_id/points_cost/points_balance` 及 submit/poll/download;自定义网关为 `generation_source="direct"`、`provider="openai_images_edits"`,`task_id` 必须为空,复用 T-678 的同步多图编辑请求,固定 `n=1`,收到图片字节即保存本地资产,不轮询、不写远程 URL、不自动重试。任何来源/提供方组合不精确匹配的 job 都拒绝执行,不能借 task ID 串到 cmhub。
- direct job 进入 `running` 时保存仅用于本次进程的 `run_session_id`。只有应用启动阶段持有本地单进程恢复租约时,才将不属于活动会话的遗留 direct `running` job 标为失败,提示“程序中断,无法确认生成结果,请手动重新生成”;切换项目、刷新和恢复 cmhub 任务绝不触发该清理。同步请求返回图片后即使用户刚点击停止,也必须保存为成功;停止只取消未开始 job。连接/读取超时或进程中断的 direct job 不自动补发、不进入继续查询。
- `image_studio_assets.aspect_ratio` 始终保存用户选择值;新生成资产另保存可空的 `requested_output_size`、`rendered_width`、`rendered_height`。比例映射为 `1:1 -> 1024x1024`、`3:4/9:16 -> 1024x1536`、`4:3/16:9 -> 1536x1024`,后四种由运行结果返回近似比例标记。旧资产字段保持 `NULL`;初始化迁移只附加字段且可重复执行。
- T-658a 后商品套图异步提交的图片字段统一为 `images` 数组(每项仅含本地编码的 `image_base64`),单图不再保留顶层 `image_base64` 兼容字段。提交层限制最多8张、单图原文件10MiB、编码后总输入32MiB;参考图快照字段由 T-658b 扩展。
- T-658b 后 `image_studio.create_job(..., reference_asset_ids=...)` 接收同项目、去重且不包含主图的有序图片 ID 列表,并以 JSON 快照写入 `image_studio_jobs.reference_asset_ids`;`job_reference_asset_ids(job)` 负责解析和校验。历史 `NULL` 快照返回空列表,恢复/重试不根据当前商品原图补图。
- `include_failed_downloads=True` 允许 failed 但已有 `task_id`、无输出 asset 的任务继续查询,用于下载失败或本地保存失败恢复。