import { useState, useCallback, useMemo } from "react"; import { RoleEntity, AITextEntity } from "../domain/Entities"; import { RoleEditUseCase } from "../usecase/RoleEditUseCase"; import { getUploadToken, uploadToQiniu } from "@/api/common"; import { checkShotVideoStatus, } from "@/api/video_flow"; import { SaveEditUseCase } from "../usecase/SaveEditUseCase"; /** * 角色服务Hook返回值接口 */ interface UseRoleService { // 响应式数据 /** 角色列表 */ roleList: RoleEntity[]; /** 当前选中的角色 */ selectedRole: RoleEntity | null; /** 当前角色的AI文本 */ currentRoleText: string | null; /** 角色图片URL */ roleImageUrl: string; /** 用户角色库 */ userRoleLibrary: RoleEntity[]; // 操作方法 /** 获取角色列表 */ fetchRoleList: (projectId: string) => Promise; /** 选择角色 */ selectRole: (role: RoleEntity) => Promise; /** 优化AI文本 */ optimizeRoleText: (userSuggestion: string) => Promise; /** 修改AI文本 */ updateRoleText: (newContent: string) => Promise; /** 重新生成角色 */ regenerateRole: () => Promise; /** 获取用户角色库 */ fetchUserRoleLibrary: () => Promise; /** 替换角色 */ replaceRoleWithLibrary: (replaceRoleId: string) => Promise; /** 上传图片并更新角色信息 */ uploadImageAndUpdateRole: (file: File) => Promise; /** 保存重新生成的角色到角色库 */ saveRoleToLibrary: () => Promise; /** 保存数据 */ saveData: () => Promise; /** 切换标签页回调函数 */ changeTabCallback: (callback: (isChange: Boolean) => void) => void; } /** * 角色服务Hook * 提供角色相关的所有响应式功能和业务逻辑 */ export const useRoleServiceHook = (): UseRoleService => { // 响应式状态 const [roleList, setRoleList] = useState([]); const [selectedRole, setSelectedRole] = useState(null); const [currentRoleText, setCurrentRoleText] = useState(null); const [userRoleLibrary, setUserRoleLibrary] = useState([]); const [projectId, setProjectId] = useState(""); // 添加项目ID状态 // UseCase实例 - 在角色选择时初始化 const [roleEditUseCase, setRoleEditUseCase] = useState(null); // 计算属性 /** * 角色图片URL * @description 获取当前选中角色的图片URL */ const roleImageUrl = useMemo(() => { return selectedRole?.imageUrl || ""; }, [selectedRole]); /** * 获取角色列表 * @description 根据项目ID获取所有角色列表 * @param projectId 项目ID * @throws {Error} 当API调用失败时抛出错误 * @returns {Promise} 获取完成后的Promise */ const fetchRoleList = useCallback(async (projectId: string) => { try { // 保存项目ID到状态 setProjectId(projectId); // 初始化角色编辑UseCase实例 const newRoleEditUseCase = new RoleEditUseCase(); const roleList = await newRoleEditUseCase.getRoleList(projectId); setRoleList(roleList); setRoleEditUseCase(newRoleEditUseCase); } catch (error) { console.error("获取角色列表失败:", error); throw error; } }, []); /** * 选择角色 * @description 根据角色ID选择角色,并初始化相关的UseCase实例 * @param roleId 角色ID */ const selectRole = useCallback( async (role: RoleEntity) => { console.log("selectRole", role); setRoleList((prev) => prev.map((r) => (r.name === role.name ? role : r))); setSelectedRole(role); // 调用selectRole方法 roleEditUseCase!.selectRole(role); }, [roleEditUseCase] ); /** * 优化AI文本 * @description 对当前角色的AI文本进行优化 * @throws {Error} 当没有可优化的文本内容或UseCase未初始化时抛出错误 * @returns {Promise} 优化完成后的Promise */ const optimizeRoleText = useCallback(async () => { if (!roleEditUseCase) { throw new Error("角色编辑UseCase未初始化"); } if (!currentRoleText) { throw new Error("没有可优化的文本内容"); } if (!selectedRole) { throw new Error("没有选中的角色"); } try { const { optimizedDescription, keywords } = await roleEditUseCase.optimizeRoleDescription(selectedRole); setCurrentRoleText(optimizedDescription); // 更新角色列表中的对应角色描述和标签 setRoleList((prev) => prev.map((role) => role.id === selectedRole?.id ? { ...role, generateText: optimizedDescription, tags: keywords.map((keyword) => ({ id: `tag_${Date.now()}_${Math.random() .toString(36) .substr(2, 9)}`, /** 名称 */ name: keyword, /** 内容 */ content: keyword, loadingProgress: 100, updatedAt: Date.now(), })), } : role ) ); // 更新当前选中角色 if (selectedRole) { selectRole({ ...selectedRole, generateText: optimizedDescription, tags: keywords.map((keyword) => ({ id: `tag_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, /** 名称 */ name: keyword, /** 内容 */ content: keyword, loadingProgress: 100, updatedAt: Date.now(), })), }); } } catch (error) { console.error("优化角色文本失败:", error); throw error; } }, [roleEditUseCase, currentRoleText, selectedRole, selectRole]); /** * 修改AI文本 * @description 手动修改当前角色的AI文本内容 * @param newContent 新的文本内容 * @throws {Error} 当没有可编辑的文本或UseCase未初始化时抛出错误 * @returns {Promise} 修改完成后的Promise */ const updateRoleText = useCallback( async (newContent: string) => { if (!roleEditUseCase) { throw new Error("角色编辑UseCase未初始化"); } setCurrentRoleText(newContent); // 更新角色列表中的对应角色描述 setRoleList((prev) => prev.map((role) => role.id === selectedRole?.id ? { ...role, generateText: newContent } : role ) ); // 更新当前选中角色 if (selectedRole) { selectRole({ ...selectedRole, generateText: newContent }); } }, [roleEditUseCase, selectRole, selectedRole] ); /** * 重新生成角色 * @description 使用AI文本重新生成角色 * @throws {Error} 当缺少重新生成角色所需的数据或UseCase未初始化时抛出错误 * @returns {Promise} 重新生成完成后的Promise */ const regenerateRole = useCallback(async () => { if (!roleEditUseCase) { throw new Error("角色编辑UseCase未初始化"); } if (!selectedRole || !currentRoleText) { throw new Error("缺少重新生成角色所需的数据"); } if (!projectId) { throw new Error("缺少项目ID,无法重新生成角色"); } try { const newRoleEntity = await roleEditUseCase.AIgenerateRole( projectId, selectedRole.name, currentRoleText ); selectRole(newRoleEntity); // 更新角色列表 setRoleList((prev) => prev.map((role) => role.id === newRoleEntity.id ? newRoleEntity : role ) ); } catch (error) { console.error("重新生成角色失败:", error); throw error; } }, [roleEditUseCase, selectedRole, currentRoleText, projectId, selectRole]); /** * 获取用户角色库 * @description 获取当前用户的角色库列表 * @throws {Error} 当API调用失败时抛出错误 * @returns {Promise} 获取完成后的Promise */ const fetchUserRoleLibrary = useCallback(async () => { try { let useCase = roleEditUseCase; // 如果没有初始化RoleEditUseCase,创建一个新的实例 if (!useCase) { useCase = new RoleEditUseCase(); setRoleEditUseCase(useCase); } // 从localStorage获取当前用户信息 const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); if (!User.id) { throw new Error("无法获取用户ID,请重新登录"); } // 获取当前选中角色的描述 const userDescription = selectedRole?.generateText || ""; const roleLibraryList = await useCase!.getRoleLibraryList( User.id, userDescription ); setUserRoleLibrary(roleLibraryList); } catch (error) { console.error("获取用户角色库失败:", error); throw error; } }, [roleEditUseCase, selectedRole]); /** * 替换角色 * @description 使用角色库中的角色替换当前角色,并重新获取角色详细数据 * @param replaceRoleId 替换的角色ID * @throws {Error} 当未选择角色、API调用失败或UseCase未初始化时抛出错误 * @returns {Promise} 替换完成后的Promise */ const replaceRoleWithLibrary = useCallback( async (replaceRoleId: string) => { if (!selectedRole) { throw new Error("请先选择角色"); } if (!roleEditUseCase) { throw new Error("角色编辑UseCase未初始化"); } try { await roleEditUseCase.replaceRoleById(selectedRole.id, replaceRoleId); // 更新角色列表 const libraryRole = userRoleLibrary.find( (role) => role.id === replaceRoleId ); if (libraryRole) { const updatedRole = { ...selectedRole, name: libraryRole.name, generateText: libraryRole.generateText, imageUrl: libraryRole.imageUrl, fromDraft: false, isChangeRole: true }; selectRole(updatedRole); setRoleList((prev) => prev.map((role) => role.id === selectedRole.id ? updatedRole : role ) ); } } catch (error) { console.error("替换角色失败:", error); throw error; } }, [selectedRole, roleEditUseCase, userRoleLibrary, selectRole] ); /** * 上传图片并更新角色信息 * @description 上传图片文件到七牛云存储,然后调用AI接口分析图片生成描述和高亮标签,最后更新当前选中角色的图片、描述和标签 * @param file 要上传的文件 * @returns {Promise} 上传和分析完成后的Promise */ const uploadImageAndUpdateRole = useCallback( async (file: File) => { if (!selectedRole) { throw new Error("请先选择要更新的角色"); } if (!roleEditUseCase) { throw new Error("角色编辑UseCase未初始化"); } try { // 1. 上传图片到七牛云 const { token } = await getUploadToken(); const imageUrl = await uploadToQiniu(file, token); // 2. 调用用例中的图片分析方法 const updatedRole = await roleEditUseCase.analyzeImageAndUpdateRole(imageUrl, selectedRole); // 3. 更新选中的角色 selectRole(updatedRole); // 更新角色列表中的对应角色 setRoleList((prev) => prev.map((role) => (role.id === selectedRole.id ? updatedRole : role)) ); console.log("角色图片和描述更新成功:", updatedRole); } catch (error) { console.error("上传图片并分析失败:", error); throw error; } }, [selectedRole, roleEditUseCase, selectRole] ); /** * 保存重新生成的角色到角色库 * @description 将当前选中的角色保存到角色库中 * @throws {Error} 当没有选中角色、UseCase未初始化或缺少项目ID时抛出错误 * @returns {Promise} 保存完成后的Promise */ const saveRoleToLibrary = useCallback(async () => { if (!selectedRole) { throw new Error("请先选择要保存的角色"); } if (!roleEditUseCase) { throw new Error("角色编辑UseCase未初始化"); } if (!projectId) { throw new Error("缺少项目ID,无法保存角色到角色库"); } try { // 从localStorage获取当前用户信息 const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); if (!User.id) { throw new Error("无法获取用户ID,请重新登录"); } // 调用保存重新生成角色到角色库的方法 const result = await roleEditUseCase.saveRegeneratedCharacterToLibrary( selectedRole, projectId, String(User.id) ); selectRole({ ...selectedRole, id: result.character_id, fromDraft: true, }); SaveEditUseCase.setCharacterId([ ...SaveEditUseCase.characterId, { character_id: result.character_id, name: selectedRole.name, }, ]); console.log("角色保存到角色库成功:", result); } catch (error) { console.error("保存角色到角色库失败:", error); throw error; } }, [selectedRole, roleEditUseCase, projectId]); /** * 保存数据 * @description 调用接口保存当前项目数据 * @throws {Error} 当缺少项目ID或API调用失败时抛出错误 * @returns {Promise} 保存完成后的Promise */ const saveData = useCallback(async () => { if (!projectId) { throw new Error("缺少项目ID,无法保存数据"); } try { const result = await checkShotVideoStatus({ project_id: projectId, }); if (!result.successful) { throw new Error(`保存数据失败: ${result.message}`); } console.log("数据保存成功"); } catch (error) { console.error("保存数据失败:", error); throw error; } }, [projectId]); /** * @description 切换标签页回调函数,传入当前角色是否更改 * @param callback 回调函数,接收当前角色是否更改 */ const changeTabCallback = useCallback((callback: (isChange: Boolean) => void) => { // 执行回调函数,传入已更改的角色列表 callback(selectedRole!.isChangeRole); }, [selectedRole]); return { // 响应式数据 roleList, selectedRole, currentRoleText, roleImageUrl, userRoleLibrary, // 操作方法 fetchRoleList, selectRole, optimizeRoleText, updateRoleText, regenerateRole, fetchUserRoleLibrary, replaceRoleWithLibrary, uploadImageAndUpdateRole, saveRoleToLibrary, saveData, changeTabCallback, }; };