Files
2026-09-27 22:41:33 +08:00

17 KiB
Raw Permalink Blame History

工作交接说明(HANDOFF)

更新:2026-08-31 读者:下一个接手工作的 AI / 开发者(工具无关)。先读本文再动手,避免重复探索。 配套文档:README(项目总览)、collect.md(采集)、trial-page.md(试算页)、multi-sku-pricing.md(多 SKU 试算与导出方案)、multi-sku-measurements.md(实物规格与包装物流规格的双口径设计)、image-suite.md(生图)、background-jobs.md(后台任务中心方案、实施状态与路线图)、image-asset-lifecycle.md(图片与水印存储规则)、api.md(契约)、backend-structure.md(后端结构)


1. 项目一句话

Ozon 跨境上品工具链。当前主链路(V2.1,已放弃 Ozon API 直传):

extensions/collector 扩展采集(Ozon/1688/淘宝/天猫)
  → 「上报商品」POST /api/materials 入库 + 自动打开试算页
  → studio /trial/{id} 试算页:计价 → 俄文文案 → AI 生图(套图+单张)→ 登记
  → 导出 CSV / 组合码 → 人工上 Ozon 卖家后台

技术栈:FastAPI(server,8800)+ React19/Vite/antd6(studio,8900)+ WXT Chrome 扩展(extensions/collector)。SQLite(data/app.db),无鉴权(V2.1 决策:先功能后鉴权)。

2. 启动与构建

# 一键启动(推荐):自动装依赖 → 构建采集插件 → 起插件改动监听 → 起 studio → 起 server
./start.command

# server 单独起(等价;日志建议重定向到 /tmp/osk-server.log)
.venv/bin/uvicorn main:app --app-dir server --reload --reload-include "*.yaml" --host 127.0.0.1 --port 8800

# 扩展改动后(start.command 的监听会自动构建,仍需去 chrome://extensions 手动点刷新)
pnpm -C extensions/collector build     # 产物 .output/chrome-mv3
  • start.command 新增:启动时会先执行 alembic upgrade head,再自动构建采集插件并起后台监听(3s 轮询 src/** + wxt.config.ts,改动自动重建;BSD find 语法,无新依赖)。Ctrl+C 会连同监听进程一起清理。
  • 后台任务 Worker:start.command 会额外启动 python server/worker.py。单独启动 server 时也要另开终端运行该命令,否则生图任务只会停在“排队中”。
  • 运行态提醒:交接时 server 是上个会话用 nohup 起的后台进程(日志 /tmp/osk-server.log),原 start.command 终端已被停掉。新会话建议:kill $(lsof -ti :8800) 后用 ./start.command 正常接管。
  • uvicorn --reload 不监控 .env:改 .env 后必须手动重启 server(Kill 8800 端口进程再起)。
  • 密钥在根目录 .env:DEEPSEEK_API_KEY(规划+文案)、DASHSCOPE_API_KEY(通义,可用 ✅)、RIGHTAPI_API_KEY(RightCode 中转,通道当前故障 ❌)、PCORE_API_KEY(pcore.ai,可用 ✅)、ARK_API_KEY 未配(豆包未用)。.env.example 有全部键位说明。

3. 生图供应商现状(2026-08-29,重要)

供应商 域名 模型(下拉显示) 状态
通义/阿里 dashscope.aliyuncs.com qwen-image-3.0-pro 等(阿里巴巴) ✅ 可用,实测 10s 出图
RightCode rightapi.ai gpt-image-2、gpt-image-2-vip、nano-banana 系列(RightCode) ❌ 通道故障:任务能提交但生成阶段 503/「No available channel」,纯文生图也失败;中转侧问题,待其恢复
Pcore pcore.ai gpt-image-2@pcore(Pcore) ✅ 可用(用户已在 pcore 开通 image2 分组后端到端跑通,全链路约 1 分钟/张)
  • 默认生图模型 = gpt-image-2@pcore(studio/src/services/suite.ts 的 DEFAULT_IMAGE_MODEL)。
  • 同名模型多中转的路由约定:前端模型 value 用「api模型@provider」后缀区分(目前仅 pcore 用到),服务端 schemas/suite.py 的 MODEL_PROVIDERS + api_model()(剥后缀)处理;白名单 PCORE_MODELS。
  • pcore 协议要点(generator.py 的 _pcore_request/_pcore_poll_task):无参考图走 POST /v1/images/generations,带参考图走 /v1/images/edits;对于 gpt-image-2,images 必须传 [{"image_url": "data:image/...;base64,..."}] 对象数组。Pcore 通用文档也描述字符串数组,但该模型通道会异步校验 images[].image_url,以实际错误为准。均为异步:提交拿 id → 轮询 GET /v1/images/{kind}/{task_id} → completed 后 data[0].url 取图。size 需使用模型支持的尺寸或比例。new_api 系中转常见「HTTP 200/503 + 错误体」,错误解析已兼容嵌套 error.{code,message};「No available channel」类错误不重试直接失败。
  • 速率:image2 分组 RPM 70 / RPD 1.2K(日限);当前独立 Worker 单进程逐图领取任务,远碰不到 RPM。pcore 账户余额 $5,按张扣费。

4. AI 规划张数策略(planner.py)

  • 不设硬性数量:prompt 让 AI 按商品复杂度自主决定,「建议 8 张左右」;规划规则 = 先保证每个 SKU 1 张主图,其余类型自行取舍。
  • 用户可通过「生图要求」指定张数:写了「N 张」AI 必须严格执行;服务端 _total_budget() 用正则提取,安全上限:默认 15、指定时按 N 最大 24(防跑飞,超限从尾部截断,SKU 主图优先保留)。
  • 规划器曾频繁报「规划器未返回有效方案项」:根因是 deepseek-v4 是思维链模型而规划器裸调用没禁 thinking,token 被推理烧光、正文为空。已修复:请求体加 "thinking": {"type": "disabled"} + 解析失败/空方案自动重试一次 + 失败时记录原始输出 + 缺 title 的方案项从 detail/kind 兜底合成不再丢弃。30 SKU 压测 3/3 通过。

5. 当前进度

✅ 已完成(含 2026-08-29 一轮,全部未提交,见 §6)

模块 内容
试算页 五区块页面、计价、俄文文案、采集图片/出图方案/生成结果、登记导出
采集对接 ISS 扩展并入 extensions/collector/,「上报商品」入库 + 自动打开试算页
生图服务端 planner/generator/prompts/watermark/jobs + 独立 Worker,套图 + 单张 AI 生图 + 水印 + ZIP 导出
本轮:Pcore 接入 新 provider 全链路(生成/编辑/轮询/重试/错误处理),@pcore 路由约定,下拉带供应商名,默认模型切 Pcore
本轮:规划器修复 thinking 禁用 + 重试 + 张数策略(AI 自主,建议 8 张左右,生图要求可指定)
本轮:采集箱 勾选列 + 全选/取消全选 + 批量删除(硬删、Popconfirm 二次确认、删空页自动回退)
本轮:采集图片区改版 8 列网格;AI 生图按钮半透明悬浮图片右下角;图名显示在图片下方(取 URL 末段);SKU 名并入图名行(不再悬浮遮挡勾选钮);勾选钮在右上角;默认全部不勾选
本轮:生成结果区 「导出图片」按钮(水印按钮右侧,复用 POST /api/export/images,ZIP 内分「套图结果/单张生图」文件夹);「单张 AI 生图」小节改名「生图记录」(落库历史,刷新后保留)
本轮:图片生命周期 采集、上传与 AI 图片统一保存为 original + current;只保留当前水印版;重加/移除水印自动回收旧对象;删除单图/硬删商品会清理本地或七牛对象;具体规则见 image-asset-lifecycle.md
本轮:图片资源上限 单张上传/下载默认 20 MB;采集最多 100 张;导出最多 50 张、总量 200 MB;ZIP 超过 2 MB 自动落临时磁盘并分块返回,配置见 .env.example
本轮:远程图片 SSRF 防护 代理、采集转存、AI 参考图、远程导出仅允许公网 HTTP(S) 地址;每跳重定向复验,限制连接/读写/总耗时与跳转次数;本项目 /media 素材继续本地直读,正常防盗链代理不受影响
本轮:图片格式与元数据校验 上传、采集转存、生成图统一按真实字节验证 JPEG/PNG/WebP/GIF/BMP,默认限制 4,000 万像素;静态图纠正 EXIF 方向并落库实际宽高。历史 39 条本地图像已回填尺寸;server/scripts/backfill_asset_dimensions.py 可用于其他旧库
本轮:试算页图片组件拆分与按页加载 TrialSuitePanel.tsx 拆出采集/结果/失败图片网格(TrialImageGrids.tsx)、水印设置(TrialWatermarkSettings.tsx)与共享类型;采集分组、套图结果、历史结果按每页 24 张渲染,缩略图启用原生懒加载。套图/水印轮询仍由父组件集中管理。
本轮:商品轮播视频 试算页独立的「07 视频制作」卡片:AI 图优先选择、2–5 图按选择顺序合成为 810×1080/30fps/H.264 无音轨 MP4;进行中卡片为 3:4 灰底加载态,成片可预览、下载或删除。任务复用 background_jobs,刷新恢复进行中/失败/完成状态;取消与删除都会立即移除记录及视频文件。Worker 依赖系统 ffmpeg/ffprobe(Ubuntu 安装 apt install -y ffmpeg)。
本轮:生图任务与轮询 单张 AI 编辑改为提交统一异步任务并立即返回 suite_id;套图与单张弹窗均采用无重叠递归轮询、取消在途请求与失败退避;套图任务 ID 可在刷新页面后从浏览器会话恢复
本轮:持久化图片任务 套图、单张编辑与批量添加水印已迁入数据库任务表和独立 Worker;Pcore/RightAPI/通义万相保存第三方任务 ID 并可在重启后恢复轮询;水印逐图进度可刷新恢复、取消并按失败项重试,详见 background-jobs.md
本轮:关键 bug 修复 ① axios 全局 Content-Type 导致 FormData 被 JSON 化 → 上传 422(api.ts 移除全局头,今后勿设);② TrialPage load() 置 loading 导致整页闪 Spin、卸载面板(杀生图轮询/丢勾选)→ 改静默刷新;③ web v1 页面因 cdn.tailwindcss.com 被墙整页无样式 → tailwind 运行时固化到 web/vendor/tailwind.js
本轮:杂项 采买地址「打开地址」改图标按钮(与复制图标同款);start.command 自动构建+监听插件

验证口径(本轮均实测通过)

  • 上传/生图/导出/批量删除/规划,全部真实接口+浏览器操作验证;Pcore 端到端 56s 出图并回写素材。
  • 每个 UI 改动后 pnpm -C studio exec tsc -b 零错误;插件构建通过;/api/health 200。

6. ⚠️ 未提交改动清单(当前最大事项)

分支 feat-2.1.0,工作区仍有多项未提交改动,建议按模块分 4-5 个 commit:

  1. Pcore 生图接入 + 规划器修复 + 张数策略 server/services/{generator,planner,suite_service,prompts/__init__}.py、server/{api/suite.py,schemas/suite.py,config/settings.py}、studio/src/services/suite.ts、.env.example、docs/v2.1/{image-suite,api}.md
  2. 试算页 UI 迭代 + 采集箱批量操作 + 请求层修复 studio/src/pages/trial/{TrialSuitePanel,TrialImageGrids,TrialWatermarkSettings,trialImageTypes,TrialInfoPanel,TrialPage}.tsx、studio/src/pages/collection/CollectionPage.tsx、studio/src/services/api.ts
  3. web v1 样式修复(CDN 固化)+ start.command 插件自动构建 web/ozonSeller.html、web/vendor/tailwind.js(新目录)、start.command
  4. 图片生命周期与水印回收:server/services/image_assets.py、server/services/storage.py、server/{api/materials,api/products,models/asset}.py、迁移 a41e8c7f4b20_add_asset_image_lifecycle.py、试算页水印入口
  5. 交接文档:docs/v2.1/{HANDOFF,image-asset-lifecycle,optimization-audit}.md

提交前:git checkout -- studio/tsconfig.app.tsbuildinfo(构建产物,勿提交)。

7. 下一步(按优先级)

  1. 提交:按 §6 分组提交。
  2. 手动全流程回归(浏览器 + Chrome 真机扩展):采集 → 上报 → 试算页五区块 → 生成(Pcore)/编辑/删除 → 登记表录入/导出 CSV/组合码 → 清空。
  3. 运营观察:pcore 余额($5 起步)与 image2 分组日限(1.2K 张/天);RightCode 通道恢复情况(恢复后 nano-banana 系列可回归)。
  4. Phase D 待办:批量 CSV 服务端化(GET /api/export/trial-csv);登记表数据存 localStorage(跨设备需落库)。
  5. 远期:鉴权/账户体系重做(从 deps.py 层重引);ISS-only 产品模式构建;extension-v1/v2、web/、server/legacy/ 清理时机。

8. 已知坑(新会话必读)

# 坑 对策
1 uvicorn --reload 不监控 .env 改 .env 后手动重启 server
2 生图任务依赖独立 Worker start.command 会启动;若手动运行 uvicorn,必须另开 python server/worker.py,否则任务会一直排队
3 SQLite 仅适合单机 Worker 当前通过租约恢复异常退出的任务;未来多实例前先迁移 PostgreSQL,再做多 Worker 竞争领取
4 外部模型任务可恢复范围不同 Pcore/RightAPI/通义万相保存 provider task id 后可继续轮询;豆包/同步千问没有外部任务 id,进程恰在请求中断时只能重试
5 axios 实例勿设全局 Content-Type axios 1.x 遇「默认 JSON 头 + FormData」会把表单转 JSON 发送(formDataToJSON),multipart 接口全 422。已从 api.ts 移除;对象请求体 axios 会自动补 JSON 头
6 web/ 样式依赖公网 CDN tailwind 已固化 web/vendor/tailwind.js;font-awesome/jsdelivr 若也断,同样方式下载到 web/vendor/ 改引用
7 试算页水印文本存 localStorage(trialWatermark) 改默认值不影响已保存设置;登记表同理存 localStorage trialRegisterRecords
8 studio/tsconfig.app.tsbuildinfo 是构建产物 提交前 git checkout -- studio/tsconfig.app.tsbuildinfo
9 冻结代码不要投入 server/legacy/、extension-v1/、extension-v2/、web/(本轮 CDN 固化属修复例外)、studio 商品编辑页的属性映射/发布区块
10 AI 规划/生图花钱 pcore 按 $ 扣费、RightCode 按张计费;联调时 plan 张数设 1-2、优先低成本模型
11 TrialPage load() 勿再置 loading 置 loading = 整页 Spin + 卸载面板 = 杀生图轮询/丢状态(已修,保持静默刷新)
12 浏览器自动化调试怪癖(如 ZCode IAB) 截图偶发超时(重试一次多半仍失败,改用几何测量/计算样式验证);文件上传需用 DataTransfer+input change 事件模拟;改代码后 React 事件偶发失灵 → reload 页面即恢复
13 图片上传/导出存在大小限制 默认单张 20 MB、采集 100 张、导出 50 张、ZIP 200 MB;超限接口返回 413。需要调整时改 .env 的 IMAGE_* / EXPORT_* 配置并重启服务

9. 关键文件速查

功能 前端(studio/src/) 后端(server/)
试算页骨架 pages/trial/TrialPage.tsx(load() 是静默刷新,见坑 11) —
01 商品信息(采买地址图标、型号/货号联动) pages/trial/TrialInfoPanel.tsx api/materials.py
02 价格试算 pages/trial/TrialPricingPanel.tsx + pricing/pricing.ts —
03 俄文文案 pages/product/CopyPanel.tsx(共用) api/ai.py + services/deepseek.py + prompts/copy_ru.py
04 图片与生图(7 列网格/悬浮按钮/图名) pages/trial/TrialSuitePanel.tsx(状态/轮询)+ TrialImageGrids.tsx(素材/结果卡片与分页)+ AiImageGenModal.tsx api/suite.py + services/{jobs,job_worker,suite_service,generator,planner,prompts/,watermark,image_assets}.py
图片原图/水印/删除回收 TrialSuitePanel.tsx(状态与调用)+ TrialWatermarkSettings.tsx(设置与任务状态) api/materials.py、api/products.py、services/{image_assets,storage}.py
生图供应商路由 services/suite.ts(IMAGE_MODEL_OPTIONS 带供应商名;DEFAULT_IMAGE_MODEL) schemas/suite.py(MODEL_PROVIDERS/@pcore 约定)+ services/generator.py(generate_pcore 等)
05 登记与导出 pages/trial/TrialExportPanel.tsx(localStorage trialRegisterRecords) —
生成结果导出 TrialSuitePanel.tsx handleExportResult(套图+单张分组 ZIP) api/export.py
采集箱(全选/批量删除) pages/collection/CollectionPage.tsx api/products.py(DELETE hard=true)
前端服务层 services/{suite,product,ai,fx,api}.ts schemas/suite.py(契约对齐)
扩展上报 extensions/collector/src/api/report.ts + entrypoints/{background,sidepanel/App}.tsx + storage/settings.ts api/materials.py

10. 验收标准(改完怎么算完成)

  1. pnpm -C studio exec tsc -b 零错误、pnpm -C studio build 通过(提交前还原 tsconfig.app.tsbuildinfo)
  2. 改扩展:pnpm -C extensions/collector build 通过
  3. 改 server:/api/health 200、涉及接口 curl/页面冒烟通过
  4. UI 改动:浏览器实测 + 必要时截图确认