Files
pod_trend_agent/对接文档.md
T

295 lines
14 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.
# POD 趋势感知 Agent · 对接文档
> 面向开发者/维护者的适配与扩展指南。覆盖:项目架构、**如何适配新国家**、核心流程、缓存机制、合规红线、常见问题与打包发布。
> 适用版本:dist_v67 / 源码 `pod_trend_agent/`
---
## 1. 项目概览
**目标**:为 PODPrint on Demand)出海业务自动捕捉海外热点 → 生成可打印的 T 恤印花设计 → 三图合成模特图 → 多语言标题 → 导出商品上传模板。
**技术栈**Python 3.13 · LangGraph7 节点流水线)· tkinter 桌面 UI · requests · Pillow · PyInstaller 打包
**两条运行路径**
| 路径 | 触发条件 | 行为 |
|---|---|---|
| **缓存热点模式**(日常) | `output/<国>/collected_keywords.json` 存在 | 直接用采集缓存分配热点;简报不足时**从采集缓存自动生成简报**(轻量补齐),**绝不触发 Google** |
| **完整流水线**(首次) | 完全无缓存 | `seed → fetch → filter → score → screen → prompt_build → compose → product → seed_shot → template_export → oss_upload` |
---
## 2. 目录结构
```
pod_trend_agent/
├── ui_app.py # 桌面 UI:选品/采集/运行/模板/结果表格
├── cli.py # 命令行入口
├── config.yaml # 全局配置(countries/sources/llm_screen/prompt_templates/compose/oss/product…)
├── configs/countries/<CC>.yaml# ★每国独立配置:种子词/related 种子/采集限额
├── prompts/<CC>/ # ★每国提示词:system_prompt.md + aesthetics.yaml
├── graph/
│ ├── agent.py # LangGraph 流水线编排(START→seed→fetch→…→END
│ ├── nodes/ # 各节点实现(seed/fetch/filter/score/screen/prompt/compose/product/seed_shot/template/oss
│ ├── product_batch.py # 缓存热点批量流程:分配/三级去重/review 兜底/轻量补齐
│ ├── backends/ # 图像后端:openai_image_backend / mock_image_backend
│ ├── llms/ # LLM 后端:openai_compat_backend(多模态标题)/ mock_backend
│ ├── seeds/ # 种子策略:dynamic_strategy(统一池+加权随机)/ static / holidays
│ ├── sources/ # 数据源注册表:google_trendspytrends429 兜底)/ pinterest
│ ├── product.py # 底图/模特查找(IMG_EXTS 全格式)、SKU 逻辑
│ ├── style_rules.py # 风格/配色/构图规则 + sanitize_image_prompt + review 魔改引导
│ ├── paths.py # config_root / project_root / runtime_root 路径解析
│ └── validate.py # 校验 + with_fallback 兜底装饰器
├── templates/ # 商品上传模板 + template_router.py(模板读写)
├── basemap/<款号>/<颜色>/ # 平铺底图(jpg/png…)
├── material_library/<品类>/ # 模特图(webp/jpg/png/avif…)
├── db/ # 商品数据库(sqlite
└── dist_vNN/ # PyInstaller 打包产物(含全部数据)
```
---
## 3. ★适配新国家(核心章节)
以新增 **DE(德国)** 为例,完整步骤:
### 3.1 国家代码入列
`config.yaml`
```yaml
countries:
- US
- GB
- JP
- AU
- MX
- DE # ← 新增
```
### 3.2 每国配置 `configs/countries/DE.yaml`
```yaml
# 德国专属数据源配置
trending:
enabled: true
limit: 40 # Google Trends 抓取上限
style:
enabled: true
seeds: # ★印花风格种子词(重点,越多越好,20~30 个)
- lederhosen
- alpine
- berlin street art
- bauhaus pattern
- autobahn
- ...
related:
enabled: true
seed_keywords:
- ...
exclude_topics: [] # 黑名单热点(已用过/明确不分配的词,可选)
```
**种子词选词红线**(写配置时注意):
- ❌ 会被 `review 兜底 _UNSUITABLE` 剔除的类目:`nails / recipes / lottery / weather / results / prices / jobs / mortgage / election…`(见 `graph/product_batch.py`
- ❌ 品牌/版权/真实人物:`nike / disney / margot robbie / prison break…`
- ❌ 图像策略敏感词:`skull / skeleton / blood / gun / demon…`(生成时会被 `sanitize_image_prompt` 替换,主题会变味)
- ✅ 用各国**本土流行 + 全球趋势**的印花主题(2026 参考:retro vintage / 极简 typography / 自然户外 / 手绘涂鸦 / Y2K / coquette / western / 幽默 quote / 星座塔罗 / 植物线稿)
### 3.3 每国提示词 `prompts/DE/`
- **`system_prompt.md`**screen 阶段 LLM 的角色/输出规则(风险判定、motif/art_style/color_palette/composition 四要素),**必须包含 "Return JSON…" 字样**(阿里云 MaaS 的 `response_format=json_object` 硬性要求)。
- **`aesthetics.yaml`**
```yaml
extra_style_rules: [...] # 该国风格倾向(配色/构图/审美)
extra_blacklist: [...] # 该国合规红线词(德国:纳粹符号等)
```
### 3.4 节假日 `graph/seeds/holidays.py`
`_HOLIDAYS_BY_COUNTRY` 增加国家节日(名称/月/日/规则/窗口),节日种子词自动带权重 3.0 进入统一池:
```python
"DE": [
("Oktoberfest", 9, 21, "third_saturday", 30), # 啤酒节(9 月)
("Weihnachten", 12, 25, "fixed", 25), # 圣诞节
...
]
```
### 3.5 国家模板站点校验 `ui_app.py`
`_check_template_site` 的 `country_sites` 字典加国家→站点关键词:
```python
country_sites = {
...
"DE": ("德国站", "德国"),
}
```
(模板「模版」sheet 第 1 行定位「经营站点」列 → 第 2 行站点名 → 与所选国家不匹配则**导入失败**,提示重新导入)
### 3.6 图像提示词模板 `config.yaml → prompt_templates`
`image_prompt` / `wearable_prompt` / `composite_prompt` 各加国家版本(`{motif}` 等占位符保持不变),注意:
- **提示词中不得出现任何背景描述**"isolated on … background"、"no background scene")——透明背景只由 `background="transparent"` 参数控制(官方要求)
- 不含安全规则段("no politics / no religion / no hate / no violence / no sexual"——这些词本身会触发图像 API 内容政策拦截)
### 3.7 验证清单
```bash
python cli.py -c DE --provider mock # mock 跑通全流程(不花钱)
python -c "from graph.seeds.dynamic_strategy import DynamicStrategy; ..." # 验证种子池
# UI 打开 → 切 DE → 采集 → 运行
```
---
## 4. 核心流程详解
### 4.1 完整流水线(LangGraph 7 节点)
```
START → seed(种子词) → fetch(采集) → filter(过滤) → score(打分) → screen(风险筛选+简报)
→ prompt_build(提示词) → compose(设计稿) → product(合成/标题) → seed_shot(种草图)
→ template_export(模板) → oss_upload(压缩上传) → END
```
每个节点均套 `with_fallback` 兜底(失败不中断整体流程)。
### 4.2 缓存热点模式(日常入口,`ui_app` / `run_product_batch`
```
判断:output/<国>/ 有 collected_keywords.json 或 design_briefs.json → 缓存模式
→ load 简报(简报不足 → _rebuild_briefs_from_cache 从采集缓存生成,不碰 Google)
→ assign_hotspots 分配(三级去重 + review 兜底)
→ product 节点批量处理(并发 ≤5,每 SPU 一线程)
→ 模板导出
```
### 4.3 热点分配与去重(`assign_hotspots`
| 层级 | 逻辑 |
|---|---|
| ① 热点去重 | 本批优先不同 topic(热点1-风格1、热点2-风格1…) |
| ② 风格去重 | 热点用完后自动切:热点1-风格2、热点2-风格2…(同 topic 不同 art_style |
| ③ 兜底 | 剩余未用指纹(低分热点也可);**历史已用 (topic, style) 指纹绝不重复出** |
| review 兜底 | `_UNSUITABLE` 正则剔除不适合类目(美甲/食谱/彩票/天气/比分…),日志提示 |
### 4.4 种子词机制(`dynamic_strategy.py`
- **统一池**:静态 style + 静态 related + 月份主题 + 节日 + LLM 动态 → 全部合并去重(跨类型同词权重累加)
- **权重**:节日 3.0 > 月份主题 2.0 > 静态/动态 1.0(加权随机抽取)
- **每次随机取**(加权不重复);**用完全用**(池 ≤ 需要数时全部使用,不随机限量)
- 每国独立配置(`configs/countries/<CC>.yaml`),种子缓存 `.cache/seeds/`(按 国家+provider+日期,防 Google 429
---
## 5. 缓存文件
| 文件 | 位置 | 作用 |
|---|---|---|
| `collected_keywords.json` | `output/<国>/` | 采集热点池(关键词列表) |
| `design_briefs.json` | `output/<国>/` | 简报池(topic/motif/risk/score/image_prompt…) |
| `used_designs.json` | `output/<国>/` | 已用 (topic, art_style) 指纹(成功生成才写入) |
| `.cache/seeds/` | 项目根 | 种子词日缓存(防 429 重采集) |
| `.cache/llm_screen/` | 项目根 | LLM 筛查缓存 |
> 注意:**失败产品不写 used_designs**(合成/设计失败的,热点下次仍可用)。
> 已用过不要的热点:直接从 `collected_keywords.json` / `design_briefs.json` 物理删除即可(如 8-22 的 18 个 GB 热点处理方式)。
---
## 6. 合规红线(最重要)
1. **review 判定**screen 阶段 LLM 判定疑似商标/版权/真实人物 → `risk_level=review`;openai 模式下生成设计时**自动注入原创化魔改引导**(`REVIEW_REBRAND_HINT`:只做风格参考、禁止复刻 logo/商标/角色、换名换细节)
2. **提示词清洗** `sanitize_image_prompt`(生成设计前必过):
- 删除一切背景描述(透明背景由参数控制)
- 删除内容策略触发段(`any text must be safe: no politics/religion/hate/violence/sexual…`
- 21+ 个敏感词安全替换(skull→smiley mascot、gun→star…)
3. **各国红线**:美国慎政治/宗教;德国慎纳粹符号(`aesthetics.yaml extra_blacklist` 扩展);中东整体保守;真实人物一律不进
4. **review 兜底 `_UNSUITABLE`**:不适合类目自动剔除(分配源头拦截)
---
## 7. 图像生成与合成
### 7.1 设计稿生成(`compose` / `product` 的 `generate`
- **透明背景**`background="transparent"` 参数(compose/product 配置均已设);**提示词不得提背景**
- 并发:compose 并发生成(`compose.design_workers` 默认 5);product 阶段每 SPU 一线程,并发上限 5
- 底图/模特/设计 >2MB → 自动压缩到 <2MB 再上传网关(`_shrink_blob_to_2mb`
### 7.2 三图合成(`product` 的 `print`mark=1
- 上传顺序:**图1 模特图 → 图2 印花设计稿 → 图3 衣服平铺底图**(与提示词角色一一对应)
- 图3 只提取衣服本身底色与面料材质(忽略平铺图背景/桌面/场景)
- 合成失败 → 退避重试 3 次(5/20/40s);仍失败 → 跳过该产品(不生成标题、不写模板)
- 网关处理约 2-6 分钟属正常(重负载 img2img)
---
## 8. 模型与网络配置(`config.yaml`
```yaml
llm_screen: # LLMscreen/种子/标题共用)
model: "qwen3.7-..." # ★标题生成需视觉模型(qwen-vl 系列);纯文本模型会 400
base_url: "https://...maas.aliyuncs.com/compatible-mode/v1"
api_key: "sk-..." # 或环境变量 LLM_API_KEY
compose: # 设计稿图像网关
backend: "openai"
model: "gpt-image-2" # 支持 background=transparent
base_url: "https://api.tofastcode.xyz"
background: "transparent"
product:
backend: "mock" # openai / mock
background: "transparent"
concurrency: 5 # 合成并发上限(默认 min(任务数,5))
```
**代理策略**:模型调用(LLM + 图像)一律直连(`NO_PROXY` + 环境变量级 `no_proxy=*`,用户挂 VPN 也不走代理);**Google 采集(pytrends)走系统代理**(需要 VPN)。
---
## 9. 打包发布(每版流程)
```bash
# 1. 打包(不跑 self-test:会撞 Google 429,浪费 7-10 分钟)
pyinstaller -y PODTrendAgent.spec --distpath dist_vNN --workpath build_cleanNN
# 2. 补齐 dist 数据(必须,否则 exe 缺资源)
cp -r templates db basemap material_library configs prompts .cache dist_vNN/
cp config.yaml dist_vNN/
# 3. 拷贝最近缓存(output/<国>/*.json),避免 exe 首次运行重新采集
# 4. 验证:find_first_model_folder 能查到模特(material_library 拷贝不完整是常见坑)
```
---
## 10. 常见问题(FAQ
| 现象 | 根因 | 解决 |
|---|---|---|
| 有缓存还去采集(Google 429 刷屏) | UI 判断只看 design_briefs,忽略 collected | v60+ 已修:有 collected 即缓存模式,绝不触发 seed/fetch |
| Google 429 / SSL EOF | 限流 | 换 VPN 节点;已采集后运行走缓存不再碰 Google |
| 三图合成全部超时 | 并发过高压垮网关 / 底图过大 | 并发上限 5 + 输入图压缩 <2MB + 退避重试 |
| 生成设计全是商标侵权 | review 简报未魔改 | v57+ 自动注入 REVIEW_REBRAND_HINT |
| 内容政策拦截频繁 | 提示词含敏感词/安全规则段/背景描述 | sanitize_image_prompt 自动清理 |
| 设计稿不透明(RGB 白底) | product 后端未配 background | `product.background: transparent` |
| 标题 400 | 模型不支持图片输入(非视觉模型) | 换 qwen-vl 系列视觉模型 |
| 模特找不到 | material_library 拷贝不全 / avif 不识别 | 全量拷贝;IMG_EXTS 已含 avif/gif/tiff |
| 生成的设计 6 个重复 | compose 只生成 safe 简报的设计 | v48+ 为全部简报(含 review)生成设计 |
---
## 11. 开发环境
```bash
python -m venv .venv
.venv/Scripts/pip install -r requirements.txt # 或 uv syncuv.lock 已锁定)
# 环境变量:LLM_API_KEY / LLM_BASE_URL / OSS_ACCESS_KEY_ID / OSS_ACCESS_KEY_SECRET
```
**对接新国家一句话总结**`configs/countries/<CC>.yaml`(种子词)+ `prompts/<CC>/`(提示词)+ `holidays.py`(节日)+ `config.yaml countries 列表` + UI 国家下拉 + 模板站点映射 → mock 跑通 → 真 LLM 验证。