import { useState, useCallback, Dispatch, SetStateAction } from "react"; import { ScriptEditUseCase } from "../usecase/ScriptEditUseCase"; import { getProjectScript, abortVideoTask } 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; // 操作方法 /** 根据用户想法生成剧本并自动创建项目 */ generateScriptFromIdea: (idea: string) => Promise; /** 根据项目ID初始化已有剧本 */ initializeFromProject: (projectId: string) => Promise; /** 修改剧本 */ updateScript: (scriptText: string) => void; /** 应用剧本到视频生成流程 */ applyScript: () => Promise; /** 中断视频任务 */ abortVideoTask: () => Promise; // 修改字段的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(""); // 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((scriptText: string): void => { if (scriptEditUseCase) { scriptEditUseCase.updateScript(scriptText); // 更新解析后的故事详情 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 || ""); } }, [scriptEditUseCase]); /** * 应用剧本到视频生成流程 */ 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]); return { // 响应式状态 loading, synopsis, categories, protagonist, incitingIncident, problem, conflict, stakes, characterArc, projectId, planId, // 操作方法 generateScriptFromIdea, initializeFromProject, updateScript, applyScript, abortVideoTask: abortVideoTaskHandler, // 修改字段的set函数 setSynopsis, setCategories, setProtagonist, setIncitingIncident, setProblem, setConflict, setStakes, setCharacterArc, }; };