This commit is contained in:
2026-07-07 15:18:00 +08:00
parent e94225995c
commit 0fb2c5f165
52 changed files with 4017 additions and 1531 deletions
@@ -2,12 +2,13 @@ from __future__ import annotations
from datetime import datetime
from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, Text, text
from sqlalchemy import DateTime, Float, ForeignKey, Index, Integer, String, Text, text
from sqlalchemy.orm import Mapped, mapped_column
from app.enums.private_portrait import (
PrivatePortraitAssetStatus,
PrivatePortraitAssetType,
PrivatePortraitLibraryType,
PrivatePortraitRemoteDeleteStatus,
)
from app.models.base import Base, SoftDeleteMixin, TimestampMixin
@@ -19,10 +20,13 @@ class PrivatePortraitAsset(Base, TimestampMixin, SoftDeleteMixin):
__tablename__ = "private_portrait_assets"
__table_args__ = (
Index("uq_private_portrait_assets_remote_asset_id", "remote_asset_id", unique=True),
Index("idx_private_portrait_assets_user_library_status_created", "user_id", "library_type", "status", "created_at"),
Index("idx_private_portrait_assets_user_status_created", "user_id", "status", "created_at"),
Index("idx_private_portrait_assets_project_status_created", "project_id", "status", "created_at"),
Index("idx_private_portrait_assets_group_status_created", "group_id", "status", "created_at"),
Index("idx_private_portrait_assets_remote_project_name", "remote_project_name"),
Index("idx_private_portrait_assets_library_type", "library_type"),
Index("idx_private_portrait_assets_asset_type", "asset_type"),
Index(
"idx_private_portrait_assets_next_poll_status",
"next_poll_at",
@@ -36,6 +40,13 @@ class PrivatePortraitAsset(Base, TimestampMixin, SoftDeleteMixin):
user_id: Mapped[str] = mapped_column(String(32), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
project_id: Mapped[str] = mapped_column(String(32), ForeignKey("private_portrait_projects.id", ondelete="CASCADE"), nullable=False, index=True)
group_id: Mapped[str] = mapped_column(String(32), ForeignKey("private_portrait_asset_groups.id", ondelete="CASCADE"), nullable=False, index=True)
library_type: Mapped[str] = mapped_column(
String(32),
nullable=False,
default=PrivatePortraitLibraryType.REAL_PERSON.value,
server_default=PrivatePortraitLibraryType.REAL_PERSON.value,
index=True,
)
remote_group_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
remote_asset_id: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
remote_project_name: Mapped[str] = mapped_column(String(256), nullable=False, index=True)
@@ -45,6 +56,10 @@ class PrivatePortraitAsset(Base, TimestampMixin, SoftDeleteMixin):
preview_url: Mapped[str | None] = mapped_column(Text, nullable=True)
remote_url: Mapped[str | None] = mapped_column(Text, nullable=True)
remote_url_expired_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
video_duration: Mapped[float | None] = mapped_column(Float, nullable=True, comment="视频素材时长,秒")
video_cover_url: Mapped[str | None] = mapped_column(Text, nullable=True, comment="视频素材封面预览地址")
file_size: Mapped[int | None] = mapped_column(Integer, nullable=True, comment="素材文件大小,字节")
mime_type: Mapped[str | None] = mapped_column(String(128), nullable=True)
status: Mapped[str] = mapped_column(
String(32),
nullable=False,
@@ -6,8 +6,9 @@ from sqlalchemy import DateTime, ForeignKey, Index, String, Text, text
from sqlalchemy.orm import Mapped, mapped_column
from app.enums.private_portrait import (
PRIVATE_PORTRAIT_GROUP_TYPE,
PRIVATE_PORTRAIT_REAL_PERSON_GROUP_TYPE,
PrivatePortraitAssetGroupStatus,
PrivatePortraitLibraryType,
PrivatePortraitRemoteDeleteStatus,
)
from app.models.base import Base, SoftDeleteMixin, TimestampMixin
@@ -20,9 +21,11 @@ class PrivatePortraitAssetGroup(Base, TimestampMixin, SoftDeleteMixin):
__table_args__ = (
Index("uq_private_portrait_asset_groups_remote_group_id", "remote_group_id", unique=True),
Index("idx_private_portrait_asset_groups_user_project", "user_id", "project_id"),
Index("idx_private_portrait_asset_groups_user_library", "user_id", "library_type"),
Index("idx_private_portrait_asset_groups_project_status", "project_id", "status"),
Index("idx_private_portrait_asset_groups_remote_delete_status", "remote_delete_status"),
Index("idx_private_portrait_asset_groups_remote_project_name", "remote_project_name"),
Index("idx_private_portrait_asset_groups_library_type", "library_type"),
Index(
"uq_private_portrait_asset_groups_one_active_project",
"project_id",
@@ -34,10 +37,17 @@ class PrivatePortraitAssetGroup(Base, TimestampMixin, SoftDeleteMixin):
id: Mapped[str] = mapped_column(String(32), primary_key=True)
user_id: Mapped[str] = mapped_column(String(32), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
project_id: Mapped[str] = mapped_column(String(32), ForeignKey("private_portrait_projects.id", ondelete="CASCADE"), nullable=False, index=True)
library_type: Mapped[str] = mapped_column(
String(32),
nullable=False,
default=PrivatePortraitLibraryType.REAL_PERSON.value,
server_default=PrivatePortraitLibraryType.REAL_PERSON.value,
index=True,
)
remote_group_id: Mapped[str] = mapped_column(String(128), nullable=False, index=True)
remote_group_name: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
remote_project_name: Mapped[str] = mapped_column(String(256), nullable=False, index=True)
group_type: Mapped[str] = mapped_column(String(32), nullable=False, default=PRIVATE_PORTRAIT_GROUP_TYPE, server_default=PRIVATE_PORTRAIT_GROUP_TYPE)
group_type: Mapped[str] = mapped_column(String(32), nullable=False, default=PRIVATE_PORTRAIT_REAL_PERSON_GROUP_TYPE, server_default=PRIVATE_PORTRAIT_REAL_PERSON_GROUP_TYPE)
status: Mapped[str] = mapped_column(
String(32),
nullable=False,
@@ -5,15 +5,16 @@ from datetime import datetime
from sqlalchemy import DateTime, ForeignKey, Index, Integer, String, Text, text
from sqlalchemy.orm import Mapped, mapped_column
from app.enums.private_portrait import PrivatePortraitProjectStatus
from app.enums.private_portrait import PrivatePortraitLibraryType, PrivatePortraitProjectStatus
from app.models.base import Base, SoftDeleteMixin, TimestampMixin
class PrivatePortraitProject(Base, TimestampMixin, SoftDeleteMixin):
"""用户本地真人素材项目组。remote_project_name 是火山 ProjectName 快照。"""
"""用户本地私域人像素材项目组。remote_project_name 是火山 ProjectName 快照。"""
__tablename__ = "private_portrait_projects"
__table_args__ = (
Index("idx_private_portrait_projects_user_library_status_created", "user_id", "library_type", "status", "created_at"),
Index("idx_private_portrait_projects_user_status_created", "user_id", "status", "created_at"),
Index(
"idx_private_portrait_projects_user_deleted",
@@ -22,10 +23,19 @@ class PrivatePortraitProject(Base, TimestampMixin, SoftDeleteMixin):
postgresql_where=text("deleted_at IS NULL"),
),
Index("idx_private_portrait_projects_remote_project_name", "remote_project_name"),
Index("idx_private_portrait_projects_library_type", "library_type"),
)
id: Mapped[str] = mapped_column(String(32), primary_key=True)
user_id: Mapped[str] = mapped_column(String(32), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
library_type: Mapped[str] = mapped_column(
String(32),
nullable=False,
default=PrivatePortraitLibraryType.REAL_PERSON.value,
server_default=PrivatePortraitLibraryType.REAL_PERSON.value,
index=True,
comment="素材库类型:real_person 真人认证;aigc_virtual 虚拟人像",
)
name: Mapped[str] = mapped_column(String(128), nullable=False, index=True, comment="用户展示项目名")
name_slug: Mapped[str] = mapped_column(String(128), nullable=False, index=True, comment="项目名安全 slug")
remote_project_name: Mapped[str] = mapped_column(String(256), nullable=False, index=True, comment="火山 ProjectName 快照")
@@ -39,5 +49,9 @@ class PrivatePortraitProject(Base, TimestampMixin, SoftDeleteMixin):
)
asset_group_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
asset_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
image_asset_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
video_asset_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
active_asset_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
active_image_asset_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
active_video_asset_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
last_used_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
+2 -2
View File
@@ -39,8 +39,8 @@ class User(Base, TimestampMixin):
)
allowed_menus: Mapped[list | None] = mapped_column(JSON, nullable=True)
# 真人素材库图片总量限制。0 表示关闭真人素材模块;>0 表示启用并限制用户所有真人素材图片总量。
private_portrait_image_limit: Mapped[int] = mapped_column(
# 私域人像素材总量限制。0 表示关闭模块;>0 表示启用并限制真人/虚拟、图片/视频素材总量。
private_portrait_asset_limit: Mapped[int] = mapped_column(
Integer, default=5, server_default="5", nullable=False
)