forked from 77media/video-flow
优化
This commit is contained in:
parent
90fb57f0fd
commit
7d6c60ac42
@ -1,5 +1,5 @@
|
||||
"use client"
|
||||
import React, { useRef, useEffect } from "react";
|
||||
import React, { useRef, useEffect, useCallback } from "react";
|
||||
import "./style/work-flow.css";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { AISuggestionBar } from "@/components/ai-suggestion-bar";
|
||||
@ -16,7 +16,7 @@ import { GlassIconButton } from '@/components/ui/glass-icon-button';
|
||||
import { SaveEditUseCase } from "@/app/service/usecase/SaveEditUseCase";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
export default function WorkFlow() {
|
||||
const WorkFlow = React.memo(function WorkFlow() {
|
||||
console.log('WorkFlow--0294877777777777')
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [isEditModalOpen, setIsEditModalOpen] = React.useState(false);
|
||||
@ -85,7 +85,7 @@ export default function WorkFlow() {
|
||||
sketchCount,
|
||||
totalSketchCount
|
||||
});
|
||||
}, [isGeneratingSketch, taskSketch.length, sketchCount, totalSketchCount, currentStep, isPlaying]);
|
||||
}, [currentStep, isGeneratingSketch, isGeneratingVideo, isPlaying, taskSketch.length, sketchCount, totalSketchCount]);
|
||||
|
||||
// 专门监控isPlaying状态变化
|
||||
useEffect(() => {
|
||||
@ -108,18 +108,18 @@ export default function WorkFlow() {
|
||||
"Adjust lens language"
|
||||
];
|
||||
|
||||
const handleEditModalOpen = (tab: string) => {
|
||||
const handleEditModalOpen = useCallback((tab: string) => {
|
||||
setActiveEditTab(tab);
|
||||
setIsEditModalOpen(true);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSuggestionClick = (suggestion: string) => {
|
||||
const handleSuggestionClick = useCallback((suggestion: string) => {
|
||||
console.log('Selected suggestion:', suggestion);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSubmit = (text: string) => {
|
||||
const handleSubmit = useCallback((text: string) => {
|
||||
console.log('Submitted text:', text);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
@ -239,7 +239,7 @@ export default function WorkFlow() {
|
||||
icon={isPauseWorkFlow ? Play : Pause}
|
||||
size='lg'
|
||||
tooltip={isPauseWorkFlow ? "Play" : "Pause"}
|
||||
onClick={() => setIsPauseWorkFlow(!isPauseWorkFlow)}
|
||||
onClick={useCallback(() => setIsPauseWorkFlow(!isPauseWorkFlow), [isPauseWorkFlow])}
|
||||
/>
|
||||
{ mode !== 'automatic' && (
|
||||
<GlassIconButton
|
||||
@ -289,4 +289,6 @@ export default function WorkFlow() {
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
export default WorkFlow;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import React, { useRef, useEffect, useState, SetStateAction } from 'react';
|
||||
import React, { useRef, useEffect, useState, SetStateAction, useMemo } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { Edit3, Play, Pause, Volume2, VolumeX, Maximize, Minimize } from 'lucide-react';
|
||||
import { ProgressiveReveal, presets } from '@/components/ui/progressive-reveal';
|
||||
@ -32,7 +32,7 @@ interface MediaViewerProps {
|
||||
mode: string;
|
||||
}
|
||||
|
||||
export function MediaViewer({
|
||||
export const MediaViewer = React.memo(function MediaViewer({
|
||||
scriptData,
|
||||
currentStep,
|
||||
currentSketchIndex,
|
||||
@ -146,6 +146,29 @@ export function MediaViewer({
|
||||
}
|
||||
};
|
||||
|
||||
// 使用 useMemo 缓存最终视频元素,避免重复创建和请求
|
||||
const memoizedFinalVideoElement = useMemo(() => {
|
||||
console.log('final', final);
|
||||
if (!final?.url) return null;
|
||||
|
||||
return (
|
||||
<video
|
||||
ref={finalVideoRef}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
src={final.url}
|
||||
autoPlay={isFinalVideoPlaying}
|
||||
loop
|
||||
playsInline
|
||||
preload="metadata"
|
||||
poster={`${final.url}?vframe/jpg/offset/1`}
|
||||
onLoadedData={handleFinalVideoLoaded}
|
||||
onPlay={() => setIsFinalVideoPlaying(true)}
|
||||
onPause={() => setIsFinalVideoPlaying(false)}
|
||||
onClick={handleVideoClick}
|
||||
/>
|
||||
);
|
||||
}, [final?.url, isFinalVideoPlaying, handleFinalVideoLoaded, handleVideoClick]);
|
||||
|
||||
// 包装编辑按钮点击事件
|
||||
const handleEditClick = (tab: string, from?: string) => {
|
||||
if (from === 'final') {
|
||||
@ -323,20 +346,7 @@ export function MediaViewer({
|
||||
}}
|
||||
className="relative z-10 w-full h-full"
|
||||
>
|
||||
<video
|
||||
ref={finalVideoRef}
|
||||
className="w-full h-full object-cover rounded-lg"
|
||||
src={finalVideo.url}
|
||||
autoPlay={isFinalVideoPlaying}
|
||||
loop
|
||||
playsInline
|
||||
preload="metadata"
|
||||
poster={`${finalVideo.url}?vframe/jpg/offset/1`}
|
||||
onLoadedData={handleFinalVideoLoaded}
|
||||
onPlay={() => setIsFinalVideoPlaying(true)}
|
||||
onPause={() => setIsFinalVideoPlaying(false)}
|
||||
onClick={handleVideoClick}
|
||||
/>
|
||||
{memoizedFinalVideoElement}
|
||||
</motion.div>
|
||||
|
||||
{/* 操作按钮组 */}
|
||||
@ -848,6 +858,7 @@ export function MediaViewer({
|
||||
|
||||
// 根据当前步骤渲染对应内容
|
||||
if (Number(currentStep) === 6 || Number(currentStep) === 5.5) {
|
||||
console.log('1111111111111111', 1111111111111111)
|
||||
return renderFinalVideo(currentStep);
|
||||
}
|
||||
|
||||
@ -860,4 +871,4 @@ export function MediaViewer({
|
||||
}
|
||||
|
||||
return renderSketchContent();
|
||||
}
|
||||
});
|
||||
|
||||
@ -200,7 +200,7 @@ export function useWorkflowData() {
|
||||
}, [isGeneratingSketch, taskSketch.length, autoPlaySketch]);
|
||||
|
||||
// 获取流式数据
|
||||
const fetchStreamData = async () => {
|
||||
const fetchStreamData = useCallback(async () => {
|
||||
if (!episodeId || !needStreamData) return;
|
||||
|
||||
try {
|
||||
@ -209,7 +209,6 @@ export function useWorkflowData() {
|
||||
throw new Error(response.message);
|
||||
}
|
||||
|
||||
|
||||
let sketchCount = 0;
|
||||
const all_task_data = response.data;
|
||||
// all_task_data 下标0 和 下标1 换位置
|
||||
@ -219,8 +218,24 @@ export function useWorkflowData() {
|
||||
|
||||
console.log('---look-all_task_data', all_task_data);
|
||||
console.log('---look-taskData', taskData);
|
||||
for (const task of all_task_data) {
|
||||
|
||||
// 收集所有需要更新的状态
|
||||
let stateUpdates: {
|
||||
taskSketch?: any[];
|
||||
taskScenes?: any[];
|
||||
taskShotSketch?: any[];
|
||||
roles?: any[];
|
||||
taskVideos?: any[];
|
||||
isGeneratingSketch?: boolean;
|
||||
isGeneratingVideo?: boolean;
|
||||
currentStep?: string;
|
||||
currentLoadingText?: string;
|
||||
final?: any;
|
||||
needStreamData?: boolean;
|
||||
totalSketchCount?: number;
|
||||
} = {};
|
||||
|
||||
for (const task of all_task_data) {
|
||||
// 如果有已完成的数据,同步到状态
|
||||
if (task.task_name === 'generate_sketch' && (task.task_status !== 'COMPLETED' || taskData.sketch.total_count !== taskData.sketch.data.length)) {
|
||||
taskData.status = '1';
|
||||
@ -235,24 +250,24 @@ export function useWorkflowData() {
|
||||
});
|
||||
}
|
||||
taskData.sketch.data = sketchList;
|
||||
setTaskSketch(sketchList);
|
||||
setTaskScenes(sketchList);
|
||||
updateSketchCount(sketchList.length);
|
||||
setIsGeneratingSketch(true);
|
||||
stateUpdates.taskSketch = sketchList;
|
||||
stateUpdates.taskScenes = sketchList;
|
||||
stateUpdates.isGeneratingSketch = true;
|
||||
stateUpdates.totalSketchCount = task.task_result.total_count;
|
||||
loadingText = LOADING_TEXT_MAP.sketch(sketchList.length, task.task_result.total_count);
|
||||
}
|
||||
if (task.task_status === 'COMPLETED') {
|
||||
// 草图生成完成
|
||||
taskData.sketch.total_count = taskData.sketch.data.length;
|
||||
setIsGeneratingSketch(false);
|
||||
stateUpdates.isGeneratingSketch = false;
|
||||
sketchCount = task.task_result.total_count;
|
||||
console.log('----------草图生成完成', sketchCount);
|
||||
loadingText = LOADING_TEXT_MAP.sketchComplete;
|
||||
taskData.status = '2';
|
||||
}
|
||||
setTotalSketchCount(task.task_result.total_count);
|
||||
stateUpdates.currentStep = taskData.status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (task.task_name === 'generate_character' && (task.task_status !== 'COMPLETED' || taskData.character.total_count !== taskData.character.data.length)) {
|
||||
if (task.task_result.data.length >= 0 && roles.length !== task.task_result.data.length) {
|
||||
// 正在生成角色中 替换角色数据
|
||||
@ -267,7 +282,7 @@ export function useWorkflowData() {
|
||||
});
|
||||
}
|
||||
taskData.character.data = characterList;
|
||||
setRoles(characterList);
|
||||
stateUpdates.roles = characterList;
|
||||
loadingText = LOADING_TEXT_MAP.newCharacter(characterList.length, task.task_result.total_count);
|
||||
}
|
||||
if (task.task_status === 'COMPLETED') {
|
||||
@ -275,11 +290,12 @@ export function useWorkflowData() {
|
||||
// 角色生成完成
|
||||
taskData.character.total_count = taskData.character.data.length;
|
||||
taskData.status = '3';
|
||||
|
||||
loadingText = LOADING_TEXT_MAP.getShotSketchStatus;
|
||||
}
|
||||
stateUpdates.currentStep = taskData.status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (task.task_name === 'generate_shot_sketch' && (task.task_status !== 'COMPLETED' || taskData.shot_sketch.total_count !== taskData.shot_sketch.data.length)) {
|
||||
const realShotResultData = task.task_result.data.filter((item: any) => item.url);
|
||||
if (realShotResultData.length >= 0) {
|
||||
@ -294,25 +310,26 @@ export function useWorkflowData() {
|
||||
});
|
||||
}
|
||||
taskData.shot_sketch.data = sketchList;
|
||||
setTaskSketch(sketchList);
|
||||
setTaskShotSketch(sketchList);
|
||||
updateSketchCount(sketchList.length);
|
||||
setIsGeneratingSketch(true);
|
||||
stateUpdates.taskSketch = sketchList;
|
||||
stateUpdates.taskShotSketch = sketchList;
|
||||
stateUpdates.isGeneratingSketch = true;
|
||||
stateUpdates.totalSketchCount = task.task_result.total_count;
|
||||
loadingText = LOADING_TEXT_MAP.shotSketch(sketchList.length, task.task_result.total_count);
|
||||
}
|
||||
if (task.task_status === 'COMPLETED') {
|
||||
// 草图生成完成
|
||||
taskData.shot_sketch.total_count = taskData.shot_sketch.data.length;
|
||||
setIsGeneratingSketch(false);
|
||||
setIsGeneratingVideo(true);
|
||||
stateUpdates.isGeneratingSketch = false;
|
||||
stateUpdates.isGeneratingVideo = true;
|
||||
sketchCount = task.task_result.total_count;
|
||||
console.log('----------草图生成完成', sketchCount);
|
||||
loadingText = LOADING_TEXT_MAP.getVideoStatus;
|
||||
taskData.status = '3';
|
||||
}
|
||||
setTotalSketchCount(task.task_result.total_count);
|
||||
stateUpdates.currentStep = taskData.status;
|
||||
break;
|
||||
}
|
||||
|
||||
if (task.task_name === 'generate_videos' && (task.task_status !== 'COMPLETED' || taskData.video.total_count !== taskData.video.data.length)) {
|
||||
const realTaskResultData = task.task_result.data.filter((item: any) => item.urls && item.urls.length > 0);
|
||||
if (realTaskResultData.length >= 0) {
|
||||
@ -329,65 +346,90 @@ export function useWorkflowData() {
|
||||
});
|
||||
}
|
||||
taskData.video.data = videoList;
|
||||
setTaskVideos(videoList);
|
||||
updateVideoCount(videoList.length);
|
||||
setIsGeneratingVideo(true);
|
||||
stateUpdates.taskVideos = videoList;
|
||||
stateUpdates.isGeneratingVideo = true;
|
||||
loadingText = LOADING_TEXT_MAP.video(videoList.length, task.task_result.total_count);
|
||||
}
|
||||
if (task.task_status === 'COMPLETED') {
|
||||
console.log('----------视频生成完成');
|
||||
// 视频生成完成
|
||||
taskData.video.total_count = taskData.video.data.length;
|
||||
setIsGeneratingVideo(false);
|
||||
stateUpdates.isGeneratingVideo = false;
|
||||
taskData.status = '4';
|
||||
|
||||
// 暂时没有音频生成 直接跳过
|
||||
taskData.status = '5';
|
||||
loadingText = LOADING_TEXT_MAP.postProduction('generating rough cut video...');
|
||||
}
|
||||
stateUpdates.currentStep = taskData.status;
|
||||
break;
|
||||
}
|
||||
|
||||
// 粗剪
|
||||
if (task.task_name === 'generate_final_simple_video') {
|
||||
if (task.task_result && task.task_result.video) {
|
||||
setFinal({
|
||||
stateUpdates.final = {
|
||||
url: task.task_result.video,
|
||||
})
|
||||
};
|
||||
taskData.status = '5.5';
|
||||
loadingText = LOADING_TEXT_MAP.postProduction('generating fine-grained video clips...');
|
||||
}
|
||||
}
|
||||
|
||||
// 最终剪辑
|
||||
if (task.task_name === 'generate_final_video') {
|
||||
if (task.task_result && task.task_result.video) {
|
||||
setFinal({
|
||||
stateUpdates.final = {
|
||||
url: task.task_result.video,
|
||||
})
|
||||
};
|
||||
taskData.status = '6';
|
||||
loadingText = LOADING_TEXT_MAP.complete;
|
||||
|
||||
// 停止轮询
|
||||
setNeedStreamData(false);
|
||||
stateUpdates.needStreamData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('-----look-finalStep-----', taskData.status);
|
||||
// 设置步骤
|
||||
setCurrentStep(taskData.status);
|
||||
setTaskObject(prev => {
|
||||
if (!prev) return null;
|
||||
return {
|
||||
...prev,
|
||||
taskStatus: taskData.status
|
||||
};
|
||||
});
|
||||
setCurrentLoadingText(loadingText);
|
||||
|
||||
// 设置最终的状态更新
|
||||
stateUpdates.currentStep = taskData.status;
|
||||
stateUpdates.currentLoadingText = loadingText;
|
||||
|
||||
// 批量更新所有状态 因为上面的循环 会执行很多次更新 影响性能
|
||||
if (stateUpdates.taskSketch) setTaskSketch(stateUpdates.taskSketch);
|
||||
if (stateUpdates.taskScenes) setTaskScenes(stateUpdates.taskScenes);
|
||||
if (stateUpdates.taskShotSketch) setTaskShotSketch(stateUpdates.taskShotSketch);
|
||||
if (stateUpdates.roles) setRoles(stateUpdates.roles);
|
||||
if (stateUpdates.taskVideos) setTaskVideos(stateUpdates.taskVideos);
|
||||
if (stateUpdates.isGeneratingSketch !== undefined) setIsGeneratingSketch(stateUpdates.isGeneratingSketch);
|
||||
if (stateUpdates.isGeneratingVideo !== undefined) setIsGeneratingVideo(stateUpdates.isGeneratingVideo);
|
||||
if (stateUpdates.currentStep) setCurrentStep(stateUpdates.currentStep);
|
||||
if (stateUpdates.currentLoadingText) setCurrentLoadingText(stateUpdates.currentLoadingText);
|
||||
if (stateUpdates.final) setFinal(stateUpdates.final);
|
||||
if (stateUpdates.needStreamData !== undefined) setNeedStreamData(stateUpdates.needStreamData);
|
||||
if (stateUpdates.totalSketchCount) setTotalSketchCount(stateUpdates.totalSketchCount);
|
||||
|
||||
// Redux 更新放在最后,避免触发额外的 useEffect
|
||||
if (stateUpdates.taskSketch) updateSketchCount(stateUpdates.taskSketch.length);
|
||||
if (stateUpdates.taskVideos) updateVideoCount(stateUpdates.taskVideos.length);
|
||||
|
||||
// 更新 taskObject
|
||||
if (stateUpdates.currentStep) {
|
||||
setTaskObject(prev => {
|
||||
if (!prev) return null;
|
||||
return {
|
||||
...prev,
|
||||
taskStatus: stateUpdates.currentStep!
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('获取数据失败:', error);
|
||||
}
|
||||
};
|
||||
}, [episodeId, needStreamData, roles.length, taskShotSketch.length]);
|
||||
|
||||
// 轮询获取流式数据
|
||||
useEffect(() => {
|
||||
@ -403,7 +445,7 @@ export function useWorkflowData() {
|
||||
clearInterval(interval);
|
||||
}
|
||||
};
|
||||
}, [needStreamData]);
|
||||
}, [needStreamData, fetchStreamData]);
|
||||
|
||||
// 初始化数据
|
||||
const initializeWorkflow = async () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user