76 lines
3.2 KiB
Python
76 lines
3.2 KiB
Python
from datetime import datetime, UTC
|
||
from enum import Enum
|
||
from typing import Optional, Any, List
|
||
|
||
from pydantic import BaseModel, computed_field, Field, model_validator
|
||
|
||
|
||
class AssetContentType(str, Enum):
|
||
IMAGE = 'image'
|
||
PROMPT = 'prompt'
|
||
VIDEO = 'video'
|
||
|
||
class AssetType(str, Enum):
|
||
UPLOADED = 'uploaded'
|
||
GENERATED = 'generated'
|
||
INSPIRATION = 'inspiration'
|
||
|
||
|
||
class Asset(BaseModel):
|
||
id: Optional[str] = None
|
||
name: str
|
||
type: AssetType = AssetType.GENERATED
|
||
content_type: AssetContentType = AssetContentType.IMAGE
|
||
linked_char_id: Optional[str] = None
|
||
data: Optional[bytes] = None
|
||
tg_doc_file_id: Optional[str] = None
|
||
tg_photo_file_id: Optional[str] = None
|
||
minio_object_name: Optional[str] = None
|
||
minio_bucket: Optional[str] = None
|
||
minio_thumbnail_object_name: Optional[str] = None
|
||
thumbnail: Optional[bytes] = None
|
||
tags: List[str] = []
|
||
created_by: Optional[str] = None
|
||
project_id: Optional[str] = None
|
||
is_deleted: bool = False
|
||
created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
||
updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
||
|
||
@model_validator(mode='before')
|
||
@classmethod
|
||
def check_legacy_type(cls, data: Any) -> Any:
|
||
if isinstance(data, dict):
|
||
# Если поле type содержит старые значения ("image", "prompt"),
|
||
# переносим их в content_type, а type ставим по умолчанию (GENERATED)
|
||
# или пытаемся угадать.
|
||
# Но по задаче мы дефолтим в GENERATED, и script'ом поправим.
|
||
|
||
raw_type = data.get('type')
|
||
if raw_type in ['image', 'prompt']:
|
||
data['content_type'] = raw_type
|
||
# Если в базе нет нового поля type, оно встанет в default=GENERATED
|
||
# Чтобы не вызывало ошибку валидации AssetType, меняем его или удаляем,
|
||
# полагаясь на default.
|
||
# Но если мы просто удалим, поле type примет дефолтное значение.
|
||
# Однако, если мы хотим явно отличить, можно ничего не делать,
|
||
# но тогда валидация поля `type` упадет, т.к. "image" != "generated".
|
||
# Поэтому удаляем старое значение из type, чтобы сработал дефолт.
|
||
if 'type' in data:
|
||
del data['type']
|
||
|
||
# Если content_type нет в данных (легаси), пытаемся его восстановить из удалённого type
|
||
# (выше мы его переложили).
|
||
|
||
return data
|
||
|
||
# --- CALCULATED FIELD ---
|
||
@computed_field
|
||
@property
|
||
def url(self) -> str:
|
||
"""
|
||
Это поле автоматически вычислится и попадет в model_dump() / .json()
|
||
"""
|
||
if self.id:
|
||
return f"/assets/{self.id}"
|
||
return ""
|