import { useState, useCallback, Dispatch, SetStateAction } from "react"; import { ScriptEditUseCase,ScriptEditKey } from "../usecase/ScriptEditUseCase"; import { getProjectScript, abortVideoTask, pausePlanFlow, resumePlanFlow } from "../../../api/video_flow"; /** * 剧本服务Hook接口 * 定义剧本服务Hook的所有状态和操作方法 */ export interface UseScriptService { // 响应式状态 /** 加载状态 */ loading: boolean; /** 故事梗概 */ synopsis: string; /** 故事分类 */ categories: string[]; /** 主角*/ protagonist: string; /** 激励事件 */ incitingIncident: string; /** 问题与新目标 */ problem: string; /** 冲突与障碍 */ conflict: string; /** 赌注 */ stakes: string; /** 人物弧线完成 */ characterArc: string; /** 项目ID */ projectId: string; /** 计划ID */ planId: string; /** AI优化要求 */ aiOptimizing: string; // 操作方法 /** 根据用户想法生成剧本并自动创建项目 */ generateScriptFromIdea: (idea: string) => Promise; /** 根据项目ID初始化已有剧本 */ initializeFromProject: (projectId: string) => Promise; /** 修改剧本 */ updateScript: (scriptText: string) => Promise; /** 应用剧本到视频生成流程 */ applyScript: () => Promise; /** 中断视频任务 */ abortVideoTask: () => Promise; /** 聚焦处理函数 */ focusHandler: (field: 'synopsis' | 'categories' | 'protagonist' | 'incitingIncident' | 'problem' | 'conflict' | 'stakes' | 'characterArc') => Promise; /** 增强剧本 */ enhanceScript: () => Promise; /** 设置AI优化要求 */ setAiOptimizing: Dispatch>; // 修改字段的set函数 /** 设置故事梗概 */ setSynopsis: Dispatch>; /** 设置故事分类 */ setCategories: Dispatch>; /** 设置主角名称 */ setProtagonist: Dispatch>; /** 设置激励事件 */ setIncitingIncident: Dispatch>; /** 设置问题与新目标 */ setProblem: Dispatch>; /** 设置冲突与障碍 */ setConflict: Dispatch>; /** 设置赌注 */ setStakes: Dispatch>; /** 设置人物弧线完成 */ setCharacterArc: Dispatch>; } /** * 剧本服务Hook * 提供剧本相关的所有状态管理和操作方法 * 包括剧本生成、项目创建、剧本保存等功能 */ export const useScriptService = (): UseScriptService => { // 响应式状态 const [loading, setLoading] = useState(false); const [synopsis, setSynopsis] = useState(""); const [categories, setCategories] = useState([]); const [protagonist, setProtagonist] = useState(""); const [incitingIncident, setIncitingIncident] = useState(""); const [problem, setProblem] = useState(""); const [conflict, setConflict] = useState(""); const [stakes, setStakes] = useState(""); const [characterArc, setCharacterArc] = useState(""); const [projectId, setProjectId] = useState(""); const [planId, setPlanId] = useState(""); const [aiOptimizing, setAiOptimizing] = useState(""); const [focusedField, setFocusedField] = useState(""); // UseCase实例 const [scriptEditUseCase, setScriptEditUseCase] = useState(null); /** * 根据用户想法生成剧本并自动创建项目 * @param idea 用户想法 */ const generateScriptFromIdea = useCallback(async (idea: string): Promise => { try { setLoading(true); // 创建新的剧本编辑用例 const newScriptEditUseCase = new ScriptEditUseCase(''); setScriptEditUseCase(newScriptEditUseCase); // 调用AI生成剧本 await newScriptEditUseCase.generateScript(idea, (content) => { // 获取解析后的故事详情 const storyDetails = newScriptEditUseCase.getStoryDetails(); setSynopsis(storyDetails.synopsis || ""); setCategories(storyDetails.categories || []); setProtagonist(storyDetails.protagonist || ""); setIncitingIncident(storyDetails.incitingIncident || ""); setProblem(storyDetails.problem || ""); setConflict(storyDetails.conflict || ""); setStakes(storyDetails.stakes || ""); setCharacterArc(storyDetails.characterArc || ""); }); // 剧本生成完成后,自动创建项目 const projectData = await newScriptEditUseCase.createProject( idea, "user123", "auto", "720p" ); setProjectId(projectData.project_id); setPlanId(projectData.plan_id); // 自动保存剧本到项目 await newScriptEditUseCase.saveScript(projectData.project_id); } catch (error) { console.error('生成剧本失败:', error); throw error; } finally { setLoading(false); } }, []); /** * 根据项目ID初始化已有剧本 * @param projectId 项目ID */ const initializeFromProject = useCallback(async (projectId: string): Promise => { try { setLoading(true); // 设置项目ID setProjectId(projectId); // 调用API获取项目剧本数据 const response = await getProjectScript({ project_id: projectId }); if (!response.successful) { throw new Error(response.message || '获取项目剧本失败'); } const { generated_script } = response.data; // 创建新的剧本编辑用例并初始化数据 const newScriptEditUseCase = new ScriptEditUseCase(generated_script); setScriptEditUseCase(newScriptEditUseCase); // 获取解析后的故事详情 const storyDetails = newScriptEditUseCase.getStoryDetails(); setSynopsis(storyDetails.synopsis || ""); setCategories(storyDetails.categories || []); setProtagonist(storyDetails.protagonist || ""); setIncitingIncident(storyDetails.incitingIncident || ""); setProblem(storyDetails.problem || ""); setConflict(storyDetails.conflict || ""); setStakes(storyDetails.stakes || ""); setCharacterArc(storyDetails.characterArc || ""); } catch (error) { console.error('初始化项目剧本失败:', error); throw error; } finally { setLoading(false); } }, []); /** * 修改剧本 * @param scriptText 新的剧本文本 */ const updateScript = useCallback(async (): Promise => { if (scriptEditUseCase) { // 更新解析后的故事详情 const storyDetails = scriptEditUseCase.getStoryDetails(); // 如果有项目ID,则保存剧本 if (projectId) { await scriptEditUseCase.saveScript(projectId); } } }, [scriptEditUseCase, projectId]); /** * 应用剧本到视频生成流程 */ const applyScript = useCallback(async (): Promise => { try { setLoading(true); if (!scriptEditUseCase) { throw new Error("剧本编辑用例未初始化"); } if (!projectId || !planId) { throw new Error("项目ID或计划ID未设置"); } await scriptEditUseCase.applyScript(projectId, planId); } catch (error) { console.error("应用剧本失败:", error); throw error; } finally { setLoading(false); } }, [scriptEditUseCase, projectId, planId]); /** * 中断视频任务 */ const abortVideoTaskHandler = useCallback(async (): Promise => { try { if (!projectId || !planId) { throw new Error("项目ID或计划ID未设置"); } // 调用中断视频任务API const response = await abortVideoTask({ project_id: projectId, plan_id: planId }); if (!response.successful) { throw new Error(response.message || "中断视频任务失败"); } console.log("视频任务中断成功"); } catch (error) { console.error("中断视频任务失败:", error); throw error; } }, [projectId, planId]); // 封装的setter函数,同时更新hook状态和scriptEditUseCase中的值对象 const setSynopsisWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(synopsis) : value; setSynopsis(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('synopsis', newValue); } }, [synopsis, scriptEditUseCase]); const setCategoriesWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(categories) : value; setCategories(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('categories', newValue); } }, [categories, scriptEditUseCase]); const setProtagonistWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(protagonist) : value; setProtagonist(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('protagonist', newValue); } }, [protagonist, scriptEditUseCase]); const setIncitingIncidentWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(incitingIncident) : value; setIncitingIncident(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('incitingIncident', newValue); } }, [incitingIncident, scriptEditUseCase]); const setProblemWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(problem) : value; setProblem(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('problem', newValue); } }, [problem, scriptEditUseCase]); const setConflictWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(conflict) : value; setConflict(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('conflict', newValue); } }, [conflict, scriptEditUseCase]); const setStakesWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(stakes) : value; setStakes(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('stakes', newValue); } }, [stakes, scriptEditUseCase]); const setCharacterArcWrapper = useCallback((value: SetStateAction) => { const newValue = typeof value === 'function' ? value(characterArc) : value; setCharacterArc(newValue); if (scriptEditUseCase) { scriptEditUseCase.updateStoryField('characterArc', newValue); } }, [characterArc, scriptEditUseCase]); /** * 聚焦处理函数 */ const focusHandler = useCallback(async (field: ScriptEditKey): Promise => { try { // 如果当前已经有聚焦的字段,先处理暂停/继续逻辑 // 设置新的聚焦字段 setFocusedField(field); } catch (error) { console.error("聚焦处理失败:", error); throw error; } }, []); /** * 增强剧本 */ const enhanceScript = useCallback(async (): Promise => { try { setLoading(true); if (!scriptEditUseCase) { throw new Error("剧本编辑用例未初始化"); } // 调用增强剧本方法 await scriptEditUseCase.enhanceScript( synopsis, focusedField as ScriptEditKey, aiOptimizing, (content: any) => { // 获取解析后的故事详情 const storyDetails = scriptEditUseCase.getStoryDetails(); setSynopsis(storyDetails.synopsis || ""); setCategories(storyDetails.categories || []); setProtagonist(storyDetails.protagonist || ""); setIncitingIncident(storyDetails.incitingIncident || ""); setProblem(storyDetails.problem || ""); setConflict(storyDetails.conflict || ""); setStakes(storyDetails.stakes || ""); setCharacterArc(storyDetails.characterArc || ""); } ); // 如果有项目ID,则保存增强后的剧本 if (projectId) { await scriptEditUseCase.saveScript(projectId); } } catch (error) { console.error("增强剧本失败:", error); throw error; } finally { setLoading(false); } }, [scriptEditUseCase, synopsis, focusedField, aiOptimizing, projectId]); return { // 响应式状态 loading, synopsis, categories, protagonist, incitingIncident, problem, conflict, stakes, characterArc, projectId, planId, aiOptimizing, // 操作方法 generateScriptFromIdea, initializeFromProject, updateScript, applyScript, abortVideoTask: abortVideoTaskHandler, focusHandler, enhanceScript, setAiOptimizing, // 封装的set函数 setSynopsis: setSynopsisWrapper, setCategories: setCategoriesWrapper, setProtagonist: setProtagonistWrapper, setIncitingIncident: setIncitingIncidentWrapper, setProblem: setProblemWrapper, setConflict: setConflictWrapper, setStakes: setStakesWrapper, setCharacterArc: setCharacterArcWrapper, }; };