video-flow-b/components/pages/work-flow/use-workflow-data.tsx
2025-07-19 23:12:06 +08:00

547 lines
19 KiB
TypeScript

'use client';
import { useState, useEffect, useCallback } from 'react';
import { useSearchParams } from 'next/navigation';
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData } from '@/api/video_flow';
// 步骤映射
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...',
sketch: (count: number, total: number) => `Generating sketch ${count + 1 > total ? total : count + 1}/${total}...`,
sketchComplete: 'Sketch generation complete',
character: 'Drawing characters...',
newCharacter: (count: number, total: number) => `Drawing character ${count + 1 > total ? total : count + 1}/${total}...`,
getShotSketchStatus: 'Getting shot sketch status...',
shotSketch: (count: number, total: number) => `Generating shot sketch ${count + 1 > total ? total : count + 1}/${total}...`,
getVideoStatus: 'Getting video status...',
video: (count: number, total: number) => `Generating video ${count + 1 > total ? total : count + 1}/${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;
// 添加 TaskObject 接口
interface TaskObject {
taskStatus: string;
title: string;
currentLoadingText: string;
sketchCount?: number;
totalSketchCount?: number;
isGeneratingSketch?: boolean;
isGeneratingVideo?: boolean;
roles?: any[];
music?: any[];
final?: any;
tags?: any[];
}
export function useWorkflowData() {
const searchParams = useSearchParams();
const episodeId = searchParams.get('episodeId');
// 更新 taskObject 的类型
const [taskObject, setTaskObject] = useState<TaskObject | null>(null);
const [taskSketch, setTaskSketch] = useState<any[]>([]);
const [taskShotSketch, setTaskShotSketch] = useState<any[]>([]);
const [taskVideos, setTaskVideos] = useState<any[]>([]);
const [sketchCount, setSketchCount] = useState(0);
const [videoCount, setVideoCount] = useState(0);
const [isLoading, setIsLoading] = useState(true);
const [currentStep, setCurrentStep] = useState('0');
const [currentSketchIndex, setCurrentSketchIndex] = useState(0);
const [isGeneratingSketch, setIsGeneratingSketch] = useState(false);
const [isGeneratingVideo, setIsGeneratingVideo] = useState(false);
const [currentLoadingText, setCurrentLoadingText] = useState('正在加载项目数据...');
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 [needStreamData, setNeedStreamData] = useState(false);
// 自动开始播放一轮
const autoPlaySketch = useCallback(() => {
return new Promise<void>((resolve) => {
let currentIndex = 0;
const interval = 2000; // 每个草图显示2秒
const playNext = () => {
if (currentIndex < taskSketch.length) {
setCurrentSketchIndex(currentIndex);
currentIndex++;
setTimeout(playNext, interval);
} else {
// 播放完成后重置到第一个
setTimeout(() => {
setCurrentSketchIndex(0);
resolve();
}, 500); // 短暂延迟后重置
}
};
// 开始播放
playNext();
});
}, [taskSketch.length]);
// 草图生成完毕后自动播放一轮
useEffect(() => {
const handleAutoPlay = async () => {
if (!isGeneratingSketch && taskSketch.length > 0 && sketchCount === totalSketchCount && currentStep === '3' && !taskVideos.length) {
await autoPlaySketch();
}
};
handleAutoPlay();
}, [sketchCount, totalSketchCount, isGeneratingSketch, autoPlaySketch]);
useEffect(() => {
console.log('sketchCount 已更新:', sketchCount);
setCurrentSketchIndex(sketchCount - 1);
}, [sketchCount]);
useEffect(() => {
console.log('videoCount 已更新:', videoCount);
setCurrentSketchIndex(videoCount - 1);
}, [videoCount]);
// 添加手动播放控制
const handleManualPlay = useCallback(async () => {
if (!isGeneratingSketch && taskSketch.length > 0) {
await autoPlaySketch();
}
}, [isGeneratingSketch, taskSketch.length, autoPlaySketch]);
// 获取流式数据
const fetchStreamData = async () => {
if (!episodeId || !needStreamData) return;
try {
const response = await getRunningStreamData({ project_id: episodeId });
if (!response.successful) {
throw new Error(response.message);
}
let loadingText: any = LOADING_TEXT_MAP.initializing;
let finalStep = '1', sketchCount = 0, isChange = false;
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;
console.log('all_task_data', all_task_data);
for (const task of all_task_data) {
// 如果有已完成的数据,同步到状态
if (task.task_name === 'generate_sketch' && task.task_result) {
if (task.task_result.data.length >= 0 && taskSketch.length < task.task_result.data.length) {
// 正在生成草图中 替换 sketch 数据
const sketchList = [];
for (const sketch of task.task_result.data) {
sketchList.push({
url: sketch.image_path,
script: sketch.sketch_name
});
}
setTaskSketch(sketchList);
setSketchCount(sketchList.length);
setIsGeneratingSketch(true);
loadingText = LOADING_TEXT_MAP.sketch(sketchList.length, task.task_result.total_count);
}
if (task.task_status === 'COMPLETED') {
// 草图生成完成
setIsGeneratingSketch(false);
sketchCount = task.task_result.total_count;
console.log('----------草图生成完成', sketchCount);
loadingText = LOADING_TEXT_MAP.sketchComplete;
finalStep = '2';
}
setTotalSketchCount(task.task_result.total_count);
}
if (task.task_name === 'generate_character' && task.task_result) {
if (task.task_result.data.length >= 0 && roles.length !== task.task_result.data.length) {
// 正在生成角色中 替换角色数据
const characterList = [];
for (const character of task.task_result.data) {
characterList.push({
name: character.character_name,
url: character.image_path,
sound: null,
soundDescription: '',
roleDescription: character.character_description
});
}
setRoles(characterList);
loadingText = LOADING_TEXT_MAP.newCharacter(characterList.length, task.task_result.total_count);
}
if (task.task_status === 'COMPLETED') {
console.log('----------角色生成完成,有几个分镜', sketchCount);
// 角色生成完成
finalStep = '3';
loadingText = LOADING_TEXT_MAP.getShotSketchStatus;
}
}
if (task.task_name === 'generate_shot_sketch' && task.task_result) {
if (task.task_result.data.length >= 0 && taskShotSketch.length < task.task_result.data.length) {
console.log('----------正在生成草图中 替换 sketch 数据', taskShotSketch.length, task.task_result.data.length);
// 正在生成草图中 替换 sketch 数据
const sketchList = [];
for (const sketch of task.task_result.data) {
sketchList.push({
url: sketch.url,
script: sketch.description
});
}
setTaskSketch(sketchList);
setTaskShotSketch(sketchList);
setSketchCount(sketchList.length);
setIsGeneratingSketch(true);
loadingText = LOADING_TEXT_MAP.shotSketch(sketchList.length, task.task_result.total_count);
}
if (task.task_status === 'COMPLETED') {
// 草图生成完成
setIsGeneratingSketch(false);
setIsGeneratingVideo(true);
sketchCount = task.task_result.total_count;
console.log('----------草图生成完成', sketchCount);
loadingText = LOADING_TEXT_MAP.getVideoStatus;
finalStep = '3';
} else {
}
setTotalSketchCount(task.task_result.total_count);
}
if (task.task_name === 'generate_videos' && task.task_result) {
const realTaskResultData = task.task_result.data.filter((item: any) => item.urls && item.urls.length > 0);
if (realTaskResultData.length >= 0 && taskVideos.length !== realTaskResultData.length) {
console.log('----------正在生成视频中-发生变化才触发', taskVideos.length);
// 正在生成视频中 替换视频数据
const videoList = [];
for (const video of realTaskResultData) {
// 每一项 video 有多个视频 先默认取第一个
videoList.push({
url: video.urls && video.urls.length > 0 ? video.urls.find((url: string) => url) : null,
script: video.description,
audio: null,
});
}
setTaskVideos(videoList);
setVideoCount(videoList.length);
setIsGeneratingVideo(true);
loadingText = LOADING_TEXT_MAP.video(videoList.length, task.task_result.total_count);
}
if (task.task_status === 'COMPLETED') {
console.log('----------视频生成完成');
// 视频生成完成
setIsGeneratingVideo(false);
finalStep = '4';
// 暂时没有音频生成 直接跳过
finalStep = '5';
loadingText = LOADING_TEXT_MAP.postProduction('post-production...');
}
}
// 粗剪
if (task.task_name === 'generate_final_simple_video') {
if (task.task_result && task.task_result.video) {
setFinal({
url: task.task_result.video,
})
finalStep = '5.5';
loadingText = LOADING_TEXT_MAP.postProduction('post-production...');
}
}
// 最终剪辑
if (task.task_name === 'generate_final_video') {
if (task.task_result && task.task_result.video) {
setFinal({
url: task.task_result.video,
})
finalStep = '6';
loadingText = LOADING_TEXT_MAP.complete;
// 停止轮询
setNeedStreamData(false);
}
}
}
console.log('----------finalStep', finalStep);
// 设置步骤
setCurrentStep(finalStep);
setTaskObject(prev => {
if (!prev) return null;
return {
...prev,
taskStatus: finalStep
};
});
setCurrentLoadingText(loadingText);
} catch (error) {
console.error('获取数据失败:', error);
}
};
// 轮询获取流式数据
useEffect(() => {
let interval: NodeJS.Timeout;
if (needStreamData) {
interval = setInterval(fetchStreamData, 10000);
fetchStreamData(); // 立即执行一次
}
return () => {
if (interval) {
clearInterval(interval);
}
};
}, [needStreamData]);
// 初始化数据
const initializeWorkflow = async () => {
if (!episodeId) {
setDataLoadError('缺少必要的参数');
setIsLoading(false);
return;
}
try {
setIsLoading(true);
setCurrentLoadingText('loading project info...');
// 获取剧集详情
const response = await detailScriptEpisodeNew({ project_id: episodeId });
if (!response.successful) {
throw new Error(response.message);
}
const { name, status, data, tags } = response.data;
setIsLoading(false);
// 设置初始数据
setTaskObject({
taskStatus: '0',
title: name || 'generating...',
currentLoadingText: status === 'COMPLETED' ? LOADING_TEXT_MAP.complete : LOADING_TEXT_MAP.initializing,
tags: tags || []
});
// 设置标题
if (!name) {
// 如果没有标题,轮询获取
const titleResponse = await getScriptTitle({ project_id: episodeId });
console.log('titleResponse', titleResponse);
if (titleResponse.successful) {
setTaskObject((prev: TaskObject | null) => ({
...(prev || {}),
title: titleResponse.data.title,
tags: titleResponse.data.tags || []
} as TaskObject));
}
}
let loadingText: any = LOADING_TEXT_MAP.initializing;
if (status === 'COMPLETED') {
loadingText = LOADING_TEXT_MAP.complete;
}
// 如果有已完成的数据,同步到状态
let finalStep = '1';
if (data) {
if (data.sketch && data.sketch.data && data.sketch.data.length > 0) {
const sketchList = [];
for (const sketch of data.sketch.data) {
sketchList.push({
url: sketch.image_path,
script: sketch.sketch_name,
});
}
setTaskSketch(sketchList);
setSketchCount(sketchList.length);
setTotalSketchCount(data.sketch.total_count);
// 设置为最后一个草图
if (data.sketch.total_count > data.sketch.data.length) {
setIsGeneratingSketch(true);
loadingText = LOADING_TEXT_MAP.sketch(data.sketch.data.length, data.sketch.total_count);
} else {
finalStep = '2';
if (!data.character || !data.character.data || !data.character.data.length) {
loadingText = LOADING_TEXT_MAP.newCharacter(0, data.character.total_count);
}
}
}
if (data.character && data.character.data && data.character.data.length > 0) {
const characterList = [];
for (const character of data.character.data) {
characterList.push({
name: character.character_name,
url: character.image_path,
sound: null,
soundDescription: '',
roleDescription: character.character_description
});
}
setRoles(characterList);
if (data.character.total_count > data.character.data.length) {
loadingText = LOADING_TEXT_MAP.newCharacter(data.character.data.length, data.character.total_count);
} else {
finalStep = '3';
if (!data.video || !data.video.data || !data.video.data.length) {
loadingText = LOADING_TEXT_MAP.getShotSketchStatus;
}
}
}
if (data.shot_sketch && data.shot_sketch.data && data.shot_sketch.data.length > 0) {
const sketchList = [];
for (const sketch of data.shot_sketch.data) {
sketchList.push({
url: sketch.url,
script: sketch.description,
});
}
setTaskSketch(sketchList);
setTaskShotSketch(sketchList);
setSketchCount(sketchList.length);
setTotalSketchCount(data.shot_sketch.total_count);
// 设置为最后一个草图
if (data.shot_sketch.total_count > data.shot_sketch.data.length) {
setIsGeneratingSketch(true);
loadingText = LOADING_TEXT_MAP.shotSketch(data.shot_sketch.data.length, data.shot_sketch.total_count);
} else {
finalStep = '3';
setIsGeneratingVideo(true);
if (!data.character || !data.character.data || !data.character.data.length) {
loadingText = LOADING_TEXT_MAP.getVideoStatus;
}
}
}
if (data.video.data) {
const realDataVideoData = data.video.data.filter((item: any) => item.urls && item.urls.length > 0);
if (realDataVideoData.length > 0) {
const videoList = [];
console.log('----------data.video.data', data.video.data);
for (const video of realDataVideoData) {
// 每一项 video 有多个视频 默认取存在的项
videoList.push({
url: video.urls && video.urls.length > 0 ? video.urls.find((url: string) => url) : null,
script: video.description,
audio: null,
});
}
setTaskVideos(videoList);
setVideoCount(videoList.length);
// 如果在视频步骤,设置为最后一个视频
if (data.video.total_count > realDataVideoData.length) {
setIsGeneratingVideo(true);
loadingText = LOADING_TEXT_MAP.video(realDataVideoData.length, data.video.total_count);
} else {
finalStep = '4';
loadingText = LOADING_TEXT_MAP.audio;
// 暂时没有音频生成 直接跳过
finalStep = '5';
loadingText = LOADING_TEXT_MAP.postProduction('post-production...');
}
}
}
// 粗剪
if (data.final_simple_video && data.final_simple_video.video) {
setFinal({
url: data.final_simple_video.video
});
finalStep = '5.5';
loadingText = LOADING_TEXT_MAP.postProduction('post-production...');
}
if (data.final_video && data.final_video.video) {
setFinal({
url: data.final_video.video
});
finalStep = '6';
loadingText = LOADING_TEXT_MAP.complete;
}
}
// 设置步骤
setCurrentStep(finalStep);
setTaskObject(prev => {
if (!prev) return null;
return {
...prev,
taskStatus: finalStep
};
});
console.log('---------loadingText', loadingText);
setCurrentLoadingText(loadingText);
// 设置是否需要获取流式数据
setNeedStreamData(status !== 'COMPLETED' && finalStep !== '6');
} catch (error) {
console.error('初始化失败:', error);
setDataLoadError('加载失败,请重试');
setIsLoading(false);
}
};
// 重试加载数据
const retryLoadData = () => {
setDataLoadError(null);
// 重置所有状态
setTaskSketch([]);
setTaskVideos([]);
setSketchCount(0);
setTotalSketchCount(0);
setRoles([]);
setMusic([]);
setFinal(null);
setCurrentSketchIndex(0);
setCurrentStep('0');
// 重新初始化
initializeWorkflow();
};
// 初始化
useEffect(() => {
initializeWorkflow();
}, [episodeId]);
return {
taskObject,
taskSketch,
taskVideos,
sketchCount,
isLoading,
currentStep,
currentSketchIndex,
isGeneratingSketch,
isGeneratingVideo,
currentLoadingText,
totalSketchCount,
roles,
music,
final,
dataLoadError,
setCurrentSketchIndex,
retryLoadData,
handleManualPlay,
};
}