119 lines
5.8 KiB
Python
119 lines
5.8 KiB
Python
"""数据模型:Product(商品)/ ProductAsset(采集素材)/ Suite(套图任务)/ SuiteImage(生成图)。"""
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import DateTime, Float, ForeignKey, Integer, JSON, String, Text, Uuid, func
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from db import Base
|
|
|
|
# 产品阶段
|
|
STAGE_COLLECTED = "collected"
|
|
STAGE_GENERATED = "generated"
|
|
|
|
# 素材/生成图状态
|
|
STATUS_PENDING = "pending"
|
|
STATUS_DOWNLOADING = "downloading"
|
|
STATUS_OK = "ok"
|
|
STATUS_FAILED = "failed"
|
|
|
|
# 套图任务状态
|
|
SUITE_PENDING = "pending"
|
|
SUITE_RUNNING = "running"
|
|
SUITE_DONE = "done"
|
|
SUITE_PARTIAL = "partial"
|
|
SUITE_FAILED = "failed"
|
|
|
|
|
|
class Product(Base):
|
|
__tablename__ = "products"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
stage: Mapped[str] = mapped_column(String(16), default=STAGE_COLLECTED, index=True)
|
|
|
|
# 采集溯源
|
|
source_platform: Mapped[str | None] = mapped_column(String(16), nullable=True) # ozon | 1688 | taobao
|
|
source_item_id: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)
|
|
source_url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
|
|
name: Mapped[str] = mapped_column(Text, default="")
|
|
description: Mapped[str] = mapped_column(Text, default="")
|
|
price: Mapped[float | None] = mapped_column(Float, nullable=True)
|
|
|
|
# 采集原文:{title, price, brand, params: [...], sellingPoints, desc, texts: [...]}
|
|
raw: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
asset_counts: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), server_default=func.now(), onupdate=func.now(), index=True
|
|
)
|
|
|
|
|
|
class ProductAsset(Base):
|
|
"""采集素材(源站图片,转存到本地 media)。"""
|
|
|
|
__tablename__ = "product_assets"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
product_id: Mapped[uuid.UUID] = mapped_column(
|
|
Uuid(as_uuid=True), ForeignKey("products.id", ondelete="CASCADE"), index=True
|
|
)
|
|
group_key: Mapped[str] = mapped_column(String(16), default="main") # main/sku/detail/video
|
|
variant_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
|
|
sort_order: Mapped[int] = mapped_column(Integer, default=0)
|
|
type: Mapped[str] = mapped_column(String(8), default="img") # img / video
|
|
source_url: Mapped[str] = mapped_column(Text, default="")
|
|
stored_url: Mapped[str | None] = mapped_column(Text, nullable=True) # 本地 media key 或公网 URL
|
|
status: Mapped[str] = mapped_column(String(16), default=STATUS_PENDING, index=True)
|
|
dedupe_key: Mapped[str | None] = mapped_column(String(512), nullable=True, index=True)
|
|
error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
|
|
|
|
class Suite(Base):
|
|
"""一次套图生成任务(无状态:直接携带采集数据,不依赖商品库)。"""
|
|
|
|
__tablename__ = "suites"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
# 兼容旧的商品挂载路径;工具化流程为空
|
|
product_id: Mapped[uuid.UUID | None] = mapped_column(
|
|
Uuid(as_uuid=True), ForeignKey("products.id", ondelete="CASCADE"), nullable=True, index=True
|
|
)
|
|
status: Mapped[str] = mapped_column(String(16), default=SUITE_PENDING, index=True)
|
|
style_set: Mapped[int] = mapped_column(Integer, default=1) # 风格模板 1-5
|
|
style_prompt: Mapped[str | None] = mapped_column(Text, nullable=True) # 用户改写的风格提示词(覆盖模板)
|
|
platform: Mapped[str] = mapped_column(String(8), default="cn") # 目标平台 ozon | wb | cn
|
|
lang: Mapped[str] = mapped_column(String(4), default="zh") # ru / zh(由平台推导)
|
|
ratio: Mapped[str] = mapped_column(String(8), default="1:1") # 图片比例(由平台推导)
|
|
types: Mapped[list | None] = mapped_column(JSON, nullable=True) # 图类型 id 列表(旧)
|
|
plan: Mapped[list | None] = mapped_column(JSON, nullable=True) # 出图方案(展开后的逐张任务)
|
|
provider: Mapped[str] = mapped_column(String(16), default="doubao")
|
|
model: Mapped[str | None] = mapped_column(String(64), nullable=True) # 生图模型名(覆盖 provider 默认)
|
|
# 工具化流程:请求自带的数据(生图上下文 + 参考图 URL 列表)
|
|
context: Mapped[dict | None] = mapped_column(JSON, nullable=True)
|
|
ref_images: Mapped[list | None] = mapped_column(JSON, nullable=True)
|
|
error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
class SuiteImage(Base):
|
|
"""任务里单张生成图。"""
|
|
|
|
__tablename__ = "suite_images"
|
|
|
|
id: Mapped[uuid.UUID] = mapped_column(Uuid(as_uuid=True), primary_key=True, default=uuid.uuid4)
|
|
suite_id: Mapped[uuid.UUID] = mapped_column(
|
|
Uuid(as_uuid=True), ForeignKey("suites.id", ondelete="CASCADE"), index=True
|
|
)
|
|
type_id: Mapped[str] = mapped_column(String(32)) # white_bg / key_features / ...
|
|
name: Mapped[str] = mapped_column(String(64), default="") # 中文名(文件名)
|
|
stored_url: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
status: Mapped[str] = mapped_column(String(16), default=STATUS_PENDING)
|
|
error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
|