diff --git a/packages/shared/ai_service.py b/packages/shared/ai_service.py index c4a02a0fa..2550fb060 100755 --- a/packages/shared/ai_service.py +++ b/packages/shared/ai_service.py @@ -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, }