from __future__ import annotations from datetime import datetime from sqlalchemy import DateTime, ForeignKey, Index, String, Text, text from sqlalchemy.orm import Mapped, mapped_column from app.enums.common import ModuleGenerationFlowVersionEnum from app.models.base import Base, SoftDeleteMixin, TimestampMixin class ModuleGenerationProject(Base, TimestampMixin, SoftDeleteMixin): """通用模块生成项目/总任务表。 说明: - 本表的 id 就是前端理解的“项目ID/总任务ID”,不再额外保存 project_id。 - 通过 module 区分业务模块,后续其它功能也可以复用这张总任务项目表。 - 爆款开头复刻使用 module=hot_opening_replicate。 """ __tablename__ = "module_generation_projects" __table_args__ = ( Index("idx_module_generation_projects_user_module", "user_id", "module"), Index("idx_module_generation_projects_status", "module", "status"), Index( "uq_module_generation_projects_user_module_idempotency", "user_id", "module", "idempotency_key", unique=True, postgresql_where=text("deleted_at IS NULL AND idempotency_key IS NOT NULL"), ), ) id: Mapped[str] = mapped_column(String(32), primary_key=True) user_id: Mapped[str] = mapped_column( String(32), ForeignKey("users.id", ondelete="CASCADE"), index=True, nullable=False ) module: Mapped[str] = mapped_column(String(64), index=True, nullable=False) flow_version: Mapped[str] = mapped_column( String(16), nullable=False, default=ModuleGenerationFlowVersionEnum.V1.value, server_default=ModuleGenerationFlowVersionEnum.V1.value, ) title: Mapped[str | None] = mapped_column(String(160), nullable=True) status: Mapped[str] = mapped_column(String(32), default="pending", index=True) current_step_code: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) final_image_url: Mapped[str | None] = mapped_column(String(512), nullable=True) final_video_url: Mapped[str | None] = mapped_column(String(512), nullable=True) final_video_cover_url: Mapped[str | None] = mapped_column(String(512), nullable=True) error_message: Mapped[str | None] = mapped_column(Text, nullable=True) idempotency_key: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True) completed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)