forked from 77media/video-flow
整理 主界面 loading 展示,改为大阶段 展示 8s 后 关闭。
This commit is contained in:
parent
0ef11c4e89
commit
5471457a4c
@ -642,6 +642,24 @@ export interface ShotVideo {
|
|||||||
video_status: number;
|
video_status: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 执行loading文字映射
|
||||||
|
export const LOADING_TEXT_MAP = {
|
||||||
|
initializing: 'initializing...',
|
||||||
|
script: 'Generating script...',
|
||||||
|
getSketchStatus: 'Getting sketch status...',
|
||||||
|
sketch: (count: number, total: number) => `Generating sketch ${count}/${total}...`,
|
||||||
|
character: 'Getting character status...',
|
||||||
|
newCharacter: (count: number, total: number) => `Drawing character ${count}/${total}...`,
|
||||||
|
getShotSketchStatus: 'Getting shot sketch status...',
|
||||||
|
shotSketch: (count: number, total: number) => `Generating shot sketch ${count}/${total}...`,
|
||||||
|
getVideoStatus: 'Getting video status...',
|
||||||
|
video: (count: number, total: number) => `Generating video ${count}/${total}...`,
|
||||||
|
audio: 'Generating background audio...',
|
||||||
|
postProduction: (step: string) => `Post-production: ${step}...`,
|
||||||
|
final: 'Generating final product...',
|
||||||
|
complete: 'Task completed'
|
||||||
|
} as const;
|
||||||
|
|
||||||
export type Status = 'IN_PROGRESS' | 'COMPLETED' | 'FAILED';
|
export type Status = 'IN_PROGRESS' | 'COMPLETED' | 'FAILED';
|
||||||
export type Stage = 'script' | 'character' | 'scene' | 'shot_sketch' | 'video' | 'final_video';
|
export type Stage = 'script' | 'character' | 'scene' | 'shot_sketch' | 'video' | 'final_video';
|
||||||
// 添加 TaskObject 接口
|
// 添加 TaskObject 接口
|
||||||
|
|||||||
@ -33,17 +33,9 @@ const WorkFlow = React.memo(function WorkFlow() {
|
|||||||
const {
|
const {
|
||||||
taskObject,
|
taskObject,
|
||||||
scriptData,
|
scriptData,
|
||||||
taskSketch,
|
|
||||||
taskVideos,
|
|
||||||
sketchCount,
|
|
||||||
isLoading,
|
isLoading,
|
||||||
currentStep,
|
|
||||||
currentSketchIndex,
|
currentSketchIndex,
|
||||||
isGeneratingSketch,
|
|
||||||
isGeneratingVideo,
|
|
||||||
currentLoadingText,
|
currentLoadingText,
|
||||||
totalSketchCount,
|
|
||||||
final,
|
|
||||||
dataLoadError,
|
dataLoadError,
|
||||||
setCurrentSketchIndex,
|
setCurrentSketchIndex,
|
||||||
retryLoadData,
|
retryLoadData,
|
||||||
@ -58,9 +50,8 @@ const WorkFlow = React.memo(function WorkFlow() {
|
|||||||
|
|
||||||
const {
|
const {
|
||||||
isVideoPlaying,
|
isVideoPlaying,
|
||||||
togglePlay,
|
|
||||||
toggleVideoPlay,
|
toggleVideoPlay,
|
||||||
} = usePlaybackControls(taskSketch, taskVideos, currentStep);
|
} = usePlaybackControls(taskObject.videos.data, taskObject.currentStage);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('changedIndex_work-flow', currentSketchIndex, taskObject);
|
console.log('changedIndex_work-flow', currentSketchIndex, taskObject);
|
||||||
@ -97,10 +88,8 @@ const WorkFlow = React.memo(function WorkFlow() {
|
|||||||
<div className="info-UUGkPJ">
|
<div className="info-UUGkPJ">
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<TaskInfo
|
<TaskInfo
|
||||||
isLoading={isLoading}
|
|
||||||
taskObject={taskObject}
|
taskObject={taskObject}
|
||||||
currentLoadingText={currentLoadingText}
|
currentLoadingText={currentLoadingText}
|
||||||
dataLoadError={dataLoadError}
|
|
||||||
roles={taskObject.roles.data}
|
roles={taskObject.roles.data}
|
||||||
isPauseWorkFlow={isPauseWorkFlow}
|
isPauseWorkFlow={isPauseWorkFlow}
|
||||||
/>
|
/>
|
||||||
@ -170,14 +159,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
|||||||
<ThumbnailGrid
|
<ThumbnailGrid
|
||||||
isDisabledFocus={isEditModalOpen || isPauseWorkFlow}
|
isDisabledFocus={isEditModalOpen || isPauseWorkFlow}
|
||||||
taskObject={taskObject}
|
taskObject={taskObject}
|
||||||
isLoading={isLoading}
|
|
||||||
currentSketchIndex={currentSketchIndex}
|
currentSketchIndex={currentSketchIndex}
|
||||||
taskSketch={taskSketch}
|
|
||||||
taskVideos={taskVideos}
|
|
||||||
isGeneratingSketch={isGeneratingSketch}
|
|
||||||
isGeneratingVideo={isGeneratingVideo}
|
|
||||||
sketchCount={sketchCount}
|
|
||||||
totalSketchCount={totalSketchCount}
|
|
||||||
onSketchSelect={setCurrentSketchIndex}
|
onSketchSelect={setCurrentSketchIndex}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -10,12 +10,11 @@ import {
|
|||||||
Film,
|
Film,
|
||||||
Scissors
|
Scissors
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
import { TaskObject } from '@/api/DTO/movieEdit';
|
||||||
|
|
||||||
interface TaskInfoProps {
|
interface TaskInfoProps {
|
||||||
isLoading: boolean;
|
taskObject: TaskObject;
|
||||||
taskObject: any;
|
|
||||||
currentLoadingText: string;
|
currentLoadingText: string;
|
||||||
dataLoadError?: string | null;
|
|
||||||
roles: any[];
|
roles: any[];
|
||||||
isPauseWorkFlow: boolean;
|
isPauseWorkFlow: boolean;
|
||||||
}
|
}
|
||||||
@ -120,17 +119,14 @@ const StageIcons = ({ currentStage, isExpanded, isPauseWorkFlow }: { currentStag
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function TaskInfo({
|
export function TaskInfo({
|
||||||
isLoading,
|
taskObject,
|
||||||
taskObject,
|
|
||||||
currentLoadingText,
|
currentLoadingText,
|
||||||
dataLoadError,
|
|
||||||
roles,
|
roles,
|
||||||
isPauseWorkFlow
|
isPauseWorkFlow
|
||||||
}: TaskInfoProps) {
|
}: TaskInfoProps) {
|
||||||
const [isScriptModalOpen, setIsScriptModalOpen] = useState(false);
|
const [isScriptModalOpen, setIsScriptModalOpen] = useState(false);
|
||||||
const [currentStage, setCurrentStage] = useState(0);
|
const [currentStage, setCurrentStage] = useState(0);
|
||||||
const [isShowScriptIcon, setIsShowScriptIcon] = useState(true);
|
|
||||||
const [isStageIconsExpanded, setIsStageIconsExpanded] = useState(false);
|
const [isStageIconsExpanded, setIsStageIconsExpanded] = useState(false);
|
||||||
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
const timerRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
|
||||||
@ -146,72 +142,39 @@ export function TaskInfo({
|
|||||||
timerRef.current = null;
|
timerRef.current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 统一更新currentStage
|
||||||
|
if (currentLoadingText.includes('initializing') || currentLoadingText.includes('script') || currentLoadingText.includes('character')) {
|
||||||
|
setCurrentStage(0);
|
||||||
|
} else if (currentLoadingText.includes('sketch') && !currentLoadingText.includes('shot sketch')) {
|
||||||
|
setCurrentStage(1);
|
||||||
|
} else if (!currentLoadingText.includes('Post-production') && (currentLoadingText.includes('shot sketch') || currentLoadingText.includes('video'))) {
|
||||||
|
setCurrentStage(2);
|
||||||
|
} else if (currentLoadingText.includes('Post-production')) {
|
||||||
|
setCurrentStage(3);
|
||||||
|
}
|
||||||
|
|
||||||
if (currentLoadingText.includes('Task completed')) {
|
if (currentLoadingText.includes('Task completed')) {
|
||||||
console.log('Closing modal at completion');
|
console.log('Closing modal at completion');
|
||||||
setIsScriptModalOpen(false);
|
setIsScriptModalOpen(false);
|
||||||
setIsShowScriptIcon(false);
|
|
||||||
}
|
}
|
||||||
if (currentLoadingText.includes('Post-production')) {
|
if (currentLoadingText.includes('Post-production') || currentLoadingText.includes('status')) {
|
||||||
if (isScriptModalOpen) {
|
|
||||||
setIsScriptModalOpen(false);
|
|
||||||
}
|
|
||||||
setCurrentStage(3);
|
|
||||||
console.log('isScriptModalOpen-Post-production', currentLoadingText, isScriptModalOpen);
|
console.log('isScriptModalOpen-Post-production', currentLoadingText, isScriptModalOpen);
|
||||||
timerRef.current = setTimeout(() => {
|
|
||||||
setIsScriptModalOpen(true);
|
|
||||||
}, 8000);
|
|
||||||
}
|
|
||||||
if (currentLoadingText.includes('Generating video')) {
|
|
||||||
console.log('isScriptModalOpen-video', currentLoadingText, isScriptModalOpen);
|
|
||||||
if (isScriptModalOpen) {
|
if (isScriptModalOpen) {
|
||||||
setIsScriptModalOpen(false);
|
setIsScriptModalOpen(false);
|
||||||
setCurrentStage(2);
|
|
||||||
|
|
||||||
// 延迟8s 再次打开
|
|
||||||
timerRef.current = setTimeout(() => {
|
|
||||||
setIsScriptModalOpen(true);
|
|
||||||
}, 8000);
|
|
||||||
} else {
|
} else {
|
||||||
setIsScriptModalOpen(true);
|
setIsScriptModalOpen(true);
|
||||||
setCurrentStage(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentLoadingText.includes('video status')) {
|
|
||||||
if (isScriptModalOpen) {
|
|
||||||
setIsScriptModalOpen(false);
|
|
||||||
}
|
|
||||||
setCurrentStage(2);
|
|
||||||
}
|
|
||||||
if (currentLoadingText.includes('Generating sketch') || currentLoadingText.includes('Generating shot sketch')) {
|
|
||||||
console.log('isScriptModalOpen-sketch', currentLoadingText, isScriptModalOpen);
|
|
||||||
if (isScriptModalOpen) {
|
|
||||||
setIsScriptModalOpen(false);
|
|
||||||
setCurrentStage(1);
|
|
||||||
|
|
||||||
// 延迟8s 再次打开
|
|
||||||
timerRef.current = setTimeout(() => {
|
timerRef.current = setTimeout(() => {
|
||||||
setIsScriptModalOpen(true);
|
setIsScriptModalOpen(false);
|
||||||
}, 8000);
|
}, 8000);
|
||||||
} else {
|
|
||||||
setIsScriptModalOpen(true);
|
|
||||||
setCurrentStage(1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (currentLoadingText.includes('sketch status')) {
|
|
||||||
if (isScriptModalOpen) {
|
|
||||||
setIsScriptModalOpen(false);
|
|
||||||
}
|
|
||||||
setCurrentStage(1);
|
|
||||||
}
|
|
||||||
if (currentLoadingText.includes('script')) {
|
if (currentLoadingText.includes('script')) {
|
||||||
console.log('isScriptModalOpen-script', currentLoadingText, isScriptModalOpen);
|
console.log('isScriptModalOpen-script', currentLoadingText, isScriptModalOpen);
|
||||||
setIsScriptModalOpen(true);
|
setIsScriptModalOpen(true);
|
||||||
setCurrentStage(0);
|
|
||||||
}
|
}
|
||||||
if (currentLoadingText.includes('initializing')) {
|
if (currentLoadingText.includes('initializing')) {
|
||||||
console.log('isScriptModalOpen-initializing', currentLoadingText, isScriptModalOpen);
|
console.log('isScriptModalOpen-initializing', currentLoadingText, isScriptModalOpen);
|
||||||
setIsScriptModalOpen(true);
|
setIsScriptModalOpen(true);
|
||||||
setCurrentStage(0);
|
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
if (timerRef.current) {
|
if (timerRef.current) {
|
||||||
|
|||||||
@ -10,28 +10,14 @@ import { TaskObject } from '@/api/DTO/movieEdit';
|
|||||||
interface ThumbnailGridProps {
|
interface ThumbnailGridProps {
|
||||||
isDisabledFocus: boolean;
|
isDisabledFocus: boolean;
|
||||||
taskObject: TaskObject;
|
taskObject: TaskObject;
|
||||||
isLoading: boolean;
|
|
||||||
currentSketchIndex: number;
|
currentSketchIndex: number;
|
||||||
taskSketch: any[];
|
|
||||||
taskVideos: any[];
|
|
||||||
isGeneratingSketch: boolean;
|
|
||||||
isGeneratingVideo: boolean;
|
|
||||||
sketchCount: number;
|
|
||||||
totalSketchCount: number;
|
|
||||||
onSketchSelect: (index: number) => void;
|
onSketchSelect: (index: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ThumbnailGrid({
|
export function ThumbnailGrid({
|
||||||
isDisabledFocus,
|
isDisabledFocus,
|
||||||
taskObject,
|
taskObject,
|
||||||
isLoading,
|
|
||||||
currentSketchIndex,
|
currentSketchIndex,
|
||||||
taskSketch,
|
|
||||||
taskVideos,
|
|
||||||
isGeneratingSketch,
|
|
||||||
isGeneratingVideo,
|
|
||||||
sketchCount,
|
|
||||||
totalSketchCount,
|
|
||||||
onSketchSelect
|
onSketchSelect
|
||||||
}: ThumbnailGridProps) {
|
}: ThumbnailGridProps) {
|
||||||
const thumbnailsRef = useRef<HTMLDivElement>(null);
|
const thumbnailsRef = useRef<HTMLDivElement>(null);
|
||||||
@ -166,89 +152,11 @@ export function ThumbnailGrid({
|
|||||||
console.log('taskObject.currentStage_thumbnail-grid', taskObject.currentStage);
|
console.log('taskObject.currentStage_thumbnail-grid', taskObject.currentStage);
|
||||||
}, [taskObject.currentStage]);
|
}, [taskObject.currentStage]);
|
||||||
|
|
||||||
// 渲染加载状态
|
|
||||||
if (isLoading) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
|
|
||||||
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
|
|
||||||
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
|
|
||||||
<Skeleton className="w-[128px] h-[128px] rounded-lg" />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 粗剪/精剪最终成片阶段不显示缩略图
|
// 粗剪/精剪最终成片阶段不显示缩略图
|
||||||
if (taskObject.currentStage === 'final_video') {
|
if (taskObject.currentStage === 'final_video') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 渲染生成中的缩略图
|
|
||||||
const renderGeneratingThumbnail = () => {
|
|
||||||
const currentSketch = taskSketch[currentSketchIndex];
|
|
||||||
const defaultBgColors = ['RGB(45, 50, 70)', 'RGB(75, 80, 100)', 'RGB(105, 110, 130)'];
|
|
||||||
const bgColors = currentSketch?.bg_rgb || defaultBgColors;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<motion.div
|
|
||||||
className="relative aspect-video rounded-lg overflow-hidden"
|
|
||||||
initial={{ opacity: 0, scale: 0.8 }}
|
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
|
||||||
transition={{ duration: 0.3 }}
|
|
||||||
>
|
|
||||||
{/* 动态渐变背景 */}
|
|
||||||
<motion.div
|
|
||||||
className={`absolute inset-0 bg-gradient-to-r from-[${bgColors[0]}] via-[${bgColors[1]}] to-[${bgColors[2]}]`}
|
|
||||||
animate={{
|
|
||||||
backgroundPosition: ["0% 50%", "100% 50%", "0% 50%"],
|
|
||||||
}}
|
|
||||||
transition={{
|
|
||||||
duration: 5,
|
|
||||||
repeat: Infinity,
|
|
||||||
ease: "linear"
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
backgroundSize: "200% 200%",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{/* 动态光效 */}
|
|
||||||
<motion.div
|
|
||||||
className="absolute inset-0 opacity-50"
|
|
||||||
style={{
|
|
||||||
background: "radial-gradient(circle at center, rgba(255,255,255,0.8) 0%, transparent 50%)",
|
|
||||||
}}
|
|
||||||
animate={{
|
|
||||||
scale: [1, 1.2, 1],
|
|
||||||
}}
|
|
||||||
transition={{
|
|
||||||
duration: 2,
|
|
||||||
repeat: Infinity,
|
|
||||||
ease: "easeInOut"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className="absolute inset-0 flex items-center justify-center">
|
|
||||||
<div className="relative">
|
|
||||||
<motion.div
|
|
||||||
className="absolute -inset-4 bg-gradient-to-r from-white via-sky-200 to-cyan-200 rounded-full opacity-60 blur-xl"
|
|
||||||
animate={{
|
|
||||||
scale: [1, 1.2, 1],
|
|
||||||
rotate: [0, 180, 360],
|
|
||||||
}}
|
|
||||||
transition={{
|
|
||||||
duration: 4,
|
|
||||||
repeat: Infinity,
|
|
||||||
ease: "linear"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="absolute bottom-0 left-0 right-0 p-2 bg-gradient-to-t from-black/60 to-transparent">
|
|
||||||
<span className="text-xs text-white/90">Scene {sketchCount + 1}</span>
|
|
||||||
</div>
|
|
||||||
</motion.div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 渲染视频阶段的缩略图
|
// 渲染视频阶段的缩略图
|
||||||
const renderVideoThumbnails = () => (
|
const renderVideoThumbnails = () => (
|
||||||
taskObject.videos.data.map((video, index) => {
|
taskObject.videos.data.map((video, index) => {
|
||||||
@ -354,7 +262,6 @@ export function ThumbnailGrid({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{isGeneratingSketch && sketchCount < totalSketchCount && renderGeneratingThumbnail()}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useRef, useEffect, useCallback } from 'react';
|
import { useState, useRef, useEffect, useCallback } from 'react';
|
||||||
|
|
||||||
export function usePlaybackControls(taskSketch: any[], taskVideos: any[], currentStep: string) {
|
export function usePlaybackControls(taskVideos: any[], currentStage: string) {
|
||||||
const [isPlaying, setIsPlaying] = useState(false);
|
const [isPlaying, setIsPlaying] = useState(false);
|
||||||
const [isVideoPlaying, setIsVideoPlaying] = useState(true);
|
const [isVideoPlaying, setIsVideoPlaying] = useState(true);
|
||||||
const [showControls, setShowControls] = useState(false);
|
const [showControls, setShowControls] = useState(false);
|
||||||
@ -19,24 +19,6 @@ export function usePlaybackControls(taskSketch: any[], taskVideos: any[], curren
|
|||||||
setIsVideoPlaying(prev => !prev);
|
setIsVideoPlaying(prev => !prev);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 自动播放逻辑 - 分镜草图(移除重复的定时器逻辑,由主组件处理)
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (isPlaying && taskSketch.length > 0) {
|
|
||||||
// playTimerRef.current = setInterval(() => {
|
|
||||||
// // 这里的切换逻辑需要在父组件中处理
|
|
||||||
// // 因为需要访问 setCurrentSketchIndex
|
|
||||||
// }, 1000);
|
|
||||||
// } else if (playTimerRef.current) {
|
|
||||||
// clearInterval(playTimerRef.current);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return () => {
|
|
||||||
// if (playTimerRef.current) {
|
|
||||||
// clearInterval(playTimerRef.current);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// }, [isPlaying, taskSketch.length]);
|
|
||||||
|
|
||||||
// 视频自动播放逻辑
|
// 视频自动播放逻辑
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isVideoPlaying && taskVideos.length > 0) {
|
if (isVideoPlaying && taskVideos.length > 0) {
|
||||||
@ -55,20 +37,12 @@ export function usePlaybackControls(taskSketch: any[], taskVideos: any[], curren
|
|||||||
};
|
};
|
||||||
}, [isVideoPlaying, taskVideos.length]);
|
}, [isVideoPlaying, taskVideos.length]);
|
||||||
|
|
||||||
// 当切换到视频模式时,停止分镜草图播放(注释掉,让用户手动控制)
|
|
||||||
// useEffect(() => {
|
|
||||||
// if (Number(currentStep) >= 3) {
|
|
||||||
// console.log('切换到步骤3+,停止分镜草图播放');
|
|
||||||
// setIsPlaying(false);
|
|
||||||
// }
|
|
||||||
// }, [currentStep]);
|
|
||||||
|
|
||||||
// 当切换到分镜草图模式时,停止视频播放
|
// 当切换到分镜草图模式时,停止视频播放
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentStep !== '3') {
|
if (currentStage !== 'video') {
|
||||||
setIsVideoPlaying(false);
|
setIsVideoPlaying(false);
|
||||||
}
|
}
|
||||||
}, [currentStep]);
|
}, [currentStage]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isPlaying,
|
isPlaying,
|
||||||
|
|||||||
@ -3,43 +3,9 @@
|
|||||||
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, pauseMovieProjectPlan, resumeMovieProjectPlan } from '@/api/video_flow';
|
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, pauseMovieProjectPlan, resumeMovieProjectPlan } from '@/api/video_flow';
|
||||||
import { useAppDispatch, useAppSelector } from '@/lib/store/hooks';
|
|
||||||
import { setSketchCount, setVideoCount } from '@/lib/store/workflowSlice';
|
|
||||||
import { useScriptService } from "@/app/service/Interaction/ScriptService";
|
import { useScriptService } from "@/app/service/Interaction/ScriptService";
|
||||||
import { useUpdateEffect } from '@/app/hooks/useUpdateEffect';
|
import { useUpdateEffect } from '@/app/hooks/useUpdateEffect';
|
||||||
import { TaskObject, Status, Stage } from '@/api/DTO/movieEdit';
|
import { LOADING_TEXT_MAP, TaskObject, Status, Stage } from '@/api/DTO/movieEdit';
|
||||||
|
|
||||||
// 步骤映射
|
|
||||||
const STEP_MAP = {
|
|
||||||
'initializing': '0',
|
|
||||||
'sketch': '1',
|
|
||||||
'character': '2',
|
|
||||||
'video': '3',
|
|
||||||
'music': '4',
|
|
||||||
'final_video': '6'
|
|
||||||
} as const;
|
|
||||||
// 执行loading文字映射
|
|
||||||
const LOADING_TEXT_MAP = {
|
|
||||||
initializing: 'initializing...',
|
|
||||||
script: 'Generating script...',
|
|
||||||
getSketchStatus: 'Getting sketch status...',
|
|
||||||
sketch: (count: number, total: number) => `Generating sketch ${count}/${total}...`,
|
|
||||||
sketchComplete: 'Sketch generation complete',
|
|
||||||
character: 'Drawing characters...',
|
|
||||||
newCharacter: (count: number, total: number) => `Drawing character ${count}/${total}...`,
|
|
||||||
getShotSketchStatus: 'Getting shot sketch status...',
|
|
||||||
shotSketch: (count: number, total: number) => `Generating shot sketch ${count}/${total}...`,
|
|
||||||
getVideoStatus: 'Getting video status...',
|
|
||||||
video: (count: number, total: number) => `Generating video ${count}/${total}...`,
|
|
||||||
videoComplete: 'Video generation complete',
|
|
||||||
audio: 'Generating background audio...',
|
|
||||||
postProduction: (step: string) => `Post-production: ${step}...`,
|
|
||||||
final: 'Generating final product...',
|
|
||||||
complete: 'Task completed'
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
type ApiStep = keyof typeof STEP_MAP;
|
|
||||||
|
|
||||||
|
|
||||||
export function useWorkflowData() {
|
export function useWorkflowData() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -53,7 +19,7 @@ export function useWorkflowData() {
|
|||||||
let tempTaskObject = useRef<TaskObject>({
|
let tempTaskObject = useRef<TaskObject>({
|
||||||
title: '',
|
title: '',
|
||||||
tags: [],
|
tags: [],
|
||||||
currentStage: 'script',
|
currentStage: 'script' as Stage,
|
||||||
status: 'IN_PROGRESS' as Status,
|
status: 'IN_PROGRESS' as Status,
|
||||||
roles: {
|
roles: {
|
||||||
data: [],
|
data: [],
|
||||||
@ -81,19 +47,8 @@ export function useWorkflowData() {
|
|||||||
|
|
||||||
// 更新 taskObject 的类型
|
// 更新 taskObject 的类型
|
||||||
const [taskObject, setTaskObject] = useState<TaskObject>(tempTaskObject.current);
|
const [taskObject, setTaskObject] = useState<TaskObject>(tempTaskObject.current);
|
||||||
const [taskSketch, setTaskSketch] = useState<any[]>([]);
|
|
||||||
const [taskScenes, setTaskScenes] = useState<any[]>([]);
|
|
||||||
const [taskShotSketch, setTaskShotSketch] = useState<any[]>([]);
|
|
||||||
const [taskVideos, setTaskVideos] = useState<any[]>([]);
|
|
||||||
const [currentStep, setCurrentStep] = useState('0');
|
|
||||||
const [currentSketchIndex, setCurrentSketchIndex] = useState(0);
|
const [currentSketchIndex, setCurrentSketchIndex] = useState(0);
|
||||||
const [isGeneratingSketch, setIsGeneratingSketch] = useState(false);
|
|
||||||
const [isGeneratingVideo, setIsGeneratingVideo] = useState(false);
|
|
||||||
const [currentLoadingText, setCurrentLoadingText] = useState('loading project info...');
|
const [currentLoadingText, setCurrentLoadingText] = useState('loading project info...');
|
||||||
const [totalSketchCount, setTotalSketchCount] = useState(0);
|
|
||||||
const [roles, setRoles] = useState<any[]>([]);
|
|
||||||
const [music, setMusic] = useState<any[]>([]);
|
|
||||||
const [final, setFinal] = useState<any>(null);
|
|
||||||
const [dataLoadError, setDataLoadError] = useState<string | null>(null);
|
const [dataLoadError, setDataLoadError] = useState<string | null>(null);
|
||||||
const [needStreamData, setNeedStreamData] = useState(false);
|
const [needStreamData, setNeedStreamData] = useState(false);
|
||||||
const [isPauseWorkFlow, setIsPauseWorkFlow] = useState(false);
|
const [isPauseWorkFlow, setIsPauseWorkFlow] = useState(false);
|
||||||
@ -103,10 +58,6 @@ export function useWorkflowData() {
|
|||||||
isLoading: true
|
isLoading: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
|
||||||
const { sketchCount, videoCount } = useAppSelector((state) => state.workflow);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
scriptBlocksMemo, // 渲染剧本数据
|
scriptBlocksMemo, // 渲染剧本数据
|
||||||
initializeFromProject,
|
initializeFromProject,
|
||||||
@ -170,24 +121,24 @@ export function useWorkflowData() {
|
|||||||
console.log('应用剧本');
|
console.log('应用剧本');
|
||||||
// 自动模式下 应用剧本;手动模式 需要点击 下一步 触发
|
// 自动模式下 应用剧本;手动模式 需要点击 下一步 触发
|
||||||
// 确保仅自动触发一次
|
// 确保仅自动触发一次
|
||||||
state.mode.includes('auto') && loadingText.current !== LOADING_TEXT_MAP.getSketchStatus && applyScript();
|
state.mode.includes('auto') && loadingText.current !== LOADING_TEXT_MAP.character && applyScript();
|
||||||
loadingText.current = LOADING_TEXT_MAP.getSketchStatus;
|
loadingText.current = LOADING_TEXT_MAP.character;
|
||||||
} else {
|
} else {
|
||||||
loadingText.current = LOADING_TEXT_MAP.script;
|
loadingText.current = LOADING_TEXT_MAP.script;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (taskObject.currentStage === 'scene') {
|
|
||||||
const realSketchResultData = taskObject.scenes.data.filter((item: any) => item.status !== 0);
|
|
||||||
if (taskObject.scenes.total_count > realSketchResultData.length) {
|
|
||||||
loadingText.current = LOADING_TEXT_MAP.sketch(realSketchResultData.length, taskObject.scenes.total_count);
|
|
||||||
} else {
|
|
||||||
loadingText.current = LOADING_TEXT_MAP.character;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (taskObject.currentStage === 'character') {
|
if (taskObject.currentStage === 'character') {
|
||||||
const realCharacterResultData = taskObject.roles.data.filter((item: any) => item.status !== 0);
|
const realCharacterResultData = taskObject.roles.data.filter((item: any) => item.status !== 0);
|
||||||
if (taskObject.roles.total_count > realCharacterResultData.length) {
|
if (taskObject.roles.total_count > realCharacterResultData.length) {
|
||||||
loadingText.current = LOADING_TEXT_MAP.newCharacter(realCharacterResultData.length, taskObject.roles.total_count);
|
loadingText.current = LOADING_TEXT_MAP.newCharacter(realCharacterResultData.length, taskObject.roles.total_count);
|
||||||
|
} else {
|
||||||
|
loadingText.current = LOADING_TEXT_MAP.getSketchStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (taskObject.currentStage === 'scene') {
|
||||||
|
const realSketchResultData = taskObject.scenes.data.filter((item: any) => item.status !== 0);
|
||||||
|
if (taskObject.scenes.total_count > realSketchResultData.length) {
|
||||||
|
loadingText.current = LOADING_TEXT_MAP.sketch(realSketchResultData.length, taskObject.scenes.total_count);
|
||||||
} else {
|
} else {
|
||||||
loadingText.current = LOADING_TEXT_MAP.getShotSketchStatus;
|
loadingText.current = LOADING_TEXT_MAP.getShotSketchStatus;
|
||||||
}
|
}
|
||||||
@ -217,16 +168,6 @@ export function useWorkflowData() {
|
|||||||
setCurrentLoadingText(loadingText.current);
|
setCurrentLoadingText(loadingText.current);
|
||||||
}, [scriptBlocksMemo, taskObject.currentStage, taskObject.scenes.data, taskObject.roles.data, taskObject.shot_sketch.data, taskObject.videos.data, taskObject.status], {mode: 'none'});
|
}, [scriptBlocksMemo, taskObject.currentStage, taskObject.scenes.data, taskObject.roles.data, taskObject.shot_sketch.data, taskObject.videos.data, taskObject.status], {mode: 'none'});
|
||||||
|
|
||||||
// 更新 setSketchCount
|
|
||||||
const updateSketchCount = useCallback((count: number) => {
|
|
||||||
dispatch(setSketchCount(count));
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
// 更新 setVideoCount
|
|
||||||
const updateVideoCount = useCallback((count: number) => {
|
|
||||||
dispatch(setVideoCount(count));
|
|
||||||
}, [dispatch]);
|
|
||||||
|
|
||||||
// 将 sketchCount 和 videoCount 放到 redux 中 每一次变化也要更新
|
// 将 sketchCount 和 videoCount 放到 redux 中 每一次变化也要更新
|
||||||
|
|
||||||
// 添加手动播放控制
|
// 添加手动播放控制
|
||||||
@ -249,13 +190,7 @@ export function useWorkflowData() {
|
|||||||
throw new Error(response.message);
|
throw new Error(response.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
let sketchCount = 0;
|
|
||||||
const all_task_data = response.data;
|
const all_task_data = response.data;
|
||||||
// all_task_data 下标0 和 下标1 换位置
|
|
||||||
const temp = all_task_data[0];
|
|
||||||
all_task_data[0] = all_task_data[1];
|
|
||||||
all_task_data[1] = temp;
|
|
||||||
|
|
||||||
const { current: taskCurrent } = tempTaskObject;
|
const { current: taskCurrent } = tempTaskObject;
|
||||||
|
|
||||||
console.log('---look-all_task_data', all_task_data);
|
console.log('---look-all_task_data', all_task_data);
|
||||||
@ -266,32 +201,6 @@ export function useWorkflowData() {
|
|||||||
|
|
||||||
for (const task of all_task_data) {
|
for (const task of all_task_data) {
|
||||||
// 如果有已完成的数据,同步到状态
|
// 如果有已完成的数据,同步到状态
|
||||||
if (task.task_name === 'generate_sketch' && task.task_result && task.task_result.data) {
|
|
||||||
let realSketchResultData = task.task_result.data.filter((item: any) => item.image_path);
|
|
||||||
if (task.task_status === 'COMPLETED') {
|
|
||||||
realSketchResultData = taskCurrent.scenes.data.filter((item: any) => item.status !== 0);
|
|
||||||
}
|
|
||||||
console.log('---look-realSketchResultData', realSketchResultData);
|
|
||||||
taskCurrent.scenes.total_count = task.task_result.total_count;
|
|
||||||
if (task.task_status !== 'COMPLETED' || taskCurrent.scenes.total_count !== realSketchResultData.length) {
|
|
||||||
taskCurrent.currentStage = 'scene';
|
|
||||||
// 正在生成草图中 替换 sketch 数据
|
|
||||||
const sketchList = [];
|
|
||||||
for (const sketch of task.task_result.data) {
|
|
||||||
sketchList.push({
|
|
||||||
url: sketch.image_path,
|
|
||||||
script: sketch.sketch_name,
|
|
||||||
status: sketch.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
taskCurrent.scenes.data = sketchList;
|
|
||||||
if (task.task_status === 'COMPLETED') {
|
|
||||||
// 草图生成完成
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task.task_name === 'generate_character' && task.task_result && task.task_result.data) {
|
if (task.task_name === 'generate_character' && task.task_result && task.task_result.data) {
|
||||||
let realCharacterResultData = task.task_result.data.filter((item: any) => item.image_path);
|
let realCharacterResultData = task.task_result.data.filter((item: any) => item.image_path);
|
||||||
if (task.task_status === 'COMPLETED') {
|
if (task.task_status === 'COMPLETED') {
|
||||||
@ -317,6 +226,32 @@ export function useWorkflowData() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (task.task_name === 'generate_sketch' && task.task_result && task.task_result.data) {
|
||||||
|
let realSketchResultData = task.task_result.data.filter((item: any) => item.image_path);
|
||||||
|
if (task.task_status === 'COMPLETED') {
|
||||||
|
realSketchResultData = taskCurrent.scenes.data.filter((item: any) => item.status !== 0);
|
||||||
|
}
|
||||||
|
console.log('---look-realSketchResultData', realSketchResultData);
|
||||||
|
taskCurrent.scenes.total_count = task.task_result.total_count;
|
||||||
|
if (task.task_status !== 'COMPLETED' || taskCurrent.scenes.total_count !== realSketchResultData.length) {
|
||||||
|
taskCurrent.currentStage = 'scene';
|
||||||
|
// 正在生成草图中 替换 sketch 数据
|
||||||
|
const sketchList = [];
|
||||||
|
for (const sketch of task.task_result.data) {
|
||||||
|
sketchList.push({
|
||||||
|
url: sketch.image_path,
|
||||||
|
script: sketch.sketch_name,
|
||||||
|
status: sketch.image_path ? 1 : (task.task_status === 'COMPLETED' ? 2 : 0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
taskCurrent.scenes.data = sketchList;
|
||||||
|
if (task.task_status === 'COMPLETED') {
|
||||||
|
// 草图生成完成
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// debugger;
|
// debugger;
|
||||||
if (task.task_name === 'generate_shot_sketch' && task.task_result && task.task_result.data) {
|
if (task.task_name === 'generate_shot_sketch' && task.task_result && task.task_result.data) {
|
||||||
@ -485,27 +420,6 @@ export function useWorkflowData() {
|
|||||||
|
|
||||||
// 如果有已完成的数据,同步到状态
|
// 如果有已完成的数据,同步到状态
|
||||||
if (data) {
|
if (data) {
|
||||||
if (data.sketch && data.sketch.data) {
|
|
||||||
taskCurrent.currentStage = 'scene';
|
|
||||||
const realSketchResultData = data.sketch.data.filter((item: any) => item.image_path);
|
|
||||||
const sketchList = [];
|
|
||||||
for (const sketch of data.sketch.data) {
|
|
||||||
sketchList.push({
|
|
||||||
url: sketch.image_path,
|
|
||||||
script: sketch.sketch_name,
|
|
||||||
status: sketch.image_path ? 1 : (data.sketch.task_status === 'COMPLETED' ? 2 : 0)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
taskCurrent.scenes.data = sketchList;
|
|
||||||
taskCurrent.scenes.total_count = data.sketch.total_count;
|
|
||||||
// 设置为最后一个草图
|
|
||||||
if (data.sketch.total_count > realSketchResultData.length) {
|
|
||||||
// 场景生成中
|
|
||||||
setIsGeneratingSketch(true);
|
|
||||||
} else {
|
|
||||||
// 场景生成完成
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (data.character && data.character.data && data.character.data.length > 0) {
|
if (data.character && data.character.data && data.character.data.length > 0) {
|
||||||
taskCurrent.currentStage = 'character';
|
taskCurrent.currentStage = 'character';
|
||||||
const characterList = [];
|
const characterList = [];
|
||||||
@ -524,6 +438,26 @@ export function useWorkflowData() {
|
|||||||
// 角色生成完成
|
// 角色生成完成
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (data.sketch && data.sketch.data) {
|
||||||
|
taskCurrent.currentStage = 'scene';
|
||||||
|
const realSketchResultData = data.sketch.data.filter((item: any) => item.image_path);
|
||||||
|
const sketchList = [];
|
||||||
|
for (const sketch of data.sketch.data) {
|
||||||
|
sketchList.push({
|
||||||
|
url: sketch.image_path,
|
||||||
|
script: sketch.sketch_name,
|
||||||
|
status: sketch.image_path ? 1 : (data.sketch.task_status === 'COMPLETED' ? 2 : 0)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
taskCurrent.scenes.data = sketchList;
|
||||||
|
taskCurrent.scenes.total_count = data.sketch.total_count;
|
||||||
|
// 设置为最后一个草图
|
||||||
|
if (data.sketch.total_count > realSketchResultData.length) {
|
||||||
|
// 场景生成中
|
||||||
|
} else {
|
||||||
|
// 场景生成完成
|
||||||
|
}
|
||||||
|
}
|
||||||
if (data.shot_sketch && data.shot_sketch.data) {
|
if (data.shot_sketch && data.shot_sketch.data) {
|
||||||
taskCurrent.currentStage = 'shot_sketch';
|
taskCurrent.currentStage = 'shot_sketch';
|
||||||
const realShotResultData = data.shot_sketch.data.filter((item: any) => item.url);
|
const realShotResultData = data.shot_sketch.data.filter((item: any) => item.url);
|
||||||
@ -629,17 +563,7 @@ export function useWorkflowData() {
|
|||||||
// 重试加载数据
|
// 重试加载数据
|
||||||
const retryLoadData = () => {
|
const retryLoadData = () => {
|
||||||
setDataLoadError(null);
|
setDataLoadError(null);
|
||||||
// 重置所有状态
|
|
||||||
setTaskSketch([]);
|
|
||||||
setTaskScenes([]);
|
|
||||||
setTaskVideos([]);
|
|
||||||
updateSketchCount(0);
|
|
||||||
updateVideoCount(0);
|
|
||||||
setRoles([]);
|
|
||||||
setMusic([]);
|
|
||||||
setFinal(null);
|
|
||||||
setCurrentSketchIndex(0);
|
setCurrentSketchIndex(0);
|
||||||
setCurrentStep('0');
|
|
||||||
// 重新初始化
|
// 重新初始化
|
||||||
initializeWorkflow();
|
initializeWorkflow();
|
||||||
};
|
};
|
||||||
@ -652,21 +576,9 @@ export function useWorkflowData() {
|
|||||||
return {
|
return {
|
||||||
taskObject,
|
taskObject,
|
||||||
scriptData,
|
scriptData,
|
||||||
taskSketch,
|
|
||||||
taskScenes,
|
|
||||||
taskShotSketch,
|
|
||||||
taskVideos,
|
|
||||||
sketchCount,
|
|
||||||
isLoading: state.isLoading,
|
isLoading: state.isLoading,
|
||||||
currentStep,
|
|
||||||
currentSketchIndex,
|
currentSketchIndex,
|
||||||
isGeneratingSketch,
|
|
||||||
isGeneratingVideo,
|
|
||||||
currentLoadingText,
|
currentLoadingText,
|
||||||
totalSketchCount,
|
|
||||||
roles,
|
|
||||||
music,
|
|
||||||
final,
|
|
||||||
dataLoadError,
|
dataLoadError,
|
||||||
setCurrentSketchIndex,
|
setCurrentSketchIndex,
|
||||||
retryLoadData,
|
retryLoadData,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user