feat(ai-image): AI生图开发
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@ API 启动后会在 `/api-docs` 提供 Swagger UI,并在其 OpenAPI 文档中
|
||||
| [`pricing.md`](./pricing.md) | 已设计 | 汇率、物流价卡、即时试算、定价方案、报价快照衔接。 |
|
||||
| [`collection-and-extension.md`](./collection-and-extension.md) | 已设计 | 插件授权、采集写入、采集箱查询、素材转存与状态。 |
|
||||
| [`product-editor-and-publishing.md`](./product-editor-and-publishing.md) | 编辑器与发布预检已实现 | 编辑上下文、完整 SKU 草稿、店铺切换、规格继承、AI 来源素材字段级合并、平台级 Ozon 类目/属性/字典按需刷新及首次上架目录预检;定价、AI 任务与真正的 Ozon 发布 job 仍待实现。 |
|
||||
| [`online-listings.md`](./online-listings.md) | 初版已设计 | 店铺独有的在线商品镜像、读取与异步同步;编辑/认领仍待讨论。 |
|
||||
| [`online-listings.md`](./online-listings.md) | 首期已实现 | 店铺独有的在线商品镜像、读取与手动异步同步;编辑/认领仍待讨论。 |
|
||||
| [`platform-catalog-admin.md`](./platform-catalog-admin.md) | 已实现 | 全局系统管理员授权、平台参考源配置、类目/属性/字典读取、每周树同步、刷新策略、三种类型属性批次、优先级、任务状态及后台页面。 |
|
||||
|
||||
旧的 [`../product/api.md`](../product/api.md) 是商品域的早期草案:已确认的产品规则可作为背景,但不能当作最终 HTTP 契约。后续商品模块会迁入本目录并替换其中的路径和细节。
|
||||
|
||||
@@ -30,6 +30,8 @@ Headers:扩展 Bearer token 与 `Idempotency-Key` 必填。请求体为已定
|
||||
|
||||
尚未创建任何 `product_platform_profile` 时,SKU 草稿仍是来源投影:同一 `source_variant_key` 原位更新,新 key 创建,缺失 key 软删除。**一旦进入任一平台编辑器,SKU 草稿及其平台 mapping 不再是可替换来源投影。** 此后的重复采集仍更新来源证据、规范化载荷和候选素材;同 key 复用原 SKU ID 且不覆盖用户编辑字段,新发现的来源 SKU 会为每个已有平台配置创建 `not_listed` mapping,来源未返回的 SKU 不自动删除或恢复。来源差异的人工审查 UI 另由商品编辑模块提供,采集接口不得通过删除 SKU 或级联删除映射来“覆盖”草稿。
|
||||
|
||||
1688 结构化采集以 `skuModel.skuInfoMap` 的真实可售记录生成 SKU;每条记录的 `price`(CNY)按两位小数四舍五入后写入对应 SKU 的 `purchase_cost_cny`,`skuProps.value` 中按规格名称匹配的图片作为带 `variantSourceKey` 的 `source_sku` 候选。尚无平台编辑草稿时,重复采集会刷新来源采购价;进入编辑器后不覆盖用户修改过的采购价。SKU 对应的来源图片可在编辑页预览,用户选择后才转存并保存为正式主图。
|
||||
|
||||
成功返回 `201`(新建)或 `200`(复用):
|
||||
|
||||
```json
|
||||
|
||||
@@ -93,6 +93,8 @@ Headers:`Idempotency-Key` 必填。Body 可省略,或为:
|
||||
|
||||
Worker 只在完成所有分页和详情批次后把 run 标记 `succeeded`。部分请求失败时 run 为 `failed`,已成功 upsert 的记录仍保留,但不执行“未见记录归档”步骤,避免将网络错误放大为商品消失。
|
||||
|
||||
归档规则(2026-09-26 确认):首次成功全量同步未见某 SKU,仅记录 `missing_since`;第二次成功全量同步仍未见,或 `missing_since` 已超过 7 天,写入 `archived_at`。Worker 定时处理超过 7 天的记录,活跃全量同步期间暂缓归档。失败、部分同步或取消本身不改变这两个字段;再次出现时清空并恢复展示。列表默认排除已归档商品。
|
||||
|
||||
## 5. 明确不在首期接口中的操作
|
||||
|
||||
- 从在线商品编辑 Ozon 商品、重新发布或更新已导入 SKU;
|
||||
|
||||
@@ -86,6 +86,18 @@ Headers:`Idempotency-Key` 必填,页头平台由 header 指定,body 为空
|
||||
|
||||
## 2. 原子保存草稿与 SKU 规则
|
||||
|
||||
### 单张 AI 图片编辑(SKU 选图弹窗)
|
||||
|
||||
商品编辑页固定任务入口使用 `GET /api/products/{product_id}/image-tasks?limit=20&cursor=...`。`limit` 默认 20、最大 100,按进行中优先、创建时间倒序、ID 倒序稳定分页,返回 `{ data: ProductImageTask[], meta: { next_cursor, has_more } }`。接口只返回当前工作空间、当前商品的图片 AI 任务;首期包含单张编辑,后续套图任务按同一结构加入。每项包含 `kind: single_ai_edit | ai_suite`、`status`、`phase`、已完成数/总数、创建/完成时间、稳定错误码、`failure_source: pcore | atlas | null`、`failure_stage: task_setup | input_preparation | provider_submission | provider_polling | result_download | result_processing | result_storage | null`、`failure_detail: string | null`、`provider_error_raw: string | null` 与结果素材 ID 数组。失败来源表示 Pcore 接口返回/调用失败或 Atlas 自身处理失败;步骤指出实际出错的位置。`failure_detail` 是最长 500 字符的脱敏诊断摘要,不包含密钥、对象键或预签名 URL。Pcore 失败时 `provider_error_raw` 保留供应商原始错误响应文本(JSON 响应保存错误对象,最多 32,768 字符),便于在当前工作空间的任务列表中查看;没有供应商响应时为 `null`。历史任务未记录的字段返回 `null`,不得按通用错误码猜测失败来源。`GET /api/media-ai-edits/{task_id}` 的单张编辑响应也返回三个诊断字段,供未关闭的编辑弹窗显示。不返回供应商任务 ID、对象键或预览 URL。任务入口每 3 秒刷新运行中的任务,其余时间低频刷新;任务提交后即时刷新。查看结果时再用素材访问接口签发短时预览 URL。单张编辑任务取消沿用 `POST /api/media-ai-edits/{task_id}/cancel`。
|
||||
|
||||
`POST /api/media-assets/{asset_id}/ai-edits`:必须带 `Idempotency-Key`,请求体带当前工作空间 `product_id`,图片字段只使用正式素材 ID,不接受图片 URL。`asset_id` 为固定主图;`reference_asset_ids` 最多两项,仅作辅助参考。请求支持 `prompt`、`mode: edit | outpaint`、`ratio: 3:4 | 1:1 | 4:5`、图中文字翻译与目标语言、背景模式与描述、五种可改写的视觉风格、商品长宽高及尺寸标注图。`outpaint` 只允许 3:4、单主图,不生成尺寸标注。成功返回 HTTP 202、任务 ID 和 `queued` 状态。
|
||||
|
||||
`GET /api/media-ai-edits/{task_id}` 查询 `queued | running | succeeded | failed | cancelled`,成功时才返回独立 `output_asset` 的正式素材 ID、尺寸与短时预览地址;失败仅返回稳定错误码。`GET /api/media-ai-edits?product_id={product_id}` 返回当前商品最近 100 条成功任务,供右侧「AI 生图记录」复用素材。`POST /api/media-ai-edits/{task_id}/cancel` 需带 `Idempotency-Key`,将未完成任务标记为取消;已完成任务保持原结果。任务、operation、Outbox 在同一工作空间事务提交;Worker 持久化供应商任务 ID 后通过延迟 Outbox 继续轮询。供应商密钥、对象存储键和供应商临时图片地址不进入 API 响应或 Outbox。
|
||||
|
||||
供应商异步任务返回终态失败时不再轮询或重试同一任务 ID。只有供应商明确返回内容政策或审核错误码时才使用稳定错误码 `AI_IMAGE_CONTENT_REJECTED`;笼统的 `failed`(即使消息称“可能”涉及安全政策)及其他供应商终态失败使用 `AI_IMAGE_PROVIDER_FAILED`;提交、网络、存储等非终态问题在重试耗尽后使用 `AI_IMAGE_GENERATION_FAILED`。Worker 在终态失败或重试耗尽时把失败来源、步骤和脱敏摘要写入同工作空间的 operation 结果;用户界面显示阶段和摘要,并在任务卡片展示已取得的 Pcore 原始错误内容。历史任务若原先未保存错误内容,则相关字段为 `null`。
|
||||
|
||||
生成结果先在单张 AI 编辑抽屉中预览。用户点击“添加到当前 SKU”后,新素材插入原图后方,原图保留;选图弹窗“确认”仅写入编辑页表单,页面“保存”后才持久化 SKU `media_asset_ids`。关闭或取消编辑不修改 SKU 草稿。图片源、参考图、结果均受工作空间隔离;任务输出与源图分别存储。
|
||||
|
||||
`PUT /api/products/{product_id}/editor-draft`
|
||||
|
||||
Headers:`If-Match: "{product_revision}:{profile_revision}"`、`Idempotency-Key` 必填。请求是整个编辑页的原子快照:
|
||||
@@ -123,11 +135,12 @@ Headers:`If-Match: "{product_revision}:{profile_revision}"`、`Idempotency-Key
|
||||
- `profile.platform_product_category_id` 必须是当前平台的活动类目;同平台门店共享类目、类型属性和字典缓存。服务端从平台类目记录取得 `platform_type_id`,客户端不能伪造类型 ID。过渡期仍接受 `store_product_category_id`,但只用于按 `description_category_id + type_id` 映射平台类目,不参与当前读取和校验。
|
||||
- 类目切换或平台 schema 移除属性时,原有不再适用的属性不会进入新的发布草稿;服务端将它们写入 `unmapped_attributes` 并在编辑快照中返回。用户删除 SKU 时,其 SKU 属性随 SKU 一起移除,不生成无主未映射属性。
|
||||
- `variants` 是当前完整未删除 SKU 集合。省略既有 SKU 表示软删除;无论当前 SPU 状态都允许新增、复制、删除。`copy_from_variant_id` 仅用于新行,复制通用 SKU 数据但不复制任何平台导入映射,生成的新 SKU 从 `not_listed` 开始。
|
||||
- `variants[].purchase_cost_cny` 是人民币采购价,编辑快照以两位小数字符串返回;草稿输入最多两位小数。来源采集写入时按两位小数四舍五入。
|
||||
- 删除已导入 SKU 只从 Atlas 草稿及当前平台可发布集合移除,**不删除、不下架、不修改** Ozon 商品或在线镜像;其他平台历史映射保留。删除后当前平台只剩已导入 SKU 时,SPU 汇总自然为“已上架”。
|
||||
- `null` 的 SKU 规格字段表示继承父商品;包装物流规格的 `status` 为 `missing`/`ambiguous` 时,不允许定价确认或首次上架,但仍允许保存草稿。发布前服务端必须对每个待发布 SKU 解析 `effective_package_spec`,确认长、宽、高、重量均存在且大于 0 后才可生成 Ozon item。实物规格不用于物流;是否向 SPU 或 SKU 展示由其对应的类目 schema 属性决定,尺寸图仍可使用已确认的有效实物规格。
|
||||
- `target_store_id` 只能是当前工作空间、当前平台的活动店铺。变更目标店铺只更新**尚未导入** listing 的将来发布目标;`imported` listing 永远保留其首次导入时的店铺快照。
|
||||
- 类目变化后不匹配的旧属性作为未映射草稿返回 warnings,不能自动进入发布 payload。属性由平台 schema 校验 `type`、必填、字典、多值/复杂属性和 `is_aspect`;客户端不能用任意 JSON 绕过。
|
||||
- `media_asset_ids` 是本 SKU 当前平台的最终选图顺序;最多 30 张。格式只允许 JPG/PNG/WebP,单文件最多 20 MB,边长超过 10,000 px 拒绝,短边小于 700 px 不得作为首图并给出警告。第一张是主图。已完成的 `product_image` 上传素材和网络导入素材可供同工作空间的 SKU 选择;采集图片仍须先转存,且来源变体须匹配。
|
||||
- `media_asset_ids` 是本 SKU 当前平台的最终选图顺序;最多 30 张。格式只允许 JPG/PNG/WebP,单文件最多 20 MB,边长超过 10,000 px 拒绝,短边小于 700 px 不得作为首图并给出警告。第一张是主图。已完成的 `product_image` 上传素材和网络导入素材可供同工作空间的 SKU 选择;当前商品成功的水印与 3:4 处理结果也可选择。采集图片仍须先转存,且来源变体须匹配。
|
||||
- `common.model` 是用户手填或主动 AI 填报的商品型号;采集时允许为空,但每次首次上架前必须非空。`offer_id` 是用户手填或主动 AI 填报的目标平台卖家货号;采集入箱时不填值,生成时不直接复用 `source_sku`。草稿可为空,但每个待首次上架 SKU 的 `offer_id` 必须非空且在同一店铺/平台唯一。AI 填报接口和回填规则见[方案](../product/ai-autofill-plan.md)。
|
||||
- `common.source_title` 在编辑页显示为“中文商品名”;`profile.title` 显示为“俄文发布标题”,页面保存时必填。为允许先保存采集草稿再使用 AI 填报,API 草稿契约仍接受空标题;发布就绪校验在 `profile.title` 为空时返回 `PUBLISH_TITLE_REQUIRED`。SKU 发布标题 `variants[].title` 为 `null` 时继承 `profile.title`,不回退到 `display_name`;现有 SKU `tags=[]`、`description=null` 保持继承语义。标题、标签、描述分别独立覆盖。中俄对照按 SPU/SKU 与字段随 `editor-draft` 原子保存;SKU 继承项直接引用 SPU 对照,手工俄文覆盖但无匹配中文时标为对照待更新。发布适配器使用 SKU 有效文案仍是后续工作。
|
||||
|
||||
@@ -251,17 +264,17 @@ Headers:`Idempotency-Key` 必填。Body:
|
||||
|
||||
媒体选择通常随第 2 节草稿一起保存。为支持图片弹窗的异步“添加水印”,提供:
|
||||
|
||||
`POST /api/product-variant-platform-listings/{variant_listing_id}/watermark-derivatives`
|
||||
`POST /api/media-assets/{asset_id}/watermark-derivatives`
|
||||
|
||||
Headers:`Idempotency-Key` 必填。Body:
|
||||
|
||||
```json
|
||||
{ "source_asset_id": "uuid", "watermark_template_id": "uuid" }
|
||||
{ "watermark_template_id": "uuid" }
|
||||
```
|
||||
|
||||
服务端验证 source asset 是该 SKU 当前已选图片、模板属于当前工作空间且活动;固化模板**当前版本**后创建 `media_derivatives` 和 Worker 任务,返回 `202` 及 operation。任务成功后返回独立 output asset;原图和其他 SKU 的选择均不改变。用户在图片弹窗确认后,将 output asset 写入下一次 `editor-draft.media_asset_ids` 来替换原图位置;可再次选择原图恢复。首期不在发布时自动添加水印。
|
||||
服务端验证源图片是当前工作空间已校验的 JPG/PNG/WebP 正式素材,模板属于同一工作空间且活动;固化模板**当前版本**后,在同一事务创建水印派生记录、operation 和 Outbox 事件,返回 `202` 及任务摘要。采集候选图先按需转存为正式素材。任务成功后返回独立 output asset;原图和其他 SKU 的选择均不改变。用户在图片弹窗确认后,将 output asset 写入下一次 `editor-draft.media_asset_ids` 来替换原图位置;同一弹窗内可撤销为原图。首期不在发布时自动添加水印。
|
||||
|
||||
`GET /api/media-derivatives/{derivative_id}` 返回任务状态、脱敏错误及成功时的输出素材短时预览;不能泄露 `object_key`。
|
||||
`GET /api/media-watermark-derivatives/{derivative_id}` 返回 `id`、`status`、`source_asset_id`、`watermark_template_id`、`watermark_template_version`、`output_asset` 和脱敏 `error_code`。成功时 `output_asset` 包含正式素材 ID、宽高、类型、大小及短时预览 URL;不能泄露 `object_key`。输出保留原图显示方向与宽高,合成水印后编码为 JPG;透明原图以白色合成。模板的文字大小、图片像素尺寸、不透明度、圆角和相对位置以固化版本为准。失败后原图留在弹窗中。
|
||||
|
||||
## 6. AI 填报任务与页面回填
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ Headers:`Idempotency-Key` 必填。
|
||||
|
||||
`object_key` 是服务端内部字段,不放在普通客户端响应。上传意图和完成状态均持久化在数据库,不能只存在于 Redis 或预签名 token 中;Worker 每 5 分钟将逾期未完成意图标记为 `expired`,并删除 `failed` / `expired` 意图的临时对象。删除成功才记录清理时间;失败会在下一轮重试。
|
||||
|
||||
### 1.3 临时预览 URL
|
||||
### 1.3 临时预览与下载 URL
|
||||
|
||||
`POST /api/media-assets/{asset_id}/access-urls`
|
||||
|
||||
@@ -77,7 +77,7 @@ Headers:`Idempotency-Key` 必填。
|
||||
{ "purpose": "preview" }
|
||||
```
|
||||
|
||||
返回 10 分钟有效的短时 `url` 与 `expires_at`。仅当前工作空间的素材可签发;前端在 URL 过期后重新请求,不能把 URL 写回业务表或长期缓存。
|
||||
`purpose` 可为 `preview` 或 `download`。下载时传 `{ "purpose": "download" }`,服务端在签名 GET 请求中指定 `Content-Disposition: attachment`,文件名为 `atlas-image-{asset_id}` 加素材类型对应扩展名,浏览器打开该短时地址时保存文件。两种用途都返回 10 分钟有效的 `url` 与 `expires_at`。仅当前工作空间的素材可签发;前端在 URL 过期后重新请求,不能把 URL 写回业务表或长期缓存。
|
||||
|
||||
`GET /api/media-assets/product-uploads` 返回当前工作空间最近 100 个已经完成校验的 `product_image` 素材。每项包含 `MediaAsset` 字段及 10 分钟有效的 `preview_url`、`preview_url_expires_at`,供编辑页“上传图片”候选区展示;该地址不得写入草稿。
|
||||
|
||||
@@ -87,6 +87,18 @@ Headers:`Idempotency-Key` 必填。
|
||||
|
||||
`GET /api/media-assets/product-imports` 返回当前工作空间最近 100 条已导入的网络图片,响应项同上。图片已生成正式素材 ID 后才可进入 SKU 草稿;网络来源地址和预览地址均不得写入 `media_asset_ids`。
|
||||
|
||||
### 1.5 商品图片一键 3:4
|
||||
|
||||
`POST /api/media-assets/{asset_id}/aspect-ratio-derivatives`,需 `Idempotency-Key`,请求 `{ "preset": "3:4", "fit": "contain", "product_id": "uuid" }`。`product_id` 在商品编辑器中传入,以便将结果归档到该商品;旧调用可省略。`asset_id` 必须是当前工作空间已校验的 JPG/PNG/WebP 正式素材。采集候选图先按需转存,再以正式素材 ID 请求。服务端在同一事务创建工作空间隔离的派生记录、用户可见 `operation` 和 Outbox 事件,返回 HTTP `202`:
|
||||
|
||||
```json
|
||||
{ "data": { "id": "uuid", "status": "queued", "source_asset_id": "uuid", "output_asset": null, "error_code": null } }
|
||||
```
|
||||
|
||||
`GET /api/media-derivatives/{derivative_id}` 返回相同结构,`status` 为 `queued/running/succeeded/failed`。成功时 `output_asset` 为独立正式素材,包含 `id`、宽高、类型、大小以及 10 分钟有效的 `preview_url` 和 `preview_url_expires_at`;失败时只返回脱敏 `error_code`。任务等比缩放原图;留白贴近图片的部分采用对应边缘像素,向外平滑过渡到该边缘窄带的平均色,避免细纹理被拉成贯穿留白的条纹。透明边缘先与白色合成。输出为 1200×1600 JPG,不裁切商品,原图不修改。相同幂等键重放同一任务,Worker 重试必须复用同一派生记录。
|
||||
|
||||
单张或批量操作都逐张创建任务。弹窗用成功的 output asset 替换当前已选位置;未选的来源图处理成功后加入已选区。失败的图保持原样。弹窗「确认」只把新素材 ID 写入当前编辑表单,页面「保存」才持久化 SKU 选图。短时预览 URL、存储路径和远程来源 URL 不写入草稿或 Outbox。
|
||||
|
||||
## 2. 可用字体
|
||||
|
||||
`GET /api/watermark-fonts`
|
||||
@@ -108,11 +120,16 @@ Headers:`Idempotency-Key` 必填。
|
||||
"id": "uuid",
|
||||
"name": "右下角品牌",
|
||||
"kind": "image",
|
||||
"is_default": false,
|
||||
"current_version": 3,
|
||||
"config": {
|
||||
"image_asset": { "id": "uuid", "preview_url": "https://short-lived", "preview_url_expires_at": "2026-09-02T08:15:00Z" },
|
||||
"opacity": "0.8000",
|
||||
"scale_ratio": "0.2500",
|
||||
"scale_ratio": "0.5556",
|
||||
"image_size_px": 80,
|
||||
"border_radius_px": 0,
|
||||
"position_x": 1,
|
||||
"position_y": 1,
|
||||
"position": "bottom_right"
|
||||
},
|
||||
"created_at": "2026-09-02T08:00:00Z",
|
||||
@@ -129,11 +146,13 @@ Headers:`Idempotency-Key` 必填。
|
||||
"font_code": "NotoSans",
|
||||
"font_size_px": 24,
|
||||
"opacity": "0.8000",
|
||||
"position_x": 1,
|
||||
"position_y": 1,
|
||||
"position": "bottom_right"
|
||||
}
|
||||
```
|
||||
|
||||
`position` 只能是 `top_left`、`top_center`、`top_right`、`middle_left`、`center`、`middle_right`、`bottom_left`、`bottom_center`、`bottom_right`。`opacity` 范围 `"0"`–`"1"`;图片 `scale_ratio` 范围 `"0.1"`–`"2"`;文字 `font_size_px` 范围 12–60。
|
||||
`position_x`、`position_y` 是 0–1 的数字,分别表示水印在水平、垂直**可移动范围**内的相对位置:0 贴左/上边缘,1 贴右/下边缘,中间值不吸附九宫格;坐标保存到小数点后四位。`position` 是兼容旧版客户端的九宫格近似值,不得用于精确渲染;其枚举值仍为 `top_left`、`top_center`、`top_right`、`middle_left`、`center`、`middle_right`、`bottom_left`、`bottom_center`、`bottom_right`。`opacity` 范围 `"0"`–`"1"`;图片 `image_size_px` 是在 240×320 基准预览框中等比缩放后的最长边像素数,范围 10–200,默认 80;`border_radius_px` 是该预览框中的圆角半径,范围 0–100,默认 0。`scale_ratio` 仅用于旧客户端兼容,范围 `"0.1"`–`"2"`,新客户端以 `image_size_px` 为准;10–14px 时兼容比例固定为最小值 `"0.1"`,实际渲染仍以像素尺寸为准。文字 `font_size_px` 范围 12–60,也以基准预览框为单位。实际渲染时,Worker 用 `max(源图显示宽度/240, 源图显示高度/320)` 同比例放大图片大小、文字大小、圆角和 5px 边距;水印超出源图时再等比缩小到可容纳范围。这样商品图缩小到预览尺度后,水印大小与底边距接近模板预览。
|
||||
|
||||
### 3.1 查询
|
||||
|
||||
@@ -145,6 +164,10 @@ Headers:`Idempotency-Key` 必填。
|
||||
|
||||
返回模板当前版本,供编辑弹窗和“查看效果”使用。固定演示底图由前端内置,前端按 `config` 实时渲染预览,不在每次滑动 Slider 时创建服务端图片。
|
||||
|
||||
`GET /api/watermark-templates/default`
|
||||
|
||||
返回 `{ "data": 模板资源 }`;当前工作空间未设置默认模板时返回 `{ "data": null }`。列表和详情中的 `is_default` 表示当前工作空间的唯一默认水印。打开「SKU 图片选择」弹窗时客户端静默读取一次默认模板;点击单张或批量「添加水印」时,有默认模板便直接创建派生任务,没有默认模板才打开三列模板选择弹窗。查询尚未完成时等待结果再决定,查询失败时允许用户从选择弹窗手动选择。设置默认不会自动修改已有图片、店铺推荐水印或已生成的派生图。
|
||||
|
||||
### 3.2 创建
|
||||
|
||||
`POST /api/watermark-templates`
|
||||
@@ -162,7 +185,8 @@ Headers:`Idempotency-Key` 必填。
|
||||
"font_code": "NotoSans",
|
||||
"font_size_px": 24,
|
||||
"opacity": "0.8",
|
||||
"position": "bottom_right"
|
||||
"position_x": 0.73,
|
||||
"position_y": 0.82
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -175,20 +199,22 @@ Headers:`Idempotency-Key` 必填。
|
||||
"kind": "image",
|
||||
"config": {
|
||||
"image_asset_id": "uuid",
|
||||
"scale_ratio": "0.25",
|
||||
"image_size_px": 80,
|
||||
"border_radius_px": 12,
|
||||
"opacity": "0.8",
|
||||
"position": "bottom_right"
|
||||
"position_x": 0.73,
|
||||
"position_y": 0.82
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
模板名称在当前工作空间内唯一;图片资产必须属于当前工作空间且已完成校验。成功返回 `201 Created` 与模板资源。
|
||||
创建时须同时提交 `position_x` 和 `position_y`;旧版客户端可继续只提交 `position`,服务端会换算成 0、0.5 或 1 的坐标。若两种格式都提交,以精确坐标为准。图片水印须提交 `image_size_px`;旧版客户端可继续提交 `scale_ratio`,服务端会换算为像素尺寸。若两者都提交,以像素尺寸为准;未提交 `border_radius_px` 时取 0。模板名称在当前工作空间内唯一;图片资产必须属于当前工作空间且已完成校验。成功返回 `201 Created` 与模板资源。
|
||||
|
||||
### 3.3 编辑与删除
|
||||
|
||||
`PATCH /api/watermark-templates/{template_id}`
|
||||
|
||||
Headers:`If-Match` 与 `Idempotency-Key` 必填。请求体与创建相同,但可只提交待改字段;若切换 `kind`,须提交新类型完整 `config`,服务端不保留旧类型专属字段。
|
||||
Headers:`If-Match` 与 `Idempotency-Key` 必填。请求体与创建相同,但可只提交待改字段;坐标可单独修改一个轴,另一轴沿用当前值。旧版客户端只提交 `position` 时,两个坐标按九宫格同步换算。图片尺寸和圆角也可独立修改;仅提交旧字段 `scale_ratio` 时重新换算像素尺寸。若切换 `kind`,须提交新类型完整 `config`,服务端不保留旧类型专属字段。
|
||||
|
||||
每次影响渲染的更新都会创建新的 `watermark_template_version`,并增加模板 `current_version`。旧版本不会被覆盖,供已生成派生图追溯;模板改名只更新模板名称,不需要创建渲染版本。
|
||||
|
||||
@@ -196,6 +222,14 @@ Headers:`If-Match` 与 `Idempotency-Key` 必填。请求体与创建相同,
|
||||
|
||||
Headers:`Idempotency-Key` 必填。服务端在同一事务软删除模板并解除所有当前店铺绑定,返回 `204 No Content`。不删除原始图片资产,也不影响已生成水印派生图和历史发布快照。
|
||||
|
||||
`PUT /api/watermark-templates/{template_id}/default`
|
||||
|
||||
Headers:`Idempotency-Key` 必填;请求体为 `{}`。将当前工作空间的活动模板设为唯一默认模板,原默认模板同时取消默认状态,返回 `200 OK` 与更新后的模板资源。重复设置同一模板成功且不会创建新的渲染版本。模板不存在或不属于当前工作空间时返回 `404 RESOURCE_NOT_FOUND`。删除默认模板后,工作空间不再有默认模板。
|
||||
|
||||
## 4. 与商品编辑的边界
|
||||
|
||||
本文件只定义水印模板和通用素材。商品编辑的“图片悬浮 → 编辑 → 添加水印”将在商品接口中定义:它选择这里的活动模板、创建持久化派生任务、固化模板版本,并将生成的独立素材替换当前 SKU 已选图片位置;不会在上架时临时加水印。
|
||||
商品编辑的“图片悬浮 → 编辑 → 添加水印”使用 `POST /api/media-assets/{asset_id}/watermark-derivatives` 创建异步派生任务,需 `Idempotency-Key`,请求体为 `{ "watermark_template_id": "uuid", "product_id": "uuid" }`。`product_id` 在商品编辑器中传入,旧调用可省略。仅接受当前工作空间内已校验、最大 20 MiB、最大边长 10,000px 的 JPG/PNG/WebP 正式素材和活动模板。创建时固定模板当前版本,在同一事务写入派生任务、operation 和 Outbox,返回 HTTP `202`;`GET /api/media-watermark-derivatives/{derivative_id}` 查询进度。响应包含 `id`、`status`、`source_asset_id`、`watermark_template_id`、`watermark_template_version`、`output_asset` 和 `error_code`。成功时结果为保留源图显示方向及尺寸的独立 JPG 素材,透明源图用白底合成,返回短时预览地址;失败只返回稳定错误码。
|
||||
|
||||
单张和批量处理逐张创建任务。成功结果在图片弹窗中替换对应位置;来源候选图成功后加入已选区,失败图保持原样。弹窗可撤销本次水印替换;确认后才写入当前编辑表单,页面保存后持久化 SKU 选图。上架任务不会临时加水印。
|
||||
|
||||
`GET /api/products/{product_id}/image-derivatives` 返回当前工作空间内该商品最近 100 条成功的 3:4 与水印处理记录,按处理时间倒序;商品不存在返回 `404`。每条记录包含 `id`、`kind`(`aspect_ratio_3_4` / `watermark`)、`source_asset_id`、`created_at` 和带短时预览地址的 `output_asset`。编辑页选图弹窗的「图片处理记录」Tab 用它找回结果,选用后仍需确认选图并保存页面。未绑定商品的历史任务无法确定商品归属,不进入该列表;来源图与原素材不被覆盖。
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
├─ SKU 商品:卡片(默认)/ 紧凑列表
|
||||
│ └─ N 个 SKU;维护货号、条形码、图片、价格、变体属性、三项 SKU 文案及可选包装覆盖
|
||||
└─ 固定操作栏
|
||||
├─ 左:AI 填报 · AI 套图生成
|
||||
├─ 左:AI 填报 · AI 套图生成 · 图片任务
|
||||
└─ 右:取消并关闭 · 保存草稿 · 选择未上架 SKU 并首次上架
|
||||
```
|
||||
|
||||
@@ -59,11 +59,19 @@ SKU 名称只用于展示,不是发布标题;采集 SKU 用稳定 `source_va
|
||||
|
||||
AI 输入由两部分组成:一是用户在右侧“采集的商品信息”中整理并保存的来源标题、描述、品牌、价格、规格参数和来源类目;二是用户在左侧商品与 SKU 表单中保存的实物规格、包装规格和规格轴。右侧实际展示“最新规范化采集值 + 用户明确覆盖字段”的有效结果:没有编辑过的字段随复采更新,编辑过的字段保留用户值,并在来源变化时提供对比、逐项恢复和全部采用最新。原始采集证据不因编辑而改变。
|
||||
|
||||
点击任何 AI 动作前须先保存草稿,服务端再从当前 revision 组装输入;客户端不得把未保存的尺寸或自行解析的来源 JSON 直接提交给 AI。父商品规格与 SKU 有效规格均以后端读模型为准,SKU 的空覆盖字段按继承规则读取左侧父商品规格。
|
||||
商品文案、类目等 AI 填报动作前须先保存草稿,服务端再从当前 revision 组装输入;客户端不得把未保存的尺寸或自行解析的来源 JSON 直接提交给这类 AI 任务。图片「AI 编辑」是独立素材任务,只引用已物化的正式图片素材 ID,尺寸标注参数由用户在单张编辑抽屉中明确填写,不修改商品规格。父商品规格与 SKU 有效规格均以后端读模型为准,SKU 的空覆盖字段按继承规则读取左侧父商品规格。
|
||||
|
||||
SKU 图片选择弹窗左侧是该 SKU 的已选图片(排序/移除),右侧分组展示 AI 生图记录、采集主图、采集 SKU 图、采集详情图、网络图片和上传图片。商品级素材可被多个 SKU 选择;明确有稳定来源关联的 SKU 图只展示给对应 SKU。Ozon 首期每个 SKU 最多选择 30 张发布图片,第一张为主图,可拖动排序;平台适配器以自身限制驱动该上限。
|
||||
SKU 图片选择弹窗左侧是该 SKU 的已选图片(排序/移除),右侧依次展示 AI 生图记录、图片处理记录、采集图片、网络图片和上传图片;采集图片内按主图、SKU 图、详情图分组。商品级素材可被多个 SKU 选择;明确有稳定来源关联的 SKU 图只展示给对应 SKU。Ozon 首期每个 SKU 最多选择 30 张发布图片,第一张为主图,可拖动排序;平台适配器以自身限制驱动该上限。
|
||||
|
||||
已选图片悬浮时显示“编辑”菜单,至少包含“添加水印”。点击后在弹窗中选择一个工作空间水印模板,后台创建带水印的派生素材;原图和其他 SKU 的选择不被改写。用户确认后,以派生图替换该 SKU 当前图片位置,并可在同一弹窗撤销为原图。首期不在发布时自动加水印,也不因门店默认水印自动处理图片;后续再支持默认模板的预选、批量应用或自动应用。
|
||||
右侧「采集的商品信息」中的采集图片也提供「编辑」菜单,包含 AI 编辑、添加水印、一键 3:4 和下载。AI 编辑复用单张编辑抽屉,生成结果进入当前商品的 AI 生图记录;水印和 3:4 处理复用商品级派生任务,成功后在采集区显示处理图,重开页面时按该商品的处理记录恢复最新结果。原始采集证据与原素材保持不变;处理图可以在 SKU 图片选择弹窗的「图片处理记录」中重新选用。
|
||||
|
||||
单张图片菜单和左侧批量操作中的「一键 3:4」现使用异步素材派生任务:采集候选图先转存,Worker 对正式素材等比缩放,留白从对应边缘像素平滑过渡到该侧的平均底色,生成 1200×1600 JPG 新素材;原图保留。处理成功后在弹窗中替换对应已选位置,失败项保持原样。弹窗确认只回填当前表单,页面保存后才持久化选图。批量翻译仍待开发。
|
||||
|
||||
图片「编辑 → AI 编辑」打开标题为「AI编辑」的单张编辑抽屉,主图固定,可选最多两张辅助图。用户可设置编辑要求、图中文字翻译、背景、五种视觉风格、尺寸标注和画面比例;抽屉不展示生成方式,提交时固定使用 `edit` 模式。Worker 调用 Pcore `gpt-image-2` 异步接口;普通编辑参照旧项目以 JSON `images[].image_url` 发送原始图片的 data URI,仅扩图发送预处理后的 PNG 画布和蒙版 data URI。生成图独立保存。提交和生图期间都可关闭抽屉,任务在后台继续,可从底部操作栏的图片任务入口查看;失败任务同时展示通用提示和已取得的 Pcore 原始错误内容。用户预览后点击「添加到当前 SKU」,结果插在原图后方;已完成结果也保留在当前商品的「AI 生图记录」,可在重开弹窗后选择。选图弹窗确认和页面保存仍分别控制表单回填与持久化。
|
||||
|
||||
商品编辑页底部固定操作栏在「AI 套图生成」后展示「图片任务」入口;有运行中任务时显示「任务处理中」和数量。展开后按进行中和最近任务显示当前商品的图片 AI 任务、状态、完成数、失败信息和结果预览;单张 AI 编辑可在此取消。提交后立即刷新,进行中每 3 秒刷新,其余时间低频刷新。当前接入单张编辑;后续 AI 套图沿用商品图片任务结构并增加任务来源,入口无需重新设计。
|
||||
|
||||
打开「SKU 图片选择」时静默读取当前工作空间默认水印。点击单张或批量「添加水印」时,有默认模板便直接生成带水印的派生素材;没有默认模板或读取失败才打开每行最多三张卡片的选模板弹窗,水印管理在新标签页打开。原图和其他 SKU 的选择不被改写;生成结果替换当前图片位置,并可在同一弹窗撤销。弹窗确认只更新编辑表单,页面保存后才持久化选图;发布时不会自动加水印。
|
||||
|
||||
首期素材规则:发布图片仅接受 JPG、PNG、WebP;单文件最大 20 MB,最短边低于 700 px 给出警告且不得作为主图,超过 10,000 px 的边长在上传时拒绝;建议 1:1 或 3:4,允许其他比例但在预览中提示裁切风险。采集候选素材可保留原始文件供编辑选择,实际发布时始终按目标平台的图片数、格式和可访问性校验。Ozon 发布图片必须是可由 Ozon 拉取的 HTTPS 地址。
|
||||
|
||||
|
||||
+59
-3
@@ -1,6 +1,6 @@
|
||||
# Atlas Seller Kit 交接说明
|
||||
|
||||
> 更新:2026-09-24。此文是新 AI 对话、架构讨论与开发工作的首读入口。开始开发前,必须先阅读并遵守 [`development-collaboration-contract.md`](./development-collaboration-contract.md) 和仓库 `AGENTS.md`。下方按日期记录的旧方案仅供追溯;当前状态以本节及最新的 1.40 节为准。
|
||||
> 更新:2026-09-27。此文是新 AI 对话、架构讨论与开发工作的首读入口。开始开发前,必须先阅读并遵守 [`development-collaboration-contract.md`](./development-collaboration-contract.md) 和仓库 `AGENTS.md`。下方按日期记录的旧方案仅供追溯;当前状态以本节及最新的 1.47 节为准。
|
||||
|
||||
## 1. 项目定位
|
||||
|
||||
@@ -14,7 +14,7 @@ pnpm monorepo 包含 Web、NestJS API、BullMQ Worker、WXT 浏览器扩展、
|
||||
|
||||
已完成“采集 → 采集箱 → 商品编辑草稿”的主要数据闭环、平台级类目/属性/字典目录与发布预检。编辑页已接入异步「AI 填报」:基于来源资料与 Atlas 类目树生成类目建议、型号/SKU 货号、证据充分的包装建议及 SPU 中俄文案;单 SKU 文案由用户单独生成并确认应用。AI 结果只回填未保存表单,保存草稿仍是持久化边界。Ozon 动态类目属性可按已选类目加载并手工填写,**当前不由 AI 自动填报**。SKU 图片选择现支持采集候选图、工作空间上传图和网络导入图;在弹窗确认后回填草稿,页面保存后持久化。
|
||||
|
||||
尚未完成可直接发布的闭环:定价确认、真正的 Ozon 发布 job/import 及结果轮询、在线商品同步仍待开发。AI 类目推荐和文案已能运行,但不能等同于跨来源样本验收;尤其应继续用 1688/淘宝/天猫样本核验 Atlas 类目候选质量,以及俄文文案、包装证据和 SKU 继承行为。AI 生图仍是占位入口;图片「编辑」菜单中的 AI 编辑、水印、一键 3:4 等处理动作本轮未接入。
|
||||
尚未完成可直接发布的闭环:定价确认、真正的 Ozon 发布 job/import 及结果轮询、在线商品同步仍待开发。AI 类目推荐和文案已能运行,但不能等同于跨来源样本验收;尤其应继续用 1688/淘宝/天猫样本核验 Atlas 类目候选质量,以及俄文文案、包装证据和 SKU 继承行为。AI 套图生图仍是占位入口;图片「编辑」菜单中的一键 3:4、添加水印和单张 AI 编辑已接入异步素材任务。
|
||||
|
||||
当前优先事项:用真实来源样本回归 AI 类目推荐、文案与图片选择,补做真实图片上传/网络导入联调;完成定价确认;让首次发布 job 复用既有发布预检,再实现 Ozon import 与结果轮询。平台参考目录目前由平台级参考源和同步任务维护,不能把 9 月 10 日的门店级缓存描述当作现行架构。
|
||||
|
||||
@@ -458,7 +458,63 @@ BullMQ Worker(最多 5 次,5 秒起指数退避)
|
||||
**验证与后续范围**
|
||||
|
||||
- 本地 `031`、`032` 迁移已执行。contracts、database、API、Web TypeScript 检查及 API/Web 生产构建通过;API 媒体单元测试共 6 项、商品编辑集成测试共 11 项通过。集成测试覆盖 30 张选图保存、已上传和网络导入素材的草稿引用、非法内网网络图片链接拒绝。
|
||||
- 尚未用真实外部图片 URL、浏览器直传 MinIO 和完整编辑页操作做端到端回归;上线前需联调短时预览地址刷新、上传失败重试、跨 SKU 选图与重新打开弹窗。AI 生图和图片「编辑」菜单中的 AI 编辑、添加水印、一键 3:4、批量翻译由后续迭代接入;当前菜单仅提供入口提示,设为封图、下载和移出已选可用。
|
||||
- 尚未用真实外部图片 URL、浏览器直传 MinIO 和完整编辑页操作做端到端回归;上线前需联调短时预览地址刷新、上传失败重试、跨 SKU 选图与重新打开弹窗。AI 套图生图和批量翻译由后续迭代接入;单张 AI 编辑、一键 3:4、添加水印、设为封图、下载和移出已选可用。下载对当前工作空间素材签发带 `Content-Disposition: attachment` 的短时地址,采集候选图先按需转存,避免跨域预览链接只打开图片。
|
||||
|
||||
### 1.41 开发进度(2026-09-25):SKU 图片一键 3:4
|
||||
|
||||
- 图片弹窗的单张菜单和左侧批量操作已接入一键 3:4。采集候选图先按需转存,再以正式素材 ID 创建异步派生任务;Worker 等比缩放,留白从对应边缘像素平滑过渡到该侧窄带的平均底色,避免出现贯穿留白的条纹,生成独立的 1200×1600 JPG,保留原图。成功项替换弹窗中的图片,失败项不变;确认写入当前表单,页面保存后持久化。
|
||||
- API、共享类型、Worker 与 `033_media_aspect_ratio_derivatives.sql` 已同步;任务、operation 和 Outbox 在同一事务创建,任务表受工作空间 RLS 约束。结果查询只签发短时预览 URL。新增图像处理库 sharp,项目包管理器统一为 pnpm 11.25.0。
|
||||
- `033` 已在当前本地 `atlas` 数据库应用。API/Worker 受限角色可读写新表;图像转换、任务执行与媒体 API 单元测试已通过。临时账号和图片的 API → MinIO → Outbox → Worker → 结果查询实测返回独立的 1200×1600 JPEG,测试记录与对象已清理。仍需在真实编辑页点击单张和批量入口,回归弹窗状态与保存后的重读。
|
||||
|
||||
### 1.42 开发进度(2026-09-26):商品图片主动应用水印
|
||||
|
||||
- “添加水印”打开标题为「选择水印」的三列模板弹窗,左侧「水印管理」在新标签页打开。选择后对单张或批量图片逐张创建水印派生任务;成功项替换弹窗选图,失败项保留原图,当前弹窗支持撤销本次水印替换。确认只写入编辑表单,页面保存后才持久化。
|
||||
- `036_media_watermark_derivatives.sql` 保存源素材、锁定的模板版本及处理结果;API 创建任务时原子写入 operation 和 Outbox,Worker 读取不可变模板版本,以文字或图片水印生成独立 JPG 素材。结果查询只签发短时预览 URL。
|
||||
- 本地已应用 `036` 并核对受限应用角色可读写新表;contracts、API、Worker、Web 类型检查与 Web 生产构建通过,API 单元测试 26 项、图像 Worker 测试 13 项及新增的水印 API/数据库集成测试通过。尚需在真实商品编辑页回归选模板、批量处理、撤销与保存后重读。API 全量集成测试仍有一项既有发布预检优先级断言失败,与本轮水印路径无关。
|
||||
- 水印图片大小、文字字号、圆角和边距以管理页 240×320 预览框为基准,Worker 按源图显示尺寸同比例换算。此前直接把预览的 80px 水印贴到 1200×1600 等大图,缩小展示后明显偏小且过于贴底;已修正渲染计算,旧的派生图不会自动重生成,需要重新应用水印。
|
||||
- 打开「SKU 图片选择」时前端静默请求当前工作空间默认水印。单张和批量「添加水印」等待这次请求:有默认模板就直接执行已有派生处理,没有默认模板或请求失败才打开选模板弹窗。默认模板仅在用户主动点击后应用,不会因打开图片弹窗而修改草稿。
|
||||
|
||||
### 1.43 开发进度(2026-09-26):SKU 图片单张 AI 编辑
|
||||
|
||||
- 参考旧项目 `studio/src/pages/trial/AiImageGenModal.tsx`,图片「编辑 → AI 编辑」现打开单张抽屉:固定主图、最多两张辅助图、编辑要求、图片文字翻译、背景、五种风格及自定义提示词、尺寸标注、3:4/1:1/4:5 比例与仅扩图。Pcore `gpt-image-2` 任务由 Worker 异步提交、持久化供应商任务 ID,再经延迟 Outbox 轮询;仅扩图完成后覆盖回原图区域。生成结果独立保存为商品关联素材,用户点击「添加到当前 SKU」后插在原图后方;确认选图并保存页面后才持久化 SKU 顺序。右侧「AI 生图记录」可重新选择当前商品的最近 100 张成功结果。
|
||||
- API 契约见 `docs/api/product-editor-and-publishing.md`;`039_media_ai_edits.sql` 建立工作空间隔离任务表,`040_media_ai_edit_product_scope.sql` 关联商品。两项迁移已应用到当前本地 `atlas` 数据库,受限应用角色读取检查通过。contracts、API、Worker、Web 类型检查通过;Web 生产构建通过;API 定向测试 4 项与 Worker 定向测试 3 项通过(含仅扩图回填原图、供应商异步状态推进)。浏览器中以模拟素材挂载抽屉,验证了翻译开关、尺寸标注选项、仅扩图模式和窄视口布局;临时前端服务已停止。本次未向真实 Pcore 提交收费任务,也未登录真实商品编辑页做完整操作回归;联调时需验证 Pcore 结果地址、任务取消与页面重新打开后的图片选择。
|
||||
|
||||
### 1.44 开发进度(2026-09-26):商品图片任务入口
|
||||
|
||||
- 参考旧项目 `studio/src/pages/trial/TrialTaskCenter.tsx`,商品编辑页右下角增加固定「图片任务」入口和右侧任务抽屉。按进行中、最近任务展示当前商品任务,支持手动刷新、单张编辑取消和按需签发短时地址查看结果;单张编辑提交即刷新,运行中每 3 秒轮询。API `GET /api/products/{product_id}/image-tasks` 在工作空间事务内分页读取任务,首期聚合单张编辑;共享 `ProductImageTask` 已预留 `ai_suite` 类型。后续套图生成落地时需把套图表查询接入聚合服务,并补上套图任务的取消与结果操作。API 与 Web 类型检查、Web 生产构建、API 定向测试通过;尚未用真实登录商品页做端到端界面回归。
|
||||
- 单张 AI 编辑抽屉已移除「生成方式」选择,提交固定使用 `edit` 模式;抽屉标题改为「AI编辑」。服务端仍保留既有 `outpaint` 契约,供其他调用端或后续能力使用。
|
||||
- 商品编辑页底部操作栏已将原「AI 生图」入口更名为「AI 套图生成」,并把图片任务入口放在其后;进行中时显示任务数。套图按钮当前仍为待开发提示。
|
||||
|
||||
### 1.45 故障排查(2026-09-26):单张 AI 编辑任务失败
|
||||
|
||||
- 本地 4 条失败任务都已成功提交到 Pcore,供应商任务 ID 已持久化;Pcore 轮询返回 `status=failed` 和“请求无法用于生成图像,可能因安全政策被拦截,或不适合进行图像生成”。4 条任务使用同一张蜘蛛侠玩具主图,切换背景后仍遭相同拒绝;供应商未指明具体触发项,不能断定是图片、辅助图或提示词中的哪一项。`PCORE_API_KEY` 与 `PCORE_BASE_URL` 已在当前根 `.env` 配置,Worker 通过根 `.env` 读取并实际调用了 `gpt-image-2` 的 `/v1/images/edits`;本次排查只读查询已有供应商任务,没有提交新的付费生图。
|
||||
- Worker 现在识别 Pcore 的终态错误:内容策略/输入不适合时写 `AI_IMAGE_CONTENT_REJECTED`,其他终态写 `AI_IMAGE_PROVIDER_FAILED`,不再对同一终态任务重复尝试 5 次;前端显示对应中文提示。历史 4 条任务仍保留原通用错误码 `AI_IMAGE_GENERATION_FAILED`。Worker 单元测试 4 项、Worker/Web 类型检查和 Web 生产构建通过。排查时确认维护者的 API/Worker `tsx watch` 均在运行,Worker 子进程已随代码变更重新加载;尚未对其他图片发起实际生图验证。前端无法绕过 Pcore 内容判定。
|
||||
- 2026-09-27 复核时新增的第 5 条失败任务仍是同一张主图,但没有辅图、背景为 `auto`、编辑要求为空。Pcore 返回 `status=failed`、`error.type=image_task_error`、`error.code=failed`,消息仅称“可能因安全政策被拦截,或不适合进行图像生成”,没有审核阶段或类别;因此不能将原因确定归于主图、辅助图、提示词或生成结果。对照旧项目的 `/v1/images/edits`、`gpt-image-2`、异步轮询、`images[].image_url` 和 3:4 尺寸均一致;Atlas 的差异是发出前会压缩为 JPEG,旧项目发送原始图片字节。当前输入图本身已是 1170×1170、197 KB 的 JPEG,尚无证据表明转码导致拒绝。界面提示已改为不指定具体拦截阶段。没有提交新的付费诊断任务。
|
||||
|
||||
### 1.46 Pcore 图片编辑协议修正(2026-09-27)
|
||||
|
||||
- 根 `.env` 的 `PCORE_BASE_URL=https://pcore.ai` 没有隐藏空白;Worker 原本拼接为 `/v1/images/edits`,并能拿到供应商任务 ID,故少写 `/v1` 不是失败原因。现兼容根地址与文档的 `/v1` 地址,均规范化为同一接口路径;`.env.example` 推荐文档写法,现有根 `.env` 不必改动。
|
||||
- 用同一密钥做三项单张对照:合成花瓶图通过 JSON `images[].image_url` 提交后返回 `queued`,随后以笼统的 `image_task_error/failed` 终止;纯文生图通过 `/v1/images/generations` 成功;同一花瓶图改用 `multipart/form-data` 的 `image` 文件上传到 `/v1/images/edits` 后成功。因此笼统错误消息不能证明内容审核拒绝,此次故障定位为图片编辑请求格式与当前 Pcore 通道不兼容。
|
||||
- Worker 现在以 multipart 上传主图及各辅图,扩图时上传 PNG 图片和 `mask` 文件,保留原有异步任务 ID 与轮询。仅在供应商明确给出审核类错误码时标记 `AI_IMAGE_CONTENT_REJECTED`,笼统终态失败标记 `AI_IMAGE_PROVIDER_FAILED`。旧任务状态不回写;需重新发起生成来验证真实商品图。对照诊断提交了三条可能计费的供应商任务,其中两条成功、一条失败。
|
||||
|
||||
### 1.47 图片任务展示 Pcore 原始错误(2026-09-27)
|
||||
|
||||
- Pcore 图片编辑失败时,Worker 将供应商错误对象原文保存在对应 operation 的 `result.provider_error_raw`,稳定错误码及通用提示仍保留。商品图片任务列表在工作空间事务内联结 operation,响应增加 `provider_error_raw`;前端失败任务卡片直接展示该内容,其他任务为 `null`。供应商任务 ID、密钥及结果图片地址不随任务列表返回。历史失败任务此前未保存原始错误,需按已持久化的供应商任务 ID 补取;无法补取的记录继续显示通用提示。当前根 `.env` 指向的本地 `atlas` 数据库经只读核对为 0 个商品、0 条失败的 AI 编辑任务,因此本次无历史记录可补取。
|
||||
|
||||
### 1.48 单张 AI 编辑请求对齐旧项目(2026-09-27)
|
||||
|
||||
- 复核旧项目 SQLite 中最近两条成功的单张编辑任务:均使用 `gpt-image-2`、3:4、一张参考图,并经 `/v1/images/edits` 的 JSON `images[].image_url` 提交。两项目配置的 Pcore key 与 base URL 相同。旧项目也存在一次同端点的笼统失败,因此上一节用合成图得出的“JSON 格式与通道不兼容”不能推广到所有输入图。
|
||||
- 按维护者要求,Atlas Worker 的普通编辑改为 JSON 请求,`model/prompt/n/size/async/images` 结构与旧项目一致;图片以原始 JPG/PNG/WebP 字节生成 data URI,不再压缩、铺白或转码。仅扩图仍先构造 PNG 画布和蒙版,再用同一 JSON 协议发送 `images` 与 `mask.image_url`。异步轮询、原始错误记录与生成结果保存流程不变。Worker 定向测试 6 项、类型检查和构建通过;尚未以真实商品图重新向 Pcore 发起收费任务。
|
||||
|
||||
### 1.49 Pcore 已完成任务的结果解析修正(2026-09-27)
|
||||
|
||||
- Pcore 官方图片文档区分 `/v1/images/generations` 文生图和 `/v1/images/edits` 图生图;单张 AI 编辑传原图,应继续调用后者。文档的 JSON 图生图输入写为 URL 或 data URI 字符串或字符串数组;Atlas 当前的 `images[].image_url` 对象数组与旧项目成功任务一致,而且最新任务在 Pcore 返回 `completed`,故这次失败并非提交参数被拒绝。
|
||||
- 读取 Joey 工作空间内最近失败任务及 BullMQ 栈后确认:最近三条任务都取得供应商任务 ID,Pcore 返回 `data[0].url`,并同时给出空字符串 `b64_json`。Atlas 原先优先解码空 `b64_json`,产生空 Buffer,Sharp 抛出 `Input Buffer is empty`;BullMQ 重试五次后写通用失败。已完成任务的 Pcore 内容 URL 经只读 GET 返回 HTTP 200、`image/png`、1,580,645 字节。Worker 现仅使用非空的 base64 数据,否则回退到结果 URL。定向测试 7 项、Worker 类型检查和构建通过;未提交新的收费生图任务。此前失败记录仍为失败状态,未自动改写业务数据。
|
||||
|
||||
### 1.50 Pcore 结果下载 DNS 回调修正(2026-09-27)
|
||||
|
||||
- 前一节修复后再次提交的两条 Atlas 任务都已取得 Pcore 任务 ID,却在读取结果 URL 时以 `Invalid IP address: undefined` 失败。BullMQ 栈指向 `downloadProviderImage` 的自定义 DNS `lookup` 回调;Node 请求 `options.all=true` 时要求回调返回地址数组,旧实现仍返回单个地址,导致 TLS 连接前失败。旧项目使用 `httpx` 直接读取结果 URL,没有这一分支。
|
||||
- Worker 的 DNS 固定逻辑现按 `options.all` 返回地址数组或单个地址,公网地址校验与 TLS 域名校验保持不变。用已经完成的 Pcore 任务调用修复后的 Atlas 下载函数,只读取回有效 PNG(1,734,068 字节,1086×1448);没有发起新的收费生图。Worker 定向测试 8 项、类型检查与构建通过。历史失败记录仍未改写。
|
||||
|
||||
## 2. 已确认产品决策
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
| 水印名称 | 模板名称,在当前账户内唯一。 |
|
||||
| 水印类型 | `文字水印` 或 `图片水印`。 |
|
||||
| 水印内容 | 文字水印展示文字内容;图片水印展示缩略图/文件名,不显示原始存储路径。 |
|
||||
| 水印位置 | 九宫格位置,以清晰中文名展示,如“右下”。 |
|
||||
| 水印位置 | 显示水平、垂直相对位置;旧模板的九宫格位置会转换为相应坐标。 |
|
||||
| 操作 | `查看效果`、`编辑`、`删除`。 |
|
||||
|
||||
删除已被店铺绑定的模板时,必须二次确认并说明影响;确认删除后应解除所有店铺绑定,而不是让任务继续引用一个已删除的模板。已生成的历史图片不受影响。
|
||||
@@ -122,15 +122,15 @@
|
||||
| 模板名称 | 必填;当前账户内唯一。 |
|
||||
| 水印类型 | 必填,文字或图片。切换类型时需确认,因为原类型专属字段会被清空。 |
|
||||
| 不透明度 | 使用 Ant Design Slider;取值 0%–100%,预览同步更新。 |
|
||||
| 水印位置 | 九宫格单选:左上、上中、右上、左中、居中、右中、左下、下中、右下。 |
|
||||
| 预览效果 | 基于固定演示底图实时渲染位置、缩放和透明度;首期仅预览,不写入商品图。 |
|
||||
| 预览效果与水印位置 | 基于固定演示底图实时渲染位置、大小、圆角和透明度;在预览框内拖动水印可停在任意位置,距边缘最少 5px,也可用方向键微调。保存相对坐标,重新打开后保持原位置。商品编辑页主动应用时生成独立派生图。 |
|
||||
|
||||
图片水印专属字段:
|
||||
|
||||
| 字段 | 必填 | 规则 |
|
||||
|---|---:|---|
|
||||
| 上传图片 | 是 | 上传 PNG/JPG/WebP;透明底 PNG 是推荐格式。具体大小、像素与文件大小限制由媒体模块确定。 |
|
||||
| 图片缩放 | 是 | 使用 Ant Design Slider;首期建议取值 10%–200%,表示相对演示底图短边的比例。 |
|
||||
| 图片大小 | 是 | 使用 Ant Design Slider;在 240×320 预览框中的最长边为 10–200px,默认 80px;应用到商品图时按预览框与源图的比例换算。 |
|
||||
| 图片圆角 | 否 | 输入 0–100px,默认 0;同一个值控制四个圆角。 |
|
||||
|
||||
文字水印专属字段:
|
||||
|
||||
@@ -144,11 +144,11 @@
|
||||
|
||||
### 4.3 商品编辑时主动加水印规则
|
||||
|
||||
用户在商品编辑页的已选图片上悬浮,点击“编辑 → 添加水印”,在弹窗选择一个工作空间水印模板。确认后系统对这张图片生成一份带水印的派生图,并以派生图替换此 SKU 当前图片位置。规则如下:
|
||||
打开「SKU 图片选择」时静默读取当前工作空间默认水印。用户点击“编辑 → 添加水印”后,有默认模板就直接生成带水印的派生图;没有默认模板或读取失败才在弹窗中选择工作空间水印模板。生成后以派生图替换此 SKU 当前图片位置。规则如下:
|
||||
|
||||
- 商品级候选图片与每个 SKU 已选图片都可处理;最终仅提交用户明确选中的图片集合。
|
||||
- 原始图片不被改写;水印处理产物是独立、可追溯的派生素材,用户可在编辑弹窗恢复使用原图。
|
||||
- 派生任务固化水印模板版本、位置、缩放/字体和不透明度;模板后续编辑不影响已生成的派生图。
|
||||
- 派生任务固化水印模板版本、位置、图片大小与圆角/字体和不透明度;模板后续编辑不影响已生成的派生图。
|
||||
- 首期不在上架任务中自动加水印,也不允许发布时临时替换;后续另行支持绑定水印的默认预选、批量添加或自动添加。
|
||||
|
||||
## 5. 本轮待确认事项
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
## 6. 待补充
|
||||
|
||||
1. 采集箱草稿已绑定目标后,是否允许换平台/换店铺及其迁移规则;
|
||||
2. 在线商品列表的字段、筛选、详情、编辑入口和“认领外部商品”流程;
|
||||
2. 在线商品首期列表字段、筛选与只读详情已按 [`../api/online-listings.md`](../api/online-listings.md) 实现;编辑入口和“认领外部商品”流程仍待设计;
|
||||
3. 自动同步频率、手动同步冷却时间、单店并发和限流参数;
|
||||
4. 采集箱容量 1000 的最终套餐口径及超限提示;
|
||||
5. 采集箱“首次导入成功”的用户文案,以及在线商品“实际可见/库存”的用户文案;二者必须区分,不能把 `visible=true` 当作采集箱上架状态。
|
||||
|
||||
@@ -84,9 +84,9 @@ WHERE id = :id AND revision = :expected_revision;
|
||||
|
||||
### 5. 在线商品同步中的“未见”与归档
|
||||
|
||||
**状态:待确认。**
|
||||
**状态:已确认(2026-09-26)。** 维护者选择以下规则,在线商品全量同步按此执行。
|
||||
|
||||
建议规则如下,待产品确认后写入接口和同步 Worker:
|
||||
规则如下:
|
||||
|
||||
1. 一次**成功的全量同步**中未见某在线 SKU:仅首次写入 `missing_since`;不归档。
|
||||
2. 之后连续第二次成功全量同步仍未见,或 `missing_since` 已超过 7 天:写入 `archived_at`,列表默认隐藏但可筛选查看。
|
||||
|
||||
Reference in New Issue
Block a user