diff --git a/apps/web/src/api/viral-video/types.ts b/apps/web/src/api/viral-video/types.ts index 1ea182f55..01d7c894e 100644 --- a/apps/web/src/api/viral-video/types.ts +++ b/apps/web/src/api/viral-video/types.ts @@ -1,8 +1,8 @@ -export type FusionLevel = "full_ai" | "polish" | "as_is" +export type FusionLevel = "ai_full" | "ai_polish" | "user_primary" export const FUSION_LEVELS: { value: FusionLevel; label: string; desc: string }[] = [ - { value: "full_ai", label: "AI 全写", desc: "给我方向,全由AI创作" }, - { value: "polish", label: "AI润色", desc: "我写草稿,AI帮我润色" }, - { value: "as_is", label: "按我写的来", desc: "几乎不改我的文案" }, + { value: "ai_full", label: "AI 全写", desc: "给我方向,全由AI创作" }, + { value: "ai_polish", label: "AI润色", desc: "我写草稿,AI帮我润色" }, + { value: "user_primary", label: "按我写的来", desc: "几乎不改我的文案" }, ] export type StyleStrength = "light" | "medium" | "strict" @@ -16,8 +16,8 @@ export type ViralVideoStatus = "pending" | "running" | "wait_user_confirm" | "completed" | "failed" | "cancelled" /** - * 前端展示的流水线阶段(已移除 muse talk 口型同步;后端枚举保留字段以兼容旧数据,不展示)。 - * 百分比对齐后端 worker _emit_progress 的真实值。 + * 后端流水线阶段字符串。前端不展示逐阶段进度列表,仅保留类型 + * 用于轮询时判断当前在哪个大阶段(分析中 vs 视频生成中)以选择轮询间隔/文案。 */ export type ViralVideoStage = | "image_analysis" @@ -29,40 +29,19 @@ export type ViralVideoStage = | "tts" | "bgm_select" | "rendering" + | "musetalk" | "uploading" -export interface StageDisplay { - label: string - /** 该阶段完成时到达的总体进度百分比 */ - pct: number -} - -export const STAGE_DISPLAYS: Record = { - image_analysis: { label: "图片分析", pct: 15 }, - video_analysis: { label: "参考视频风格分析", pct: 20 }, - intent_parsing: { label: "意图理解", pct: 30 }, - copy_fusion: { label: "文案融合创作", pct: 50 }, - storyboard: { label: "分镜生成", pct: 60 }, - review: { label: "AI审核", pct: 70 }, - tts: { label: "配音生成", pct: 75 }, - bgm_select: { label: "BGM匹配", pct: 78 }, - rendering: { label: "视频渲染", pct: 88 }, - uploading: { label: "上传成片", pct: 100 }, -} - -/** 阶段顺序(用于进度列表渲染) */ -export const STAGE_ORDER: ViralVideoStage[] = [ +/** 分析类阶段(image_analysis / video_analysis / intent_parsing):属于「开始分析」阶段 */ +const ANALYSIS_STAGES = new Set([ "image_analysis", "video_analysis", "intent_parsing", - "copy_fusion", - "storyboard", - "review", - "tts", - "bgm_select", - "rendering", - "uploading", -] +]) + +export function isAnalysisStage(stage: ViralVideoStage | undefined): boolean { + return !!stage && ANALYSIS_STAGES.has(stage) +} export interface StyleTemplate { id: string diff --git a/apps/web/src/pages/viral-video/ViralVideoPage.css b/apps/web/src/pages/viral-video/ViralVideoPage.css index 72f60b29b..074204928 100644 --- a/apps/web/src/pages/viral-video/ViralVideoPage.css +++ b/apps/web/src/pages/viral-video/ViralVideoPage.css @@ -639,57 +639,6 @@ font-size: 12px; } -/* ── 阶段进度列表 ──────────────────────────────────── */ -.vv-stages { - display: flex; - flex-direction: column; - gap: 4px; - margin-top: 8px; -} -.vv-stage { - display: flex; - align-items: center; - gap: 10px; - font-size: 12px; - color: #9ca3af; - padding: 5px 0; -} -.vv-stage-dot { - width: 16px; - height: 16px; - border-radius: 50%; - border: 2px solid #e5e7eb; - display: flex; - align-items: center; - justify-content: center; - font-size: 9px; - background: #fff; - flex-shrink: 0; -} -.vv-stage.active { - color: #7c3aed; -} -.vv-stage.active .vv-stage-dot { - border-color: #7c3aed; - background: #f3f0ff; -} -.vv-stage.done { - color: #10b981; -} -.vv-stage.done .vv-stage-dot { - border-color: #10b981; - background: #10b981; - color: #fff; -} -.vv-stage.failed { - color: #ef4444; -} -.vv-stage.failed .vv-stage-dot { - border-color: #ef4444; - background: #ef4444; - color: #fff; -} - .vv-progress-bar { width: 100%; height: 6px; diff --git a/apps/web/src/pages/viral-video/ViralVideoPage.tsx b/apps/web/src/pages/viral-video/ViralVideoPage.tsx index 8b498e5eb..b0e9763a0 100644 --- a/apps/web/src/pages/viral-video/ViralVideoPage.tsx +++ b/apps/web/src/pages/viral-video/ViralVideoPage.tsx @@ -8,7 +8,6 @@ import { CaretDownOutlined, VideoCameraOutlined, SoundOutlined, - CheckOutlined, ReloadOutlined, WarningFilled, BulbFilled, @@ -20,12 +19,10 @@ import { uploadAssetDirect, getAssetLibraries, getAssetsByKind } from "@/api/ass import { FUSION_LEVELS, STYLE_STRENGTHS, - STAGE_DISPLAYS, - STAGE_ORDER, + isAnalysisStage, type FusionLevel, type StyleStrength, type ViralVideoJob, - type ViralVideoStage, } from "@/api/viral-video/types" import { generateViralVideo, confirmViralVideoIntent, retryViralVideo } from "@/api/viral-video" import { useViralVideoPolling } from "./hooks/useViralVideoPolling" @@ -124,7 +121,7 @@ const emptyTask = (id: string, title: string): TabTask => ({ title, images: [], refVideo: null, - fusionLevel: "full_ai", + fusionLevel: "ai_full", styleStrength: "medium", voiceId: "", userCopy: "", @@ -428,7 +425,7 @@ const ViralVideoPage: React.FC = () => { images: imgUrls, reference_video_url: task.refVideo?.ossUrl || undefined, style_strength: task.refVideo?.ossUrl ? task.styleStrength : undefined, - user_copy_text: task.fusionLevel !== "full_ai" ? task.userCopy : undefined, + user_copy_text: task.fusionLevel !== "ai_full" ? task.userCopy : undefined, fusion_level: task.fusionLevel, // 注意:STEP1「开始分析」阶段还没有真正开始生成视频,后端会跑到 WAIT_USER_CONFIRM 暂停。 // 配音和视频参数在 STEP2 确认文案时由 confirm-intent 继续使用;但后端接口目前只接收一次 payload, @@ -517,30 +514,11 @@ const ViralVideoPage: React.FC = () => { task.job.status === "running" && !isAwaitingConfirm && !task.generating && - (!task.job.progress_stage || - ["image_analysis", "video_analysis", "intent_parsing"].includes(task.job.progress_stage))) + (!task.job.progress_stage || isAnalysisStage(task.job.progress_stage))) const isGenerating = - task.generating || - (task.job?.status === "running" && - task.job.progress_stage && - !["image_analysis", "video_analysis", "intent_parsing"].includes(task.job.progress_stage)) + task.generating || (task.job?.status === "running" && !isAnalysisStage(task.job.progress_stage)) const isDone = task.job?.status === "completed" const isFailed = task.job?.status === "failed" - const progressPct = task.job?.progress_percent ?? 0 - const currentStage: ViralVideoStage | undefined = task.job?.progress_stage as - ViralVideoStage | undefined - - /* ── 阶段列表派生显示状态 ── */ - const stageState = (s: ViralVideoStage): "pending" | "active" | "done" | "failed" => { - if (isFailed && s === currentStage) return "failed" - if (isDone) return "done" - if (!currentStage) return "pending" - const cur = STAGE_DISPLAYS[currentStage].pct - const mine = STAGE_DISPLAYS[s].pct - if (s === currentStage) return "active" - if (mine < cur) return "done" - return "pending" - } return (
@@ -838,14 +816,14 @@ const ViralVideoPage: React.FC = () => {