feat(ai-image): AI生图开发
This commit is contained in:
+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. 已确认产品决策
|
||||
|
||||
|
||||
Reference in New Issue
Block a user