Files
root 0c511f3451 1、增加调用 AI 视频生成能力和虚拟素材库管理的对外api
2、增加后台apikkey管理
3、增加apikey单独的模型定价
4、增加apikey调用情况
5、完善所有数据的注释增加
2026-08-06 13:13:28 +08:00

96 lines
4.8 KiB
Python
Raw Permalink 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.
from __future__ import annotations
from datetime import datetime
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,
PrivatePortraitRemoteDeleteStatus,
)
from app.models.base import Base, SoftDeleteMixin, TimestampMixin
class VpV3Asset(Base, TimestampMixin, SoftDeleteMixin):
"""API V3 虚拟素材(图片/视频),归属某个 Project=火山 1 个 AssetGroup)。
字段语义和 private_portrait.PrivatePortraitAsset 保持一致,便于 service 层复用逻辑。
"""
__tablename__ = "vp_v3_assets"
__table_args__ = (
Index("uq_vp_v3_assets_remote_asset_id", "remote_asset_id", unique=True),
Index("idx_vp_v3_assets_key_status_created", "api_key_id", "status", "created_at"),
Index("idx_vp_v3_assets_project_status_created", "project_id", "status", "created_at"),
Index(
"idx_vp_v3_assets_next_poll_status",
"next_poll_at",
"status",
postgresql_where=text("deleted_at IS NULL AND next_poll_at IS NOT NULL"),
),
Index("idx_vp_v3_assets_remote_delete_status", "remote_delete_status"),
Index("idx_vp_v3_assets_asset_type", "asset_type"),
)
id: Mapped[str] = mapped_column(String(32), primary_key=True)
api_key_id: Mapped[str] = mapped_column(
String(32), ForeignKey("api_keys.id", ondelete="CASCADE"), nullable=False, index=True,
)
project_id: Mapped[str] = mapped_column(
String(32), ForeignKey("vp_v3_projects.id", ondelete="CASCADE"), nullable=False, index=True,
)
# 火山远端映射
remote_project_name: Mapped[str] = mapped_column(String(256), nullable=False, 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)
# 素材元信息
asset_type: Mapped[str] = mapped_column(
String(16), nullable=False, default=PrivatePortraitAssetType.IMAGE.value, index=True,
comment="素材类型:Image=图片 / Video=视频",
)
name: Mapped[str | None] = mapped_column(String(128), nullable=True, index=True)
# 资源 URL
source_url: Mapped[str] = mapped_column(Text, nullable=False, comment="本地上传后的访问 URLUploadResource 返回的)")
preview_url: Mapped[str | None] = mapped_column(Text, nullable=True, comment="给前端预览/显示用的 URL(签名 URL 可能过期)")
remote_url: Mapped[str | None] = mapped_column(Text, nullable=True, comment="火山返回的资源访问 URL(可能带签名和过期)")
remote_url_expired_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
upload_resource_id: Mapped[str | None] = mapped_column(
String(32), nullable=True, index=True, comment="本地 UploadResource 账本 resource_id(容量释放用)",
)
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_bytes: 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,
default=PrivatePortraitAssetStatus.CREATING.value,
server_default=PrivatePortraitAssetStatus.CREATING.value,
index=True,
comment="素材状态:creating/审核中 active/可用 failed/失败 deleting/删除中",
)
moderation_json: Mapped[str | None] = mapped_column(Text, nullable=True, comment="火山审核结果 JSON")
error_message: Mapped[str | None] = mapped_column(Text, nullable=True, comment="失败原因")
raw_response_json: Mapped[str | None] = mapped_column(Text, nullable=True, comment="火山原始响应 JSON")
# 轮询控制(异步审核)
last_poll_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
next_poll_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True, index=True)
poll_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0, server_default="0")
# 远端删除
remote_delete_status: Mapped[str] = mapped_column(
String(32), nullable=False,
default=PrivatePortraitRemoteDeleteStatus.NONE.value,
server_default=PrivatePortraitRemoteDeleteStatus.NONE.value,
index=True,
)
remote_deleted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
remote_delete_error: Mapped[str | None] = mapped_column(Text, nullable=True)