import { useState, useCallback, useMemo } from "react"; import { ScriptSlice } from "../domain/valueObject"; import { ScriptEditUseCase } from "../usecase/ScriptEditUseCase"; import { getProjectScript, saveScript as saveScriptAPI, createProject as createProjectAPI } from "../../../api/video_flow"; import { throttle } from "@/utils/tools"; /** * 剧本服务Hook接口 * 定义剧本服务Hook的所有状态和操作方法 */ export interface UseScriptService { // 响应式状态 /** 当前剧本文本 */ scriptText: string; /** 剧本片段列表 */ scriptSlices: ScriptSlice[]; /** 用户提示词(可编辑) */ userPrompt: string; /** 加载状态 */ loading: boolean; /** 项目ID */ projectId: string; // 操作方法 /** 获取根据用户想法调用接口AI生成剧本(用户提示词) */ fetchScriptData: (prompt: string) => Promise; /** 根据项目ID获取已存在的剧本数据 */ fetchProjectScript: (projectId: string) => Promise; /** 更新用户提示词 */ updateUserPrompt: (prompt: string) => void; /** 重置剧本内容到初始状态 */ resetScript: () => void; /** 应用剧本 */ applyScript: () => Promise; /** 中断剧本生成 */ abortGenerateScript: () => void; /** 保存剧本 */ saveScript: () => Promise; /** 创建项目 */ createProject: () => Promise; } /** * 剧本服务Hook * 提供剧本相关的所有状态管理和操作方法 * 包括剧本数据获取、片段管理等功能 */ export const useScriptService = (): UseScriptService => { // 响应式状态 const [scriptText, setScriptText] = useState(""); const [scriptSlices, setScriptSlices] = useState([]); const [userPrompt, setUserPrompt] = useState(""); const [initialScriptText, setInitialScriptText] = useState(""); const [loading, setLoading] = useState(false); const [projectId, setProjectId] = useState(""); // UseCase实例 const [scriptEditUseCase, setScriptEditUseCase] = useState(null); /** * 初始化,ai生成剧本(用户提示词) * @param prompt 用户提示词 */ const fetchScriptData = useCallback(async (prompt: string): Promise => { try { setLoading(true); // 清空当前状态 setScriptText(""); setScriptSlices([]); // 更新用户提示词状态 setUserPrompt(prompt); // 创建新的剧本编辑用例 const newScriptEditUseCase = new ScriptEditUseCase(''); setScriptEditUseCase(newScriptEditUseCase); // 调用AI生成剧本 await newScriptEditUseCase.generateScript(prompt,throttle((newContent)=>{ // 获取生成的剧本文本 const generatedScriptText = newScriptEditUseCase.toString(); setScriptText(generatedScriptText); console.log(scriptText); // 获取剧本片段列表 const slices = newScriptEditUseCase.getScriptSlices(); setScriptSlices(slices); // 保存初始剧本文本(只在第一次获取时保存) if (!initialScriptText) { setInitialScriptText(generatedScriptText); } })); } catch (error) { console.error('获取剧本数据失败:', error); throw error; } finally { setLoading(false); } }, [initialScriptText]); /** * 根据项目ID获取已存在的剧本数据 * @param projectId 项目ID */ const fetchProjectScript = useCallback(async (projectId: string): Promise => { try { setLoading(true); // 清空当前状态 setScriptText(""); setScriptSlices([]); // 设置项目ID setProjectId(projectId); // 调用API获取项目剧本数据 const response = await getProjectScript({ projectId }); if (!response.successful) { throw new Error(response.message || '获取项目剧本失败'); } const { prompt, scriptText } = response.data; // 更新用户提示词状态 setUserPrompt(prompt); // 保存初始剧本文本(只在第一次获取时保存) if (!initialScriptText) { setInitialScriptText(scriptText); } // 创建新的剧本编辑用例并初始化数据 const newScriptEditUseCase = new ScriptEditUseCase(scriptText); setScriptEditUseCase(newScriptEditUseCase); // 设置剧本文本 setScriptText(scriptText); // 从UseCase获取解析后的剧本片段 const scriptSlices = newScriptEditUseCase.getScriptSlices(); setScriptSlices(scriptSlices); } catch (error) { console.error('获取项目剧本数据失败:', error); throw error; } finally { setLoading(false); } }, [initialScriptText]); /** * 更新用户提示词 * @param prompt 新的用户提示词 */ const updateUserPrompt = useCallback((prompt: string): void => { setUserPrompt(prompt); }, []); /** * 重置剧本内容到初始状态 */ const resetScript = useCallback((): void => { if (initialScriptText && scriptEditUseCase) { // 重置剧本文本到初始状态 setScriptText(initialScriptText); // 更新现有剧本编辑用例的数据 scriptEditUseCase.updateScript(initialScriptText); // 从UseCase获取解析后的剧本片段 const scriptSlices = scriptEditUseCase.getScriptSlices(); setScriptSlices(scriptSlices); } }, [initialScriptText, scriptEditUseCase]); /** * 应用剧本 */ const applyScript = useCallback(async (): Promise => { try { setLoading(true); if (!scriptEditUseCase) { throw new Error("剧本编辑用例未初始化"); } await scriptEditUseCase.applyScript(projectId); } catch (error) { console.error("应用剧本失败:", error); throw error; } finally { setLoading(false); } }, [scriptEditUseCase, projectId]); /** * 中断剧本生成 */ const abortGenerateScript = useCallback((): void => { if (scriptEditUseCase) { scriptEditUseCase.abortGenerateScript(); setLoading(false); } }, [scriptEditUseCase]); /** * 保存剧本 */ const saveScript = useCallback(async (): Promise => { try { setLoading(true); if (!projectId) { throw new Error("项目ID未设置"); } if (!scriptEditUseCase) { throw new Error("剧本编辑用例未初始化"); } // 调用保存剧本接口 const scriptText = scriptEditUseCase.toString(); const response = await saveScriptAPI({ projectId, scriptText }); if (!response.successful) { throw new Error(response.message || '保存剧本失败'); } console.log("剧本保存成功"); } catch (error) { console.error("保存剧本失败:", error); throw error; } finally { setLoading(false); } }, [projectId, scriptEditUseCase]); /** * 创建项目 * @throws {Error} - 创建项目失败时抛出异常 */ const createProject = useCallback(async (): Promise => { try { setLoading(true); // 直接使用当前state中的userPrompt和scriptText const currentUserPrompt = userPrompt; const currentScriptContent = scriptText; const response = await createProjectAPI({ userPrompt: currentUserPrompt, scriptContent: currentScriptContent }); if (!response.successful) { throw new Error(response.message || '创建项目失败'); } const { projectId: newProjectId } = response.data; setProjectId(newProjectId); console.log("项目创建成功"); } catch (error) { console.error("创建项目失败:", error); throw error; } finally { setLoading(false); } }, [userPrompt, scriptText]); return { // 响应式状态 scriptText, scriptSlices, userPrompt, loading, projectId, // 操作方法 fetchScriptData, fetchProjectScript, updateUserPrompt, resetScript, applyScript, abortGenerateScript, saveScript, createProject, }; };