diff --git a/apps/web/src/api/generation/cover.ts b/apps/web/src/api/generation/cover.ts index 3a230220d..8bf308d1e 100644 --- a/apps/web/src/api/generation/cover.ts +++ b/apps/web/src/api/generation/cover.ts @@ -12,7 +12,14 @@ export interface GenerateCoverTitleConfig { } export interface GenerateCoverRequest { - asset_ids: string[] + /** + * 封面源视频标识(二选一): + * - generated_video_id:确认生成任务产出的最终视频 ID + * - video_url:最终视频 URL(兜底) + * 后端根据此标识定位最终成片文件并抽帧,MediaKit 选帧逻辑不变 + */ + generated_video_id?: string + video_url?: string cover_type?: "ai_frame" | "manual" | "upload" | "ai_regenerate" frame_time?: number /** 标题样式,用于在封面上叠加标题文字 */ @@ -31,7 +38,7 @@ export interface GenerateCoverResponse { } } -/** AI 生成封面 — 从预览视频中抽帧 */ +/** AI 生成封面 — 从最终成片中抽帧(MediaKit 选帧) */ export async function generateCover( templateId: string, data: GenerateCoverRequest, diff --git a/apps/web/src/pages/generate/GeneratePage.tsx b/apps/web/src/pages/generate/GeneratePage.tsx index f27a2a8fd..8d47b17e5 100644 --- a/apps/web/src/pages/generate/GeneratePage.tsx +++ b/apps/web/src/pages/generate/GeneratePage.tsx @@ -1,11 +1,11 @@ /** * 智能剪辑页面 — 前端实时预览架构 - * 6 步向导:选择模板 → 素材 → 配音 → 标题(含预览) → 封面 → 确认生成 - * 左右布局:左侧 generate-form + 右侧 generate-preview + * 6 步向导:选择模板 → 素材 → 配音 → 标题(含预览) → 确认生成 → 选择封面 * * 架构: - * - 步骤 4-5 右侧显示 FrontendPreviewPlayer 实时预览 - * - 步骤 6 右侧内联播放生成的最终视频 + * - 步骤 4 右侧显示 FrontendPreviewPlayer 实时预览 + * - 步骤 5 右侧内联播放生成中的/最终视频 + * - 步骤 6 封面从最终成片中智能选帧(MediaKit) * - 点"确认生成"时调用 createGenerationTask 创建一次服务器渲染任务 */ import React, { useMemo, useState, useEffect, useRef } from "react" @@ -181,18 +181,6 @@ const GeneratePage: React.FC = () => { return estimateTotalVideoDuration(currentTemplate ?? undefined) }, [previewAssets, currentTemplate]) - /* ── 步骤导航 ── */ - const { goNext, goPrev } = useStepNavigation({ - currentStep, - setCurrentStep, - selectedTemplate, - materialMode, - selectedMaterials, - smartSelectedIds, - titleSettings, - previewReady, - }) - /* ── 视频生成核心逻辑 ── */ const { generating, @@ -229,6 +217,22 @@ const GeneratePage: React.FC = () => { }, }) + /* ── 步骤导航 ── */ + const { goNext, goPrev } = useStepNavigation({ + currentStep, + setCurrentStep, + selectedTemplate, + materialMode, + selectedMaterials, + smartSelectedIds, + titleSettings, + previewReady, + generated, + }) + + /* ── 最终成片(步骤5/6 右侧播放) ── */ + const finalVideo = generatedVideos[0] + /* ================================================================ 渲染 ================================================================ */ @@ -265,13 +269,10 @@ const GeneratePage: React.FC = () => { onApplyPreset={styleUpdaters.applyPreset} activePreset={styleUpdaters.activePreset} titlePresets={styleUpdaters.titlePresets} - onPreviewTaskCreated={setPreviewTaskId} - onSourceEditPlanIdExtracted={setStoredSourceEditPlanId} bgm={bgm} bgmConfig={bgmConfig} coverSettings={coverSettings} onCoverSettingsChange={setCoverSettings} - duration={duration} selectedVoice={selectedVoice} onSelectedVoiceChange={setSelectedVoice} totalVideoDuration={totalVideoDuration} @@ -306,9 +307,9 @@ const GeneratePage: React.FC = () => { /> - {/* ════ 右侧:步骤 4-5 实时预览,步骤 6 最终视频 ════ */} + {/* ════ 右侧:步骤4实时预览,步骤5/6最终视频 ════ */}
- {currentStep >= 4 && currentStep <= 5 && !!currentTemplate && ( + {currentStep === 4 && !!currentTemplate && ( { }} /> )} - {currentStep === 6 && generated && generatedVideos.length > 0 && ( + {currentStep >= 5 && generated && finalVideo && (