60 lines
3.1 KiB
Python
60 lines
3.1 KiB
Python
from __future__ import annotations
|
||
|
||
from copy import deepcopy
|
||
from typing import Any
|
||
|
||
from fastapi import HTTPException
|
||
from sqlalchemy import select
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from app.enums.private_portrait import PRIVATE_PORTRAIT_ASSET_URI_PREFIX, PrivatePortraitAssetStatus, PrivatePortraitEventSource, PrivatePortraitEventStatus, PrivatePortraitEventType, PrivatePortraitReferenceSource
|
||
from app.models.private_portrait import PrivatePortraitAsset
|
||
from app.services.operation_log_service import log_operation_event
|
||
|
||
DOMAIN = "private_portrait"
|
||
|
||
|
||
def _ref_get(ref: Any, key: str) -> Any:
|
||
if isinstance(ref, dict):
|
||
return ref.get(key)
|
||
return getattr(ref, key, None)
|
||
|
||
|
||
def _ref_set(ref: Any, key: str, value: Any) -> None:
|
||
if isinstance(ref, dict):
|
||
ref[key] = value
|
||
else:
|
||
setattr(ref, key, value)
|
||
|
||
|
||
async def resolve_private_portrait_references(db: AsyncSession, *, user_id: str, media_references: list[Any] | None) -> list[Any] | None:
|
||
if not media_references:
|
||
return media_references
|
||
refs = deepcopy(media_references)
|
||
ids = [str(_ref_get(ref, "private_asset_id")) for ref in refs if _ref_get(ref, "source") == PrivatePortraitReferenceSource.PRIVATE_PORTRAIT_ASSET.value and _ref_get(ref, "private_asset_id")]
|
||
ids = list(dict.fromkeys(ids))
|
||
if not ids:
|
||
return refs
|
||
log_operation_event(domain=DOMAIN, event_type=PrivatePortraitEventType.REFERENCE_RESOLVE_START.value, event_status=PrivatePortraitEventStatus.PENDING.value, source=PrivatePortraitEventSource.SERVICE.value, user_id=user_id, detail={"private_asset_ids": ids})
|
||
rows = await db.execute(select(PrivatePortraitAsset).where(PrivatePortraitAsset.id.in_(ids)))
|
||
asset_map = {asset.id: asset for asset in rows.scalars().all()}
|
||
for ref in refs:
|
||
if _ref_get(ref, "source") != PrivatePortraitReferenceSource.PRIVATE_PORTRAIT_ASSET.value:
|
||
continue
|
||
asset_id = str(_ref_get(ref, "private_asset_id") or "")
|
||
asset = asset_map.get(asset_id)
|
||
if not asset:
|
||
raise HTTPException(status_code=400, detail="真人素材不存在")
|
||
if asset.user_id != user_id:
|
||
raise HTTPException(status_code=403, detail="真人素材不属于当前用户")
|
||
if asset.deleted_at is not None:
|
||
raise HTTPException(status_code=400, detail="真人素材已删除")
|
||
if asset.status != PrivatePortraitAssetStatus.ACTIVE.value:
|
||
raise HTTPException(status_code=400, detail=f"真人素材状态为 {asset.status},Active 后才可用于生成")
|
||
if not asset.remote_asset_id:
|
||
raise HTTPException(status_code=400, detail="真人素材缺少远程 AssetId")
|
||
_ref_set(ref, "remote_asset_id", asset.remote_asset_id)
|
||
_ref_set(ref, "url", f"{PRIVATE_PORTRAIT_ASSET_URI_PREFIX}{asset.remote_asset_id}")
|
||
log_operation_event(domain=DOMAIN, event_type=PrivatePortraitEventType.REFERENCE_RESOLVE_SUCCESS.value, event_status=PrivatePortraitEventStatus.SUCCESS.value, source=PrivatePortraitEventSource.SERVICE.value, user_id=user_id, detail={"count": len(ids)})
|
||
return refs
|