Files
image-suite-studio/server/schemas.py
T
2026-08-19 17:05:23 +08:00

201 lines
7.0 KiB
Python
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.
"""Pydantic 契约(插件 ↔ 服务端)。"""
from __future__ import annotations
from pydantic import BaseModel, Field
SUPPORTED_TYPES = [
"white_bg", "key_features", "selling_pt", "material",
"lifestyle", "multi_scene", "ecommerce_detail",
"size_chart", "sku_collection", "custom",
]
# 通义(DashScope)生图模型白名单:插件下拉可选的模型
TONGYI_MODELS = ["qwen-image-3.0-pro", "wan2.7-image-pro", "wan2.6-image", "wan2.6-t2i"]
# RightAPI 生图模型白名单
RIGHTAPI_MODELS = ["gpt-image-2"]
# 模型 → provider 推断表:插件只传模型名,服务端据此路由(模型名优先于 provider 字段)
MODEL_PROVIDERS: dict[str, str] = {
**{m: "tongyi" for m in TONGYI_MODELS},
**{m: "rightapi" for m in RIGHTAPI_MODELS},
}
def resolve_provider(model: str | None, requested: str | None, default: str) -> str:
"""已知模型名直接定位 provider;未知模型回退到请求指定的 provider 或默认值。"""
if model and model in MODEL_PROVIDERS:
return MODEL_PROVIDERS[model]
return requested or default
# ── 采集上传 ──
class SourceInfo(BaseModel):
platform: str = Field(..., description="ozon | 1688 | taobao")
itemId: str | None = None
url: str = ""
collectedAt: int | None = None # epoch 毫秒
class TextMaterial(BaseModel):
kind: str = Field(..., description="title | params | selling_point | desc | price | brand")
content: str = ""
pairs: list[dict] | None = None # [{key, value}]
class ImageMaterial(BaseModel):
groupKey: str = Field(..., description="main | sku | detail | video")
groupName: str = ""
variantName: str | None = None
url: str = Field(..., description="源站原图 URL")
index: int = 0
type: str = "img"
dedupeKey: str | None = None
class MaterialsRequest(BaseModel):
product_id: str | None = Field(default=None, description="传了=追加到已有商品")
source: SourceInfo
texts: list[TextMaterial] = Field(default_factory=list)
images: list[ImageMaterial] = Field(default_factory=list)
refererOrigin: str | None = None
class MaterialsResponse(BaseModel):
product_id: str
assets_queued: int
assets_skipped: int = 0
# ── 套图生成 ──
# 目标平台 → 文案语言 + 图片比例(平台决定规格,不再单独选语言)
PLATFORM_SPECS: dict[str, dict] = {
"ozon": {"lang": "ru", "ratio": "3:4", "label": "Ozon"},
"wb": {"lang": "ru", "ratio": "3:4", "label": "Wildberries"},
"cn": {"lang": "zh", "ratio": "1:1", "label": "中文(国内平台)"},
}
class SuiteCreateRequest(BaseModel):
style_set: int = Field(default=1, ge=1, le=7, description="风格模板 1-7")
types: list[str] = Field(default_factory=lambda: ["white_bg", "key_features", "lifestyle", "multi_scene"])
platform: str = Field(default="cn", description="目标平台:ozon | wb | cn")
provider: str | None = Field(default=None, description="覆盖默认 providerdoubao | tongyi")
model: str | None = Field(default=None, description="覆盖默认生图模型(tongyi: qwen-image-3.0-pro / wan2.7-image-pro")
requirements: str | None = Field(default=None, description="生图要求(最高优先级,强制约束)")
# ── 无状态套图生成(工具流程:请求自带采集数据)──
class GenerateImageItem(BaseModel):
url: str = Field(..., description="勾选的图片 URL(源站原图)")
group_key: str = Field(default="main", description="main | sku | detail")
variant_name: str | None = Field(default=None, description="SKU 规格名(方案绑定用)")
class PlanItem(BaseModel):
"""出图方案项:一类图 × 数量,可绑定 SKU 规格。"""
kind: str = Field(default="custom", description="图类型(SUPPORTED_TYPES 之一)")
title: str = Field(..., description="方案标题,如「主图·粉色」")
detail: str = Field(default="", description="这张图展示什么(中文)")
prompt_hint: str = Field(default="", description="构图提示(英文,进生图 prompt")
count: int = Field(default=1, ge=0, le=5)
variant_name: str | None = Field(default=None, description="绑定的 SKU 规格名")
class GenerateRequest(BaseModel):
texts: list[TextMaterial] = Field(default_factory=list, description="采集的文本素材")
images: list[GenerateImageItem] = Field(default_factory=list, description="勾选的参考图")
style_set: int = Field(default=1, ge=1, le=7)
style_prompt: str | None = Field(default=None, description="用户改写的风格提示词(覆盖 style_set 模板)")
requirements: str | None = Field(default=None, description="生图要求(最高优先级,强制约束,覆盖其他设定)")
types: list[str] = Field(default_factory=list, description="旧参数:无方案时按类型生成")
plan: list[PlanItem] | None = Field(default=None, description="出图方案(优先于 types")
platform: str = Field(default="cn", description="目标平台:ozon | wb | cn")
provider: str | None = Field(default=None, description="覆盖默认 providerdoubao | tongyi")
model: str | None = Field(default=None, description="覆盖默认生图模型(tongyi: qwen-image-3.0-pro / wan2.7-image-pro")
# ── 出图方案规划(DeepSeek)──
class PlanRequest(BaseModel):
texts: list[TextMaterial] = Field(default_factory=list)
sku_variants: list[str] = Field(default_factory=list, description="带图的 SKU 规格名")
image_stats: dict = Field(default_factory=dict, description="分组图片数量统计")
platform: str = Field(default="cn")
requirements: str | None = Field(default=None, description="生图要求(最高优先级,规划方案必须遵循)")
class PlanItemOut(BaseModel):
kind: str
title: str
detail: str = ""
prompt_hint: str = ""
count: int = 1
variant_name: str | None = None
class PlanResponse(BaseModel):
summary: str = ""
items: list[PlanItemOut]
class SuiteCreateResponse(BaseModel):
suite_id: str
class SuiteImageOut(BaseModel):
type_id: str
name: str
url: str
status: str
error: str | None = None
class SuiteOut(BaseModel):
id: str
product_id: str
status: str
style_set: int
platform: str
lang: str
ratio: str
types: list[str]
provider: str
model: str | None = None
images: list[SuiteImageOut]
error: str | None = None
# ── 商品 ──
class AssetOut(BaseModel):
id: str
group_key: str
variant_name: str | None = None
type: str
source_url: str
url: str | None = None
status: str
class ProductOut(BaseModel):
id: str
stage: str
source_platform: str | None = None
source_item_id: str | None = None
source_url: str | None = None
name: str
description: str
price: float | None = None
asset_counts: dict | None = None
assets: list[AssetOut] = Field(default_factory=list)
created_at: str | None = None
class ProductListOut(BaseModel):
total: int
items: list[ProductOut]