"""按 Asset id 批量生成 COS 签名 URL(解析正文 asset://)。""" from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.core.config import settings from app.core.logging import get_logger from app.features.asset.models import Asset from app.features.memoir.memoir_images.storage import ( CosDownloadUrlError, TencentCosStorageService, ) logger = get_logger(__name__) async def signed_urls_for_asset_ids( db: AsyncSession, asset_ids: set[str] ) -> dict[str, str]: """返回 asset_id -> 短期可访问 URL;签名失败则跳过该 id。""" if not asset_ids: return {} stmt = select(Asset).where(Asset.id.in_(asset_ids)) result = await db.execute(stmt) rows = list(result.scalars().all()) storage = TencentCosStorageService.from_settings(settings) out: dict[str, str] = {} for a in rows: key = (a.storage_key or "").strip() if not key: continue try: out[a.id] = storage.get_download_url(key) except CosDownloadUrlError as exc: logger.warning( "Asset 签名失败: id=%s key=%s retryable=%s error=%s", a.id, key, exc.retryable, exc, ) except Exception as exc: logger.warning("Asset 签名失败: id=%s error=%s", a.id, exc) return out