fix: 封面预览 broken image — MediaKit帧图转存OSS返回公开URL
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m15s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m30s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m33s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m0s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m4s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m15s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 2m30s
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m33s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 3m0s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m4s
CI/CD Pipeline / Validate - Code Quality (push) Has been cancelled
CI/CD Pipeline / Unit Tests (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Staging API Image (push) Has been cancelled
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Has been cancelled
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Staging API Integration Tests (push) Has been cancelled
CI/CD Pipeline / Build Production API Image (push) Has been cancelled
CI/CD Pipeline / Build Production Web Image (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Has been cancelled
CI/CD Pipeline / Deploy Production (push) Has been cancelled
CI/CD Pipeline / Production Browser E2E (push) Has been cancelled
CI/CD Pipeline / ACR Image Cleanup (push) Has been cancelled
CI/CD Pipeline / Canary Release to Production (push) Has been cancelled
CI/CD Pipeline / CI Gate (push) Has been cancelled
根因:MediaKit extract_frames 返回的 image_url 是内部临时 URL, 浏览器无法直接访问,导致封面预览显示 broken image。 修复:新增 _transfer_cover_frame_to_storage(),在 MediaKit 抽帧 成功后下载帧图并重新上传到 OSS,返回公开可访问的 URL。 失败时降级返回原始 URL(不影响流程)。 78个相关单测全部通过。
This commit is contained in:
@@ -296,6 +296,62 @@ def _call_ai_recommend_service(
|
||||
# ── AI 封面生成 ──────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
def _transfer_cover_frame_to_storage(frame_url: str, plan_id: str) -> str:
|
||||
"""下载 MediaKit 帧图并上传到 OSS,返回公开可访问的 URL.
|
||||
|
||||
Args:
|
||||
frame_url: MediaKit 返回的帧图 URL(内部/临时 URL)
|
||||
plan_id: 剪辑计划 ID(用于生成存储路径)
|
||||
|
||||
Returns:
|
||||
公开可访问的 URL;如果下载/上传失败则返回原始 URL
|
||||
"""
|
||||
import tempfile
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import httpx
|
||||
|
||||
# 下载帧图
|
||||
logger.info("下载 MediaKit 帧图: plan_id=%s url=%s", plan_id, frame_url[:80])
|
||||
resp = httpx.get(frame_url, timeout=30, follow_redirects=True)
|
||||
resp.raise_for_status()
|
||||
|
||||
if not resp.content:
|
||||
logger.warning("MediaKit 帧图下载为空,返回原始 URL")
|
||||
return frame_url
|
||||
|
||||
# 写入临时文件
|
||||
with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
|
||||
tmp.write(resp.content)
|
||||
tmp_path = tmp.name
|
||||
|
||||
# 上传到 OSS
|
||||
from packages.shared.storage import get_shared_storage_service
|
||||
storage = get_shared_storage_service()
|
||||
cover_key = f"covers/{plan_id}/mediakit_frame_{uuid.uuid4().hex[:8]}.jpg"
|
||||
storage.upload_file(
|
||||
file_or_path=tmp_path,
|
||||
storage_key=cover_key,
|
||||
content_type="image/jpeg",
|
||||
)
|
||||
|
||||
# 获取公开 URL
|
||||
public_url = storage.get_url(cover_key)
|
||||
logger.info("封面帧图已上传到 OSS: plan_id=%s key=%s url=%s", plan_id, cover_key, public_url[:80])
|
||||
|
||||
# 清理临时文件
|
||||
Path(tmp_path).unlink(missing_ok=True)
|
||||
|
||||
return public_url
|
||||
|
||||
except Exception as e:
|
||||
logger.warning("封面帧图转存失败,返回原始 URL: %s", str(e))
|
||||
return frame_url
|
||||
|
||||
|
||||
def _call_ai_cover_service(
|
||||
plan_id: str,
|
||||
asset_ids: List[str],
|
||||
@@ -363,9 +419,12 @@ def _call_ai_cover_service(
|
||||
timestamp,
|
||||
image_url[:80],
|
||||
)
|
||||
# MediaKit 返回的 URL 是临时内部 URL,浏览器无法直接访问
|
||||
# 需要下载到本地并重新上传到 OSS,返回公开可访问的 URL
|
||||
public_url = _transfer_cover_frame_to_storage(image_url, plan_id)
|
||||
return {
|
||||
"type": "ai_frame",
|
||||
"image_url": image_url,
|
||||
"image_url": public_url,
|
||||
"frame_time": round(timestamp, 1),
|
||||
"confidence": 0.85,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user