16 KiB
Ozon Seller Kit:俄文文案生成方案
状态:方案稿
日期:2026-08-07
后端语言:Python(FastAPI)
范围:先落地「中文采买信息 → 俄文标题 / 描述 / 标签 + 中文对照」;图片白底、Ozon 上传作为后续阶段预留扩展位。
1. 背景与目标
当前项目原为根目录散落的纯静态页面工具(ozonSeller.html + js/app.js),可直接 file:// 打开,已具备:
- 计价 / 录入 / 上品登记表 / 组合码导出
- 浏览器 Canvas 水印
后续需要接入大模型 API。浏览器直连 DeepSeek 会遇到 CORS,且 API Key 不能放前端,因此引入 本地 Python 服务 做代理与业务编排;仓库采用一体扁平结构,静态页放在 web/。
本阶段目标:
- 在现有页面增加「俄文文案」独立区块。
- 用户在单个输入框粘贴采买站商品信息(如有本次特殊要求可直接写在后面),点击生成。
- 后端调用 DeepSeek,返回俄文标题 / 描述 / 标签,并同步中文对照。
- 前端可编辑、一键复制;可选回填左侧「商品名」。
2. 总体架构
┌─────────────────────────────────────────────────────────────┐
│ 浏览器 │
│ web/ozonSeller.html + js/ + css/ │
│ http://127.0.0.1:8000/ozonSeller.html(由 FastAPI 托管) │
└───────────────────────────┬─────────────────────────────────┘
│ fetch JSON
▼
┌─────────────────────────────────────────────────────────────┐
│ 同仓 FastAPI(main.py) │
│ - 挂载 web/ 静态资源 │
│ - /api/ai/copy 文案生成 │
│ - (预留)/api/image/* /api/ozon/* │
└───────────────────────────┬─────────────────────────────────┘
│ HTTPS + Bearer Key
▼
┌─────────────────────────────────────────────────────────────┐
│ DeepSeek API(OpenAI 兼容) │
│ https://api.deepseek.com │
└─────────────────────────────────────────────────────────────┘
原则:
- 密钥只放
.env(不进 git);模型清单放server/config/models.yaml(可入库)。 - 前端只请求本机 API,不直连大模型、不接触密钥。
- 一体扁平结构:不拆
frontend//backend/;Python 入口在仓库根,静态资源独占web/。 - 现有静态能力尽量保留;服务端先做薄代理 + Prompt 编排。
- 本地开发统一用
http://127.0.0.1,不再依赖file://(file://无法稳定调后端)。
3. 页面落位(前端交互)
3.1 插入位置
在 计价双栏区域之后、上品登记表之前,新增全宽区块「俄文文案」。
页面顺序变为:
- Header(外链 + 汇率)
- 计价输入 + 计价结果
- 俄文文案(新)
- 上品登记表
- 上品组合码
- 图片水印
3.2 区块结构
| 区域 | 内容 |
|---|---|
| 左侧输入 | 商品资料(单个大文本,事实与本次要求写在一起)、带入当前商品名/型号(只读提示) |
| 右侧结果 | 标题 / 描述 / 标签:俄文主展示 + 中文对照;可编辑;各字段复制按钮 |
| 操作 | 「生成文案」「重新生成」;可选「中文标题填入商品名」 |
3.3 与现有字段关系
- 左侧
productName/ SKU / 型号:仍服务计价与登记,不改成俄文主编辑区。 - 文案结果独立保存于本区块 DOM / 内存;后续接 Ozon 上传时再读取俄文字段。
- 「填入商品名」仅把生成的 中文标题 写入
#productName。
4. 仓库目录与代码放置
采用 一体扁平结构(方案 B):不拆 frontend/ / backend/。Python 入口与配置在仓库根;静态页独占 web/,避免挂载时误暴露源码。
ozon-seller-kit/
├── docs/
│ └── ai-copy-backend-plan.md # 本方案
├── main.py # FastAPI 入口、CORS、挂载 web/
├── config/
│ ├── settings.py # .env 密钥与运行参数
│ └── models.yaml # 模型目录(可入库,不含密钥)
├── api/
│ ├── ai.py # /api/ai/*
│ ├── image.py # (预留)/api/image/*
│ └── ozon.py # (预留)/api/ozon/*
├── services/
│ ├── models_catalog.py # 读取 models.yaml、解析密钥
│ ├── deepseek.py # OpenAI 兼容 chat 调用
│ └── prompts/
│ └── copy_ru.py
├── schemas/
│ └── copy.py
├── web/
│ ├── ozonSeller.html
│ ├── css/
│ ├── imgs/
│ └── js/
│ ├── app.js
│ ├── ai-copy.js
│ ├── watermark-data.js
│ └── tailwind.config.js
├── requirements.txt
├── .env.example
├── start.command
├── .gitignore
└── README.md
4.1 放置约定
| 内容 | 放哪里 | 说明 |
|---|---|---|
| 页面结构 | web/ozonSeller.html |
文案区 DOM、模型下拉 |
| 文案交互 | web/js/ai-copy.js |
拉模型列表、带 model 调生成 |
| 模型目录 | server/config/models.yaml |
id/label/base_url/api_key_env;可入库 |
| 密钥 | 根目录 .env |
仅密钥与 HOST/PORT;不入库 |
| API 路由 | api/ |
按业务拆文件 |
| LLM 调用 | services/deepseek.py |
按 ModelSpec 调 OpenAI 兼容接口 |
| Prompt | services/prompts/ |
方便单独迭代文案质量 |
4.2 静态资源如何被访问
由 FastAPI 挂载 web/,一个进程同时提供页面和 API:
# main.py 示意
WEB_DIR = Path(__file__).resolve().parent / "web"
app.mount("/", StaticFiles(directory=WEB_DIR, html=True), name="web")
注意:静态挂载应放在 /api 路由注册之后,避免吞掉 API 路径。
访问地址:
- 页面:
http://127.0.0.1:8000/ozonSeller.html - API:
http://127.0.0.1:8000/api/ai/copy
前端请求基址:
const API_BASE = window.location.origin; // 同域,无 CORS 烦恼
若暂时用 VS Code Live Server 单独打开 web/、Python 另开端口,则需开 CORS,前端写死 API_BASE = 'http://127.0.0.1:8000'。首选同域挂载方案。
5. 后端设计
5.1 技术选型
| 项 | 选择 | 原因 |
|---|---|---|
| Web 框架 | FastAPI | 轻量、类型清晰、异步友好 |
| HTTP 客户端 | httpx |
调 OpenAI 兼容接口 |
| 密钥/运行参数 | pydantic-settings + .env |
只放秘密与端口 |
| 模型目录 | server/config/models.yaml |
可扩展多模型/多厂商 |
| 运行 | uvicorn |
标准 ASGI |
5.2 核心依赖
fastapi
uvicorn[standard]
httpx
pydantic-settings
python-dotenv
PyYAML
5.3 配置分层(模型目录 + 密钥)
原则:
server/config/models.yaml:模型清单(id、显示名、api_model、base_url、api_key_env),可入库,不含密钥。.env:只放密钥与 HOST/PORT 等运行参数,不入库。- 前端通过
GET /api/ai/models获取可选项,永不接触密钥。
server/config/models.yaml 示例:
default: deepseek-v4-flash
models:
- id: deepseek-v4-flash
label: Flash(快/省)
provider: deepseek
api_model: deepseek-v4-flash
base_url: https://api.deepseek.com
api_key_env: DEEPSEEK_API_KEY
- id: deepseek-v4-pro
label: Pro(质量更好)
provider: deepseek
api_model: deepseek-v4-pro
base_url: https://api.deepseek.com
api_key_env: DEEPSEEK_API_KEY
.env.example:
DEEPSEEK_API_KEY=sk-xxxx
# OPENAI_API_KEY=sk-xxxx # 若 models.yaml 引用了该变量再配置
HOST=127.0.0.1
PORT=8000
CORS_ORIGINS=
同一厂商可共用一把 Key;按「账号/厂商」分 Key,不必每个模型名硬拆一把。
5.4 API 约定
GET /api/ai/models
{
"default": "deepseek-v4-flash",
"models": [
{ "id": "deepseek-v4-flash", "label": "Flash(快/省)" },
{ "id": "deepseek-v4-pro", "label": "Pro(质量更好)" }
]
}
POST /api/ai/copy
请求:
{
"source_text": "从采买站粘贴的中文商品信息,可在末尾附带本次生成要求……",
"product_name": "可选,当前表单商品名",
"model_code": "可选,型号",
"model": "deepseek-v4-pro"
}
model可选;空则用models.yaml的default。- 不在白名单 →
400。
成功响应:
{
"titles_ru": ["……", "……"],
"titles_zh": ["……", "……"],
"description_ru": "……",
"description_zh": "……",
"tags_ru": ["……", "……"],
"tags_zh": ["……", "……"],
"model": "deepseek-v4-pro",
"usage": {
"prompt_tokens": 0,
"completion_tokens": 0
}
}
校验规则(后端):
source_text必填,去空白后长度 ≥ 10。model必须属于models.yaml(或空=默认)。- 要求模型输出 严格 JSON,解析失败则重试 1 次或返回 502。
5.5 Prompt 策略(概要)
System 角色职责:
- 面向俄罗斯消费者和 Ozon 搜索生成完整商品卡,而非把采买资料压缩成摘要。
- 优先级固定为:事实准确 > 俄语自然 > 信息完整与转化力 > 关键词覆盖。
- 标题一次输出 2 个互补方案(
titles_ru/titles_zh),以核心品类词开头,前 30 字符覆盖关键属性,长度 60~90 字符,去除年份、新款、爆款等噪声。 - 描述采用
Описание товара / Характеристики / Преимущества三段结构,原文明确提到配件时追加Комплектация;资料足够时约 900~1500 个俄文字符。 - 允许将已有事实改写成温和的使用利益点,但禁止补充原文没有的结构、认证、安全结论、适用年龄、开口位置、礼物节日等硬信息。
- 对常见行业词做翻译约束,例如“搪胶”优先译为
винил (ПВХ),不擅自译为天然橡胶каучук。 - 标签输出 10~15 个;每个俄文标签只允许一个单词,不带
#,中俄数组按索引一一对应。 - 中文标题和描述保持与最终俄文相同的事实与段落结构,便于逐项核对。
- 调用参数使用较稳定的
temperature=0.45,并给描述预留充足输出长度。
User 内容拼接:
<当前商品名>…</当前商品名>
<型号>…</型号>
<商品资料>
…
</商品资料>
输入用边界标签隔离,避免把采买文本中的内容误当作系统指令。实现放在
services/prompts/copy_ru.py,便于单独调优,不必改路由。
5.6 服务分层
api/ai.py
GET /models → models_catalog.list_model_options()
POST /copy → deepseek.generate_copy(req)
services/models_catalog.py
→ 读 models.yaml
→ 白名单校验
→ 按 api_key_env 从环境变量取密钥
services/deepseek.py
→ 组装 messages
→ 用 ModelSpec.base_url / api_model 调 /chat/completions
→ 解析 JSON → CopyResponse
6. 前端设计
6.1 DOM 落点
在 web/ozonSeller.html 中,计价 grid 结束后、上品登记表 mt-8 卡片前插入文案区。
模型下拉位于「生成文案」按钮上方;区块标题右侧提供折叠按钮。
| 元素 | id |
|---|---|
| 折叠按钮 / 内容区 | aiToggleBtn / aiCopyBody |
| 模型下拉 | aiModelSelect |
| 商品资料 | aiSourceText |
| 生成按钮 | aiGenerateBtn |
| 推荐标题容器 | aiTitlesContainer |
| 描述俄/中 | aiDescRu / aiDescZh |
| 标签容器 | aiTagsContainer |
| 状态提示 | aiCopyStatus |
结果区为只读展示:标题渲染成卡片(含复制俄文、填入商品名),描述用等高只读文本块保留换行,标签渲染成「俄文|中文」芯片,点击即复制俄文。需要调整文案时通过「生成要求」重新生成。
6.2 JS 职责拆分
web/js/ai-copy.js:
- 启动时
GET /api/ai/models填充下拉;localStorage记住上次选择 - 收集输入(含
#productName、#modelCode、选中的model) POST /api/ai/copy- 渲染标题卡片、描述文本块、标签芯片,并处理 loading / 错误态
- 复制(标题、描述、单个标签、全部标签)与「填入商品名」
- 折叠 / 展开整个文案区
web/js/app.js:保持计价、历史、水印。
6.3 交互细节
- 生成中:按钮 disabled +「生成中…」。
- 失败:在
aiCopyStatus显示可读错误。 - 不在前端存 API Key;模型列表不硬编码(以后加模型只改
models.yaml)。
7. 本地运行方式
7.1 一次性准备
在仓库根目录:
python3 -m venv .venv
source .venv/bin/activate
pip install -r server/requirements.txt
cp .env.example .env
# 编辑 .env,填入 DEEPSEEK_API_KEY
7.2 启动
source .venv/bin/activate
uvicorn main:app --app-dir server --reload --host 127.0.0.1 --port 8000
浏览器打开:
http://127.0.0.1:8000/ozonSeller.html
7.3 .gitignore 建议追加
.venv/
.env
**/__pycache__/
*.pyc
.DS_Store
web/ozonSeller.html.bak
8. 分阶段落地
Phase 1(本方案当前实施范围)
- 静态资源收拢到
web/ - 一体扁平:
main.py/api//services//schemas/ - 实现
POST /api/ai/copy - 页面插入「俄文文案」区块
web/js/ai-copy.js对接 API- FastAPI 挂载
web/,同域静态托管可本地跑通 - 根目录
README.md/start.command server/config/models.yaml模型目录 +GET /api/ai/models+ 前端下拉切换
Phase 2(图片)
POST /api/image/process:白底、服务端水印(可选保留前端水印)- 预留图生图代理接口
Phase 3(Ozon)
POST /api/ozon/products:读取文案区俄文字段 + 计价结果上传- Client-Id / Api-Key 仅存根目录
.env
9. 风险与约束
| 点 | 说明 |
|---|---|
不能用 file:// 调后端 |
需通过 http://127.0.0.1:8000 打开页面 |
| Prompt 质量 | 俄文 listing 需多轮样本调优;Prompt 独立文件便于改 |
| 模型偶发非 JSON | 后端要做解析容错与明确报错 |
| Key 泄露 | .env 不入库;勿把 Key 打进前端或日志 |
| 费用 | 前端防连点;可后续加简易速率限制 |
10. 结论
- 目录:一体扁平;Python 在仓库根,静态页在
web/。 - 模型配置:清单在
server/config/models.yaml,密钥在.env;前端只消费/api/ai/models。 - 服务:FastAPI(
main.py)挂载web/并提供/api/*。 - 前端:俄文文案区支持模型下拉;逻辑在
web/js/ai-copy.js。 - 扩展:
api/image.py、api/ozon.py预留;加模型只需改 yaml + 对应密钥环境变量。