Files
video-gen/video-gen-api/app/models/shot_replicate_task_set.py
T
2026-07-22 14:53:03 +08:00

67 lines
3.5 KiB
Python

from __future__ import annotations
from datetime import datetime
from typing import Any
from sqlalchemy import DateTime, Float, ForeignKey, Index, Integer, JSON, String, Text, text
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column
from app.models.base import Base, SoftDeleteMixin, TimestampMixin
_JSON_TYPE = JSON().with_variant(JSONB, "postgresql")
class ShotReplicateTaskSet(Base, TimestampMixin, SoftDeleteMixin):
"""拆镜复刻总任务集。"""
__tablename__ = "shot_replicate_task_sets"
__table_args__ = (
Index("idx_shot_replicate_task_sets_user_created", "user_id", "created_at"),
Index("idx_shot_replicate_task_sets_status", "status"),
Index("idx_shot_replicate_task_sets_analysis_status", "analysis_status"),
Index("idx_shot_task_sets_analysis_lease", "analysis_status", "analysis_lease_until"),
Index("idx_shot_replicate_task_sets_split_status", "split_status"),
Index(
"uq_shot_replicate_task_sets_user_idempotency",
"user_id",
"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
)
title: Mapped[str | None] = mapped_column(String(160), nullable=True)
video_url: Mapped[str] = mapped_column(String(512), nullable=False)
video_path: Mapped[str] = mapped_column(String(512), nullable=False)
video_duration_seconds: Mapped[float] = mapped_column(Float, nullable=False)
status: Mapped[str] = mapped_column(String(32), default="pending_analysis", index=True, nullable=False)
analysis_status: Mapped[str] = mapped_column(String(32), default="pending", index=True, nullable=False)
split_status: Mapped[str] = mapped_column(String(32), default="none", index=True, nullable=False)
original_video_content: Mapped[str | None] = mapped_column(Text, nullable=True)
original_video_category: Mapped[str | None] = mapped_column(String(160), nullable=True)
original_video_audience: Mapped[str | None] = mapped_column(Text, nullable=True)
ai_suggestion_json: Mapped[list[Any] | dict[str, Any] | None] = mapped_column(_JSON_TYPE, nullable=True)
analysis_raw_json: Mapped[dict[str, Any] | list[Any] | None] = mapped_column(_JSON_TYPE, nullable=True)
analysis_result_json: Mapped[dict[str, Any] | list[Any] | None] = mapped_column(_JSON_TYPE, nullable=True)
segment_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
completed_segment_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
failed_segment_count: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
analysis_attempt_no: Mapped[int] = mapped_column(Integer, default=1, nullable=False)
analysis_claim_token: Mapped[str | None] = mapped_column(String(64), nullable=True)
analysis_started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
analysis_lease_until: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
analysis_error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
split_error_message: Mapped[str | None] = mapped_column(Text, nullable=True)
idempotency_key: Mapped[str | None] = mapped_column(String(64), nullable=True, index=True)