import { useState, useCallback, useMemo } from 'react'; import { RoleEntity, AITextEntity } from '../domain/Entities'; import { RoleEditUseCase } from '../usecase/RoleEditUseCase'; import { getUploadToken, uploadToQiniu } from '@/api/common'; import { analyzeImageDescription } from '@/api/video_flow'; /** * 角色服务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; } /** * 角色服务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); // 根据 role.name 完全替换掉旧的数据 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, disableEdit: false })) } : 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, disableEdit: false })) }); } } 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, }; 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('请先选择要更新的角色'); } try { // 1. 上传图片到七牛云 const { token } = await getUploadToken(); const imageUrl = await uploadToQiniu(file, token); // 2. 调用图片分析接口获取描述 const result = await analyzeImageDescription({ image_url: imageUrl }); if (!result.successful) { throw new Error(`图片分析失败: ${result.message}`); } const { description, highlights } = result.data; // 3. 更新当前选中角色的图片、描述和标签 const updatedRole = { ...selectedRole, imageUrl: imageUrl, generateText: description, tags: highlights.map((highlight: string, index: number) => ({ id: `tag_${Date.now()}_${index}`, /** 名称 */ name: highlight, /** 内容 */ content: highlight, loadingProgress: 100, disableEdit: false })) }; // 更新选中的角色 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) ); console.log('角色保存到角色库成功:', result); } catch (error) { console.error('保存角色到角色库失败:', error); throw error; } }, [selectedRole, roleEditUseCase, projectId]); return { // 响应式数据 roleList, selectedRole, currentRoleText, roleImageUrl, userRoleLibrary, // 操作方法 fetchRoleList, selectRole, optimizeRoleText, updateRoleText, regenerateRole, fetchUserRoleLibrary, replaceRoleWithLibrary, uploadImageAndUpdateRole, saveRoleToLibrary }; };