'use client'; import { useState, useEffect } 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}...`, 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; } export function useWorkflowData() { const searchParams = useSearchParams(); const episodeId = searchParams.get('episodeId'); // 更新 taskObject 的类型 const [taskObject, setTaskObject] = useState(null); const [taskSketch, setTaskSketch] = useState([]); const [taskVideos, setTaskVideos] = useState([]); const [sketchCount, setSketchCount] = 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([]); const [music, setMusic] = useState([]); const [final, setFinal] = useState(null); const [dataLoadError, setDataLoadError] = useState(null); const [needStreamData, setNeedStreamData] = useState(false); // 获取流式数据 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; 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); setCurrentSketchIndex(sketchList.length - 1); 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: '' }); } 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.video(0, sketchCount); } } if (task.task_name === 'generate_videos' && task.task_result) { if (task.task_result.data.length >= 0 && taskVideos.length !== task.task_result.data.length) { // 正在生成视频中 替换视频数据 const videoList = []; for (const video of task.task_result.data) { // 每一项 video 有多个视频 先默认取第一个 videoList.push({ url: video[0].qiniuVideoUrl, script: video[0].operation.metadata.video.prompt, audio: null, }); } setTaskVideos(videoList); setIsGeneratingVideo(true); setCurrentSketchIndex(videoList.length - 1); 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_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('正在加载项目数据...'); // 获取剧集详情 const response = await detailScriptEpisodeNew({ project_id: episodeId }); if (!response.successful) { throw new Error(response.message); } const { name, status, data } = response.data; setIsLoading(false); // 设置初始数据 setTaskObject({ taskStatus: '0', title: name || 'generating...', currentLoadingText: status === 'COMPLETED' ? LOADING_TEXT_MAP.complete : LOADING_TEXT_MAP.initializing }); // 设置标题 if (!name) { // 如果没有标题,轮询获取 const titleResponse = await getScriptTitle({ project_id: episodeId }); console.log('titleResponse', titleResponse); if (titleResponse.successful) { setTaskObject((prev: TaskObject | null) => ({ ...(prev || {}), title: titleResponse.data.name } 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); setCurrentSketchIndex(data.sketch.data.length - 1); 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: '' }); } 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.video(0, data.video.total_count || data.sketch.total_count); } } } if (data.video && data.video.data && data.video.data.length > 0) { const videoList = []; for (const video of data.video.data) { // 每一项 video 有多个视频 先默认取第一个 videoList.push({ url: video[0].qiniuVideoUrl, script: video[0].operation.metadata.video.prompt, audio: null, }); } setTaskVideos(videoList); // 如果在视频步骤,设置为最后一个视频 if (data.video.total_count > data.video.data.length) { setIsGeneratingVideo(true); setCurrentSketchIndex(data.video.data.length - 1); loadingText = LOADING_TEXT_MAP.video(data.video.data.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_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, }; }