Files
video-gen/video-gen-api/app/services/private_portrait/reference_resolver.py
T
2026-07-06 15:13:41 +08:00

60 lines
3.1 KiB
Python
Raw 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 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