- 缓存热点批量流程(有采集缓存不触发 Google) - 简报不足直接从采集缓存生成(轻量补齐) - 三图合成(模特/印花/底图)+ 底图压缩 <2MB - 热点去重→风格去重自动切换 + 不适合类目 review 兜底 - 透明背景(background=transparent)+ 提示词清洗(敏感词/背景描述) - 任务前 basemap 校验 + 模板国家校验 + 模特任务级分配
110 lines
5.1 KiB
Python
110 lines
5.1 KiB
Python
"""节点 7/7:压缩 + 上传阿里云 OSS(oss_upload)。
|
||
|
||
在 product 之后运行:把 product 生成的成品图(composite / printed / design / basemap)
|
||
压缩为 3:4 / ≥1340×1785 / <2MB 的 JPEG,上传到 config.oss 图床。
|
||
|
||
上传 key(图床路径):{国家}/{任务时间戳}/{货号}_{4位随机}.jpg
|
||
- 任务时间戳:任务开始记录(YYYYMMDDHHMMSS),state["task_timestamp"],缺失时取当前时间
|
||
- 货号:用户自定义前缀(config.product.code_prefix,默认 DG)+ 3 位计数(000 起,最多 999)
|
||
- 4 位随机:大小写英文 + 数字
|
||
|
||
压缩/上传均带兜底:单图失败不影响其它;未配置 oss 或 enabled=false 时静默跳过。
|
||
"""
|
||
import random
|
||
import string
|
||
import time
|
||
from pathlib import Path
|
||
from typing import Any, Dict, List
|
||
|
||
from graph.validate import with_fallback
|
||
|
||
# design 设计稿是过程稿(不进模板),不压缩不上传;只传最终商品图
|
||
KIND_ORDER = ["composite", "printed", "basemap"]
|
||
MAX_CODE = 999 # 货号计数上限(000~998 共 999 张)
|
||
|
||
|
||
def _gen_rand4() -> str:
|
||
return "".join(random.choices(string.ascii_letters + string.digits, k=4))
|
||
|
||
|
||
@with_fallback("oss_upload")
|
||
def oss_upload_node(state: Dict[str, Any]) -> Dict[str, Any]:
|
||
products: List[Dict[str, Any]] = state.get("product") or []
|
||
config = state["config"] or {}
|
||
oss_cfg = config.get("oss") or {}
|
||
country = state.get("country", "")
|
||
|
||
if not (oss_cfg.get("oss_bucket") and oss_cfg.get("oss_key_id")):
|
||
print("[oss] 未配置 oss(config.oss),跳过压缩上传节点。")
|
||
return {"oss": [], "stats": state.get("stats") or {}}
|
||
if not bool(oss_cfg.get("enabled", True)):
|
||
print("[oss] config.oss.enabled=false,跳过上传。")
|
||
return {"oss": [], "stats": state.get("stats") or {}}
|
||
|
||
from graph.oss_upload import build_oss_key, compress_for_oss, upload_to_oss
|
||
|
||
# 任务时间戳:任务开始记录;缺失则当前时间
|
||
ts = str(state.get("task_timestamp") or time.strftime("%Y%m%d%H%M%S"))
|
||
# 货号前缀:config.product.code_prefix(默认 DG)
|
||
prefix = str(((config.get("product") or {}).get("code_prefix")) or "DG").strip()
|
||
# 序号从 state 续接(一次任务内跨多次节点调用不重号)
|
||
seq = int(state.get("oss_seq") or 0)
|
||
|
||
uploaded: List[Dict[str, Any]] = []
|
||
stats = dict(state.get("stats") or {})
|
||
for r in products:
|
||
spu = r.get("spu_code", "")
|
||
sku = r.get("sku_code", "")
|
||
for kind in KIND_ORDER:
|
||
src = r.get(f"{kind}_path")
|
||
if not src or not Path(src).exists():
|
||
continue
|
||
if seq >= MAX_CODE:
|
||
print(f"[oss] 货号计数已达上限 999,停止上传后续图片({src})")
|
||
break
|
||
try:
|
||
code = f"{prefix}{seq:03d}" # 货号:前缀 + 3 位计数(000 起)
|
||
compressed = compress_for_oss(src, str(Path(src).with_suffix(".oss.jpg")))
|
||
key = build_oss_key(country, ts, code, _gen_rand4())
|
||
url = upload_to_oss(oss_cfg, compressed, key)
|
||
if url:
|
||
r[f"{kind}_url"] = url
|
||
r["oss_code"] = code
|
||
uploaded.append({"spu_code": spu, "sku_code": sku, "kind": kind,
|
||
"code": code, "url": url})
|
||
seq += 1
|
||
except Exception as e: # noqa: BLE001
|
||
print(f"[oss] 处理失败 {src}: {e}")
|
||
|
||
# 多色:color_composites 用于模板按颜色路由——首色用主图 url/code,额外色单独上传(独立货号)
|
||
color_ups: List[Dict[str, Any]] = []
|
||
comps = r.get("color_composites") or []
|
||
if comps and r.get("composite_url"):
|
||
color_ups.append({**comps[0], "url": r["composite_url"], "code": r.get("oss_code", "")})
|
||
for cc in comps[1:]:
|
||
src = cc.get("composite_path")
|
||
if not src or not Path(src).exists():
|
||
continue
|
||
if seq >= MAX_CODE:
|
||
print("[oss] 货号计数已达上限 999,停止上传颜色图")
|
||
break
|
||
try:
|
||
code = f"{prefix}{seq:03d}"
|
||
compressed = compress_for_oss(src, str(Path(src).with_suffix(".oss.jpg")))
|
||
key = build_oss_key(country, ts, code, _gen_rand4())
|
||
url = upload_to_oss(oss_cfg, compressed, key)
|
||
if url:
|
||
cc["url"] = url
|
||
cc["code"] = code
|
||
color_ups.append(cc)
|
||
uploaded.append({"spu_code": spu, "sku_code": cc.get("sku_code"),
|
||
"kind": "composite_color", "code": code, "url": url})
|
||
seq += 1
|
||
except Exception as e: # noqa: BLE001
|
||
print(f"[oss] 颜色图上传失败 {src}: {e}")
|
||
if color_ups:
|
||
r["color_composites"] = color_ups
|
||
|
||
stats["oss"] = {"uploaded": len(uploaded), "timestamp": ts, "prefix": prefix, "seq": seq}
|
||
return {"oss": uploaded, "product": products, "oss_seq": seq, "stats": stats}
|