Files
ozon-seller-kit/docs/extension/legacy-v2.md
T
2026-08-11 17:09:23 +08:00

428 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Seller Helper 方案设计 V2
> 面向 Ozon 跨境电商的 AI 选品搬运工具
> 文档状态:方案探讨阶段(未开始编码)
> 最后更新:2026-08-06
> V1 见 [`方案设计.md`](./方案设计.md),本文档为架构调整后的新版,V1 保留作为历史记录。
---
## 1. 背景与目标
在 Ozon 做跨境电商,货源来自 1688 / 淘宝 / 拼多多。当前痛点:
- 单个门店的商品图片、信息往往不完善,需要**跨多个网站抓取**补齐。
- **图片最麻烦**:图里的中文需要转成俄文,需要白底化,甚至需要 AI 美化重做。
- 信息要**一条条手动填进 Ozon 商品编辑页**,耗时。
- 部分商品带**视频**,视频里的中文也可能需要替换成俄文(三期)。
### 目标工作流
```
① 浏览 1688/淘宝/拼多多商品页
↓ 插件侧边栏点「收集」(可指定文件夹)
② 素材汇入同一「文件夹」(文本 + 图片,可来自多个页面多次收集)
↓ 打开发布管理系统
③ 选择文件夹 → 进入该文件夹的发布页
↓ 左侧素材 → 加入对话框 → 写要求 → 调大模型
④ 右侧结构化表单被逐字段填充(俄文标题/描述/标签/规格)
↓ 图片:白底、图内翻译(按钮式);AI 生图(对话式)
⑤ 挑选图片与头图、填价格 → 一键提交 Ozon 草稿
```
Ozon Seller API 文档:https://docs.ozon.ru/api/seller/zh/
---
## 2. 与 V1 的核心差异
| 维度 | V1 | V2 |
|---|---|---|
| 插件职责 | 抓取当前页 → POST 后端 | **纯采集器**:识别页面 + 归入文件夹 + 去重 |
| 采集单位 | 单次抓取 = 一个商品 | **文件夹**:多页面多次收集汇入同一文件夹 |
| 发布页宿主 | 独立 Web 预览页 | **后端托管的发布管理系统**,按文件夹进入 |
| 编辑交互 | 点选区域 → 弹对话框局部重生成 | **左素材 / 右表单 / 底对话框** 三栏工作台 |
| AI 输出形态 | 生成文本填入预览 | **结构化字段补丁**,逐字段接受/丢弃 + 版本历史 |
| 图片操作 | 统一走处理管线 | **确定性操作按钮化**AI 生图走对话 |
| 模型选择 | 固定 Claude | **多模型可配置**(文本/视觉/图像三类槽位) |
| Ozon 类目 | 上传前匹配 | **进入发布页即先定类目**,用于渲染规格表单 |
未变化的部分:Python 图片微服务、对象存储、异步任务队列、Ozon 类目属性字典校验层。
---
## 3. 整体架构
```
浏览器
├─ Chrome 扩展(瘦客户端,只做采集)
│ ├─ Content Script 识别商品页 → 提取 {标题, 参数, 卖点, 图片URL[], 价格, 详情图文}
│ ├─ Side Panel 当前文件夹 ▾ / 本页抓到什么 / 「收集」按钮 / 最近素材
│ └─ Service Worker 唯一出网口:带 token 调后端;图片取不到时兜底抓字节
│ │ HTTPS
└─ 发布管理系统(普通 Web 应用,新标签页打开)
├─ 文件夹列表页 进度状态 / 素材数 / 创建时间
└─ 发布页 左素材 · 右表单 · 底对话框
后端服务(Next.js
├─ /api/folder 文件夹 CRUD、列表
├─ /api/material 写入素材(接受 URL 或二进制)+ 排队预下载图片
├─ /api/draft 草稿字段读写、字段版本历史、补丁接受/丢弃
├─ /api/chat 对话 → 调用可配置 LLM → 返回字段补丁
├─ /api/image/op 白底 / 图内翻译 / 生图(异步任务,返回 jobId)
├─ /api/job/:id 任务状态与进度(轮询或 SSE)
├─ /api/ozon/category 类目推荐 + 属性字典拉取与缓存
├─ /api/ozon/publish 属性字典校验 → 图片上传 → 建草稿
├─ 任务队列
└─ 凭证保管(各模型 key、Ozon Client-Id / Api-Key,加密存储)
├─ Python 图片微服务 OCR / inpaint / 抠图白底 / 图生图编排
├─ 对象存储 原图 + 各衍生版本
└─ 数据库 文件夹、素材、草稿、任务、Ozon 字典缓存
Ozon Seller API
```
**设计原则**:插件不持有任何密钥、不直接访问 Ozon 与模型服务;所有算力与凭证集中在后端。
---
## 4. 插件端设计
### 4.1 职责边界
插件**只做四件事**:识别页面、提取素材、归入文件夹、去重。不做生成、不做图片处理、不碰 Ozon。
预计代码量很小(几百行),好处是迭代频率低、无需频繁重新发布扩展;重逻辑全在后端和 Web 端,正常部署即可更新。
### 4.2 侧边栏(Side Panel
用 Chrome Side PanelChrome 114+)而非 popup,浏览时可常驻不消失。
```
┌ Seller Helper ──────────────┐
│ 当前文件夹:儿童保温杯 ▾ [+新建] │
│ ─────────────────────────── │
│ 本页识别到: │
│ 标题 儿童316不锈钢保温杯… │
│ 参数 12 项 │
│ 卖点 3 段 │
│ 图片 9 张 [预览] │
│ ─────────────────────────── │
│ [ 全部收集 ] [ 选择性收集 ] │
│ ─────────────────────────── │
│ 该文件夹已收集:3 个来源 · 12 图 │
│ [ 打开发布页 ↗ ] │
└─────────────────────────────┘
```
**「当前文件夹」是载荷概念**:多页收集必须先明确归属,否则容易串。支持在侧边栏直接新建。
### 4.3 与后端通信
- **必须走 Service Worker 转发**。MV3 下 Content Script 发出的跨域请求受页面 CORS 约束;Service Worker 只要在 `host_permissions` 声明了后端域名即可直连。
- **鉴权**:自用阶段用后端签发的长期 token,插件 options 页填一次存入 `chrome.storage.local`。后续如需多用户再换 OAuth。
### 4.4 图片获取的两条路
| 路径 | 场景 | 说明 |
|---|---|---|
| 优先:只传 URL | 1688 主图 CDN`cbu01.alicdn.com`)等公开可取 | 后端直接下载,插件负担最小 |
| 兜底:传二进制 | 需要 referer / 登录态才能取的图 | 插件在页面上下文 `fetch` 成 blob 后上传 |
因此 `/api/material` 接口需**同时接受 URL 列表与二进制上传**两种输入。
### 4.5 去重
多个来源页大概率有重复图。两级去重:
1. **URL 归一化去重**(去掉尺寸后缀等 query 参数)——插件侧即可完成。
2. **感知哈希去重**pHash/dHash)——后端下载后计算,相似度超阈值的标记为疑似重复,发布页折叠展示。
### 4.6 预热
素材写入后端后**立即排队预下载图片**,并可选预跑一遍白底/OCR。用户还在浏览其他页面时后台就处理完了,进发布页时图片即时可用,不用干等。
---
## 5. 数据模型
```
Folder 文件夹
id, name, status(collecting|editing|published), ozonCategoryId, createdAt
└─ Material 素材
id, folderId, type(text|image), sourceUrl, sourcePlatform, capturedAt
── type=text : textKind(title|params|selling_point|desc|price), content
── type=image : originalUrl, storageKey, width, height, phash, dupOfId
└─ Variant 图片衍生版本
id, materialId, kind(original|whitebg|translated|aigen|upscaled)
storageKey, params(JSON), jobId, createdAt
└─ Draft 发布草稿(每个文件夹一份)
id, folderId, fields(JSON), selectedVariantIds[], heroVariantId
price, currency, ozonCategoryId, updatedAt
└─ FieldVersion 字段版本历史
id, draftId, field, value(JSON), source(ai|manual), messageId, createdAt
└─ Message 对话记录
id, draftId, role(user|assistant), content
attachedMaterialIds[], attachedVariantIds[]
modelUsed, resultPatch(JSON), patchStatus(pending|accepted|discarded)
└─ Job 异步任务
id, folderId, type(download|whitebg|translate|aigen|ozon_upload)
status(queued|running|done|failed), progress, input(JSON), output(JSON), error
```
要点:
- **一张图 = 一个 Material + 多个 Variant**。右侧挑图时是从所有 Variant 里挑,原图和白底图、翻译图、AI 图平级可选。
- **FieldVersion 独立成表**,支撑逐字段回退。
- **Message 记录 resultPatch 与其接受状态**,可追溯每个字段值是哪一轮对话产生的。
---
## 6. 发布页交互设计
### 6.1 布局
```
┌──────────────────────────────────────────────────────────────────────┐
│ 文件夹:儿童保温杯 · 3个来源 · 12张图 Ozon类目:保温杯 ▾ [发布] │
├────────────────────────────┬─────────────────────────────────────────┤
│ 左:收集的素材 │ 右:生成结果(= Ozon 字段结构化表单) │
│ ┌ 文本 ─────────────────┐ │ 标题(ru) v3 ⟲历史 │
│ │ ☑ 标题 · 1688 │ │ ────────────────────────────────── │
│ │ ☐ 参数表 · 1688 │ │ 简介/描述(ru) 待生成 │
│ │ ☐ 卖点 · 淘宝 │ │ ────────────────────────────────── │
│ │ ☐ 详情文案 · 拼多多 │ │ 关键词标签 v1 │
│ └───────────────────────┘ │ ────────────────────────────────── │
│ ┌ 图片 ─────────────────┐ │ 规格属性(按类目字典渲染) │
│ │ [□][□][□][□] │ │ 颜色▾ 材质▾ 容量▾ 尺寸 重量 … │
│ │ [□][□][□] … │ │ ────────────────────────────────── │
│ │ 选中 → [白底][翻译] │ │ 图片 [头图][2][3][4] 可拖拽排序 │
│ │ [加入对话] │ │ ────────────────────────────────── │
│ └───────────────────────┘ │ 价格 [____] ₽ │
├────────────────────────────┴─────────────────────────────────────────┤
│ @标题·1688 @参数表 @img_03 模型: Claude Sonnet 4.5 ▾ │
│ 整理成符合 Ozon SEO 的俄文标题和描述… [发送] │
└──────────────────────────────────────────────────────────────────────┘
```
左侧按「文本在上、图片在下」排列,均可多选并「加入对话」,在对话框上方以 chip 形式展示引用(类似 Cursor 的 `@` 上下文引用)。
### 6.2 右侧是结构化表单,不是聊天输出区
**这决定了接口契约**:LLM 不返回自由文本,而返回**字段补丁**。
```json
{
"patches": [
{ "field": "title_ru", "value": "Детский термос из стали 316...", "reason": "含核心关键词,58字符符合Ozon标题建议长度" },
{ "field": "tags", "value": ["термос детский", "поилка", "316 сталь"] },
{ "field": "attributes.color", "value": "Синий", "dictValueId": 61234 },
{ "field": "attributes.material", "value": "Сталь", "dictValueId": 58901 },
{ "field": "attributes.weight_g", "value": 320 }
],
"notes": "参数表里未给出杯口直径,规格中该必填项仍需补充"
}
```
右侧对涉及字段展示**新旧对比 + 逐字段「接受 / 丢弃」**。
> **为什么必须这样**:如果 AI 每次返回一整份内容整体覆盖右侧,用户手改过的标题会在下一轮对话被抹掉。补丁 + 逐字段接受是保护手工编辑的必要设计。
配套 **字段级版本历史**:每个字段保留若干版本(含 `source=ai|manual`),随时回退。
### 6.3 Ozon 类目先行
**进入发布页的第一步是确认类目**,因为右侧「规格属性」区的字段构成完全由类目字典决定——哪些必填、哪些是枚举、枚举有哪些合法值。
流程:
1. 后端根据文件夹内已收集的标题/参数,让 LLM 推荐 3–5 个候选 Ozon 类目。
2. 用户确认一个(可手动搜索改选)。
3. 拉取该类目的属性字典(`/v2/category/attribute`,结果缓存)。
4. 右侧按字典渲染表单:枚举项渲染为下拉、必填项标红。
5. 之后 LLM 生成规格时,**候选值被约束在字典内**(见 §7.3),而不是自由生成完再去匹配。
### 6.4 图片:两类操作分开
| 类型 | 操作 | 交互方式 | 原因 |
|---|---|---|---|
| 确定性管线 | 抠图白底、图内中文→俄文、放大、裁剪 | **选中图片 → 点按钮 → 出新 Variant** | 参数化即可,无需自然语言 |
| 开放式生成 | AI 生图 / 改图("换成户外草地背景") | **加入对话框 → 写要求 → 发送** | 需求无法枚举,必须自然语言 |
两类操作产出统一落为 Variant,右侧挑图时平级可选。处理中的 Variant 显示占位与进度(来自 Job)。
### 6.5 对话框
- 上方 chip 区展示已引用的文本素材与图片素材,可逐个移除。
- 右侧下拉可**临时切换本次调用的模型**。
- 发送后流式返回,先出 `notes` 说明,再出 patches 落到右侧待接受状态。
- 图片素材送入视觉模型前**先降采样**,控制 token 成本。
---
## 7. 各模块技术方案
### 7.1 采集(数据入口)
沿用 V1 决策:**浏览器插件**,借用户真人登录态与真实环境,最不易被封。MVP 只支持 1688。
官方 API(1688 开放平台等)对个人几乎不开放;Playwright 无头浏览器最易触发风控。插件方案同时天然契合"多网站补充信息"场景。
### 7.2 文案生成(俄文标题/描述/标签)
引用的中文素材 → LLM → 俄文字段补丁,并按 Ozon 习惯做本地化 SEO。
-**structured output / tool calling** 约束返回为补丁 JSON schema,不用自由文本再解析。
- 标题长度、关键词密度等 Ozon 规则写进 system prompt 与校验层双重保障。
### 7.3 规格属性映射(最容易翻车的一环)
难点:LLM 生成的颜色/材质/容量等值必须落到 Ozon 字典的合法枚举 id 上。
三步兜底:
1. **召回**:属性字典可能有上千个枚举值,先按关键词/向量召回 Top-N 候选塞进 prompt。
2. **约束选择**:让 LLM 从候选中选 `dictValueId`,而非自由生成字符串。
3. **人工兜底**:匹配不到或置信度低时,右侧该字段标记为"需人工选择",提供搜索下拉。
发布前做一次**必填项与字典合法性全量校验**,不通过则阻止提交并高亮问题字段。
### 7.4 图片处理
| 能力 | 方案 | 难度 |
|---|---|---|
| 抠图白底 | 抠图模型(如 RMBG / SAM 系)+ 合成白底 | 🟢 低 |
| 图内中文→俄文 · 路线A | OCR 定位(PaddleOCR)→ inpaint 抹除 → 按原版式重排俄文 | 🟡 中,版式还原需调试 |
| 图内中文→俄文 · 路线B | 多模态图像编辑模型直改 | 🟡 中,自然但版式可能偏移 |
| AI 生图 / 改图 | 图生图,对话驱动 | 🟡 中,需控成本 |
沿用 V1 决策:**A/B 两条路线都接**,各产出一个 Variant,发布页对比挑选。
### 7.5 Ozon 上传
走 Seller API 商品导入流程(`/v2/product/import`、图片上传、类目属性)。上传为草稿,用户再去 Ozon 后台正式发布。
顺序:图片先上传拿到 Ozon 侧 URL → 组装商品 JSON(含校验通过的属性)→ import → 轮询 import 任务状态 → 回写结果到 Draft。
### 7.6 视频(三期)
- 硬字幕:逐帧 OCR + 抹除 + 重排,效果不稳定。
- 配音:STT → 翻译 → TTS 重配,相对可控。
- 一期不做。
---
## 8. 多模型配置
模型不是一类,**至少三个槽位**,各自独立配置 provider / model / key
| 槽位 | 用途 | 候选 |
|---|---|---|
| 文本 LLM | 生成俄文文案、规格映射、类目推荐 | Claude / GPT / DeepSeek / Qwen 等 |
| 视觉 LLM | 读图理解、从图里补参数、辅助 OCR 校对 | Claude / GPT-4o / Qwen-VL 等 |
| 图像生成/编辑 | 生图、改图、白底、图内改字(路线B) | 按需可插拔 |
要求:
- 全局默认 + 发布页对话框内**临时切换**。
- 密钥加密存储在后端,插件与前端均不接触。
- 抽象一层统一调用接口,避免绑死单一 provider。技术上倾向 **Vercel AI SDK** 之类的多 provider 统一层。
> **关于 Pi SDKV1 §6 的待决策)**:V2 下编辑循环的输出被收敛为"结构化字段补丁",本质是 structured output + 工具调用,不是开放式 agent 任务;加上多模型可配置的需求,多 provider 统一层比 agent 框架更贴合。**结论:一期不引入 Pi**,用统一 SDK 自行实现对话循环;未来若确实需要 session 树 fork / 多方案分支,再评估引入。
---
## 9. 技术栈
```
Chrome 扩展 WXT(或 Plasmo+ React + TailwindCSSManifest V3 + Side Panel
后端 / Web Next.js(前后端一体,App Router
数据库 PostgreSQL + Prisma
对象存储 S3 兼容(本地开发用 MinIO)
任务队列 MVP 用数据库任务表 + worker 轮询;并发上来再换 BullMQ + Redis
图片微服务 PythonFastAPI):OCR / inpaint / 抠图 / 图生图编排
模型接入 统一多 provider SDK
进度推送 MVP 轮询 /api/job/:id;发布页体验优化时换 SSE
环境 Node 22 + Python 3.14(本机已就绪)
```
**队列选型说明**:一期刻意不上 Redis,用数据库任务表 + 单 worker 轮询即可满足单人使用的并发量,少一个部署组件。
---
## 10. 分阶段路线
### 一期 MVP
**主链路**:1688 多页收集到同一文件夹 → 发布页对话生成俄文文案 → 白底处理 → 挑图填价 → 推 Ozon 草稿。
落地顺序(每步可独立验证):
1. **脚手架**Next.js + Prisma + 数据模型建表 + MinIO 本地对象存储。
2. **插件采集**:WXT 脚手架 + 1688 页面识别 + 文件夹选择 + 收集到后端,打通原始数据。*(无需任何密钥即可验证)*
3. **文件夹列表页 + 发布页骨架**:左素材 / 右表单 / 底对话框三栏布局,素材可引用。
4. **对话生成文案**:对话 → LLM → 字段补丁 → 右侧逐字段接受 + 版本历史。
5. **Ozon 类目层**:类目推荐 → 拉属性字典 → 右侧规格表单按字典渲染 → 字典约束的规格映射。
6. **Ozon 提交**:图片上传 + 商品 import + 状态回写。**先把纯文案(原图直搬)商品推成功。**
7. **图片白底**:抠图管线 + Variant 机制 + 异步任务与进度。
### 二期
图内中文翻译双路线(A/B 对比)、AI 生图改图、多平台采集(淘宝/拼多多)、感知哈希去重、SSE 进度、类目属性智能映射优化。
### 三期
视频处理。
---
## 11. 关键风险与坑
| 风险 | 级别 | 应对 |
|---|---|---|
| 1688/淘宝/拼多多反爬 | 🔴 高 | 插件借真人登录态,已是最稳路线;仍需容忍页面改版导致选择器失效,做好降级提示 |
| Ozon 类目属性字典匹配 | 🔴 高 | 召回 + 约束选择 + 人工兜底三层;提交前全量校验 |
| 右侧手工编辑被 AI 覆盖 | 🟡 中 | 字段补丁 + 逐字段接受 + 版本历史(§6.2) |
| 图片 Variant 存储膨胀 | 🟡 中 | 定期清理未被选中的 Variant;原图按需保留 |
| 视觉模型调用成本 | 🟡 中 | 图片送模型前降采样;对话上下文限制引用图片数量 |
| 页面 DOM 提取不可信输入 | 🟡 中 | 采集内容视为不可信,进 LLM 前做清洗;后端不给模型任何文件/命令执行能力 |
| 图内翻译版式还原 | 🟡 中 | A/B 双路线并存,人工挑选 |
---
## 12. 已确认决策 / 待办
### 已确认
- 采集方式:**浏览器插件**,只做采集,先支持 1688。
- 采集单位:**文件夹**,多页面多次收集汇入同一文件夹。
- 发布页宿主:**后端托管的发布管理系统**(Web 应用),不打包进插件。
- 发布页布局:**左素材(文本上 / 图片下)· 右结构化表单 · 底对话框**。
- 右侧形态:**Ozon 字段结构化表单**,AI 返回字段补丁,逐字段接受,带版本历史。
- 图片操作:**确定性操作按钮化,AI 生图走对话**;结果统一为 Variant。
- 图内文字翻译:**A/B 两条路线都接**,发布页挑选。
- 模型:**多模型可配置**,文本 / 视觉 / 图像三类槽位,密钥仅存后端。
- 编辑循环:**不引入 Pi SDK**,用多 provider 统一 SDK 自行实现。
- Ozon 交互:**插件不直接访问 Ozon**,全部经后端。
### 待用户提供(不阻塞前 4 步)
- **Ozon Seller API 的 Client-Id / Api-Key**(沙箱或正式)——用于第 5–6 步。
- **模型 API Key**(文本 / 视觉 / 图像各一)——用于第 4 步及图片处理。
- **富文本描述模板**(哪怕草稿版)——用于描述字段的结构设计。
- **图像编辑模型偏好**(无偏好则做成可插拔,白底先用开源抠图模型跑通)。
### 待决策
- 文件夹与 SKU 的关系:一个文件夹固定产出一个商品,还是允许拆成多个变体商品(多颜色/多规格)?
- 素材是否需要跨文件夹复用(如通用尾图、品牌图)?
- 是否需要发布历史与"再次编辑已发布商品"的能力。