From bf6d02f26f51f210767f683354a7eef9b4121bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=81=B5=E5=BA=94?= Date: Thu, 10 Sep 2026 15:33:07 +0800 Subject: [PATCH] =?UTF-8?q?fix(ai-avatar):=20=E6=A0=87=E9=A2=98=E5=88=86?= =?UTF-8?q?=E8=A1=8C/=E5=B0=81=E9=9D=A2=E7=AD=BE=E5=90=8DURL/=E6=B8=B2?= =?UTF-8?q?=E6=9F=93b=5Froll=E7=BB=93=E6=9E=84=E5=AF=B9=E9=BD=90=E5=90=8E?= =?UTF-8?q?=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 标题 / 分行: 对齐智能剪辑 FrontendPreviewPlayer 的 split(/[//]/) 逻辑,/ 和 / 都会分行 2. 封面签名URL: 私有桶 OSS upload 后必须 get_download_url 签名,否则前端无法加载 3. 渲染 b_roll_segments 结构: 前端 {asset: AssetItem} 转后端 {asset_url: string},对齐 BRollSegment schema 4. #1821 对口型加速工单已关闭(收益有限,MediaKit GPU 排队是主要瓶颈) --- apps/api/app/services/ai_avatar_cover_service.py | 6 +++++- apps/web/src/pages/ai-avatar/AiAvatarPage.tsx | 10 +++++++++- .../ai-avatar/components/PanelLipsyncPreview.tsx | 12 ++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/apps/api/app/services/ai_avatar_cover_service.py b/apps/api/app/services/ai_avatar_cover_service.py index df0bd40aa..6e92d7ded 100644 --- a/apps/api/app/services/ai_avatar_cover_service.py +++ b/apps/api/app/services/ai_avatar_cover_service.py @@ -139,7 +139,11 @@ def persist_cover_to_oss(frame_url: str, *, job_id: str = "", prefix: str = "ai- content_type="image/jpeg", ) logger.info("[数字人封面] 封面已转存 OSS: key=%s", cover_key) - return public_url or frame_url + # 私有桶:返回预签名 URL(前端才能加载) + if public_url: + signed = storage.get_download_url(cover_key, expires_seconds=86400) + return signed + return frame_url except Exception: logger.warning("[数字人封面] 封面转存 OSS 失败,返回原始 URL", exc_info=True) return frame_url diff --git a/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx b/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx index 7c5114a5f..2c6f30122 100644 --- a/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx +++ b/apps/web/src/pages/ai-avatar/AiAvatarPage.tsx @@ -197,7 +197,15 @@ const AiAvatarPage: React.FC = () => { await submitRender({ lipsync_job_id: state.lipsyncJob.id, script_id: state.script?.id, - b_roll_segments: state.bRollSegments as never, + b_roll_segments: state.bRollSegments.map((seg) => ({ + script_segment_index: seg.script_segment_index, + asset_url: seg.asset.file_url || "", + mode: seg.mode, + start_time: seg.start_time, + end_time: seg.end_time, + pip_position: seg.pip_position, + pip_scale: seg.pip_scale, + })) as never, // 字段映射:build_title_drawtext_filter 真实口径 text/font_size/font_color/position/... title_config: buildTitleConfigPayload(state.titleConfig), // cover_config:智能封面 cover_url + 截帧 timestamp diff --git a/apps/web/src/pages/ai-avatar/components/PanelLipsyncPreview.tsx b/apps/web/src/pages/ai-avatar/components/PanelLipsyncPreview.tsx index 920a51f40..845403ad2 100755 --- a/apps/web/src/pages/ai-avatar/components/PanelLipsyncPreview.tsx +++ b/apps/web/src/pages/ai-avatar/components/PanelLipsyncPreview.tsx @@ -56,7 +56,6 @@ export function PanelLipsyncPreview({ fontSize: `${(titleConfig.size || 36) * 0.55}px`, // 预览等比缩 fontWeight: titleConfig.bold ? 700 : 400, fontStyle: titleConfig.italic ? "italic" : "normal", - whiteSpace: "pre-wrap", textAlign: "center", width: "90%", padding: "4px 8px", @@ -142,7 +141,16 @@ export function PanelLipsyncPreview({ {isDone && lipsyncJob?.output_video_url ? (
) : isGenerating ? (