import { useState, useCallback, useMemo } from "react"; import { VideoSegmentEntity, RoleEntity, SceneEntity, } from "../domain/Entities"; import { ContentItem, ScriptSlice, ScriptValueObject, LensType } from "../domain/valueObject"; import { VideoSegmentItem } from "../domain/Item"; import { VideoSegmentEditUseCase } from "../usecase/ShotEditUsecase"; import { getShotList, // getShotDetail, updateShotContent, getUserRoleLibrary, replaceShotRole, getShotVideoScript, } from "@/api/video_flow"; /** * 视频片段服务Hook接口 * 定义视频片段服务Hook的所有状态和操作方法 */ export interface UseVideoSegmentService { // 响应式状态 /** 视频片段列表 */ videoSegmentList: VideoSegmentEntity[]; /** 当前选中的视频片段 */ selectedVideoSegment: VideoSegmentItem | null; /** 当前视频片段的草图数据URL */ videoSegmentSketchData: string | null; /** 当前视频片段的视频数据URL */ videoSegmentVideoData: string[] | null; /** 用户角色库 */ userRoleLibrary: RoleEntity[]; /** 当前视频片段的视频剧本片段 */ videoSegmentVideoScript: ScriptSlice[]; /** 加载状态 */ loading: boolean; /** 错误信息 */ error: string | null; // 操作方法 /** 获取视频片段列表 */ fetchVideoSegmentList: (projectId: string) => Promise; /** 选择视频片段并获取详情 */ selectVideoSegment: (videoSegmentId: string) => Promise; /** 修改视频片段对话内容 */ updateVideoSegmentContent: ( newContent: Array<{ roleId: string; content: string }> ) => Promise; /** 获取用户角色库 */ fetchUserRoleLibrary: () => Promise; /** 替换视频片段角色 */ replaceVideoSegmentRole: (oldRoleId: string, newRoleId: string) => Promise; /** 获取视频片段视频剧本内容 */ fetchVideoSegmentVideoScript: () => Promise; /** 获取视频片段关联的角色信息 */ getVideoSegmentRoles: () => Promise; /** 获取视频片段关联的场景信息 */ getVideoSegmentScenes: () => Promise; /** 重新生成视频片段 */ regenerateVideoSegment: ( shotPrompt: LensType[], dialogueContent: ContentItem[], roleReplaceParams: { oldId: string; newId: string }[], sceneReplaceParams: { oldId: string; newId: string }[] ) => Promise; } /** * 视频片段服务Hook * 提供视频片段相关的所有状态管理和操作方法 * 包括视频片段列表管理、视频片段选择、数据获取、内容修改等功能 */ export const useVideoSegmentService = (): UseVideoSegmentService => { // 响应式状态 const [videoSegmentList, setVideoSegmentList] = useState([]); const [selectedVideoSegment, setSelectedVideoSegment] = useState(null); const [videoSegmentSketchData, setVideoSegmentSketchData] = useState(null); const [videoSegmentVideoData, setVideoSegmentVideoData] = useState(null); const [userRoleLibrary, setUserRoleLibrary] = useState([]); const [videoSegmentVideoScript, setVideoSegmentVideoScript] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [projectId, setProjectId] = useState(""); // UseCase实例 const [videoSegmentEditUseCase, setVideoSegmentEditUseCase] = useState(null); /** * 获取视频片段列表 * @description 根据项目ID获取所有视频片段列表 * @param projectId 项目ID */ const fetchVideoSegmentList = useCallback(async (projectId: string) => { setProjectId(projectId); try { setLoading(true); setError(null); const response = await getShotList({ projectId }); if (response.successful) { setVideoSegmentList(response.data); } else { setError(`获取视频片段列表失败: ${response.message}`); } } catch (err) { setError( `获取视频片段列表失败: ${err instanceof Error ? err.message : "未知错误"}` ); } finally { setLoading(false); } }, []); /** * 选择视频片段并获取详情 * @description 根据视频片段ID获取视频片段详情,并初始化相关的UseCase和数据 * @param videoSegmentId 视频片段ID */ const selectVideoSegment = useCallback(async (videoSegmentId: string) => { try { setLoading(true); setError(null); // 获取视频片段详情 await fetchVideoSegmentList(projectId); const videoSegmentEntity = videoSegmentList.find( (videoSegment: VideoSegmentEntity) => videoSegment.id === videoSegmentId ); if (!videoSegmentEntity) { setError(`视频片段不存在: ${videoSegmentId}`); return; } const videoSegmentItem = new VideoSegmentItem(videoSegmentEntity); setSelectedVideoSegment(videoSegmentItem); // 初始化UseCase const newVideoSegmentEditUseCase = new VideoSegmentEditUseCase(videoSegmentItem); setVideoSegmentEditUseCase(newVideoSegmentEditUseCase); // 从视频片段实体中获取草图数据和视频数据 setVideoSegmentSketchData(videoSegmentEntity.sketchUrl || null); setVideoSegmentVideoData(videoSegmentEntity.videoUrl || null); } catch (err) { setError( `选择视频片段失败: ${err instanceof Error ? err.message : "未知错误"}` ); } finally { setLoading(false); } }, []); /** * 修改视频片段对话内容 * @description 更新视频片段的对话内容,ContentItem数量和ID顺序不能变,只能修改content字段 * @param newContent 新的对话内容数组 */ const updateVideoSegmentContentHandler = useCallback( async (newContent: Array<{ roleId: string; content: string }>) => { if (!videoSegmentEditUseCase) { setError("视频片段编辑用例未初始化"); return; } try { setLoading(true); setError(null); const updatedVideoSegment = await videoSegmentEditUseCase.updateVideoSegmentContent(newContent); setSelectedVideoSegment(new VideoSegmentItem(updatedVideoSegment)); } catch (err) { setError( `修改视频片段对话内容失败: ${ err instanceof Error ? err.message : "未知错误" }` ); } finally { setLoading(false); } }, [videoSegmentEditUseCase] ); /** * 获取用户角色库 * @description 获取当前用户的所有角色库数据 */ const fetchUserRoleLibrary = useCallback(async () => { try { setLoading(true); setError(null); const response = await getUserRoleLibrary(); if (response.successful) { setUserRoleLibrary(response.data); } else { setError(`获取用户角色库失败: ${response.message}`); } } catch (err) { setError( `获取用户角色库失败: ${err instanceof Error ? err.message : "未知错误"}` ); } finally { setLoading(false); } }, []); /** * 替换视频片段角色 * @description 将视频片段中的某个角色替换为角色库中的另一个角色 * @param oldRoleId 旧角色ID * @param newRoleId 新角色ID */ const replaceVideoSegmentRoleHandler = useCallback( async (oldRoleId: string, newRoleId: string) => { if (!selectedVideoSegment) { setError("未选择视频片段"); return; } try { setLoading(true); setError(null); const response = await replaceShotRole({ shotId: selectedVideoSegment.entity.id, oldRoleId, newRoleId, }); if (response.successful) { // 重新获取视频片段详情 await selectVideoSegment(selectedVideoSegment.entity.id); } else { setError(`替换视频片段角色失败: ${response.message}`); } } catch (err) { setError( `替换视频片段角色失败: ${err instanceof Error ? err.message : "未知错误"}` ); } finally { setLoading(false); } }, [selectedVideoSegment, selectVideoSegment] ); /** * 获取视频片段视频剧本内容 * @description 获取视频片段视频的剧本内容,通过接口返回多个ScriptSliceEntity片段 */ const fetchVideoSegmentVideoScript = useCallback(async () => { if (!selectedVideoSegment) { setError("未选择视频片段"); return; } try { setLoading(true); setError(null); const response = await getShotVideoScript({ shotId: selectedVideoSegment.entity.id, }); if (response.successful) { const script = new ScriptValueObject(response.data); setVideoSegmentVideoScript([...script.scriptSlices]); } else { setError(`获取视频片段视频剧本失败: ${response.message}`); } } catch (err) { setError( `获取视频片段视频剧本失败: ${ err instanceof Error ? err.message : "未知错误" }` ); } finally { setLoading(false); } }, [selectedVideoSegment]); /** * 获取视频片段关联的角色信息 * @description 获取当前视频片段可以使用的角色列表 * @returns Promise 角色信息列表 */ const getVideoSegmentRoles = useCallback(async (): Promise => { if (!videoSegmentEditUseCase) { throw new Error("视频片段编辑用例未初始化"); } return await videoSegmentEditUseCase.getVideoSegmentRoles(); }, [videoSegmentEditUseCase]); /** * 获取视频片段关联的场景信息 * @description 获取当前视频片段可以使用的场景列表 * @returns Promise 场景信息列表 */ const getVideoSegmentScenes = useCallback(async (): Promise => { if (!videoSegmentEditUseCase) { throw new Error("视频片段编辑用例未初始化"); } return await videoSegmentEditUseCase.getVideoSegmentScenes(); }, [videoSegmentEditUseCase]); /** * 重新生成视频片段 * @description 使用镜头、对话内容、角色ID替换参数、场景ID替换参数重新生成视频片段 * @param shotPrompt 镜头描述 * @param dialogueContent 对话内容 * @param roleReplaceParams 角色ID替换参数,格式为{oldId:string,newId:string}[] * @param sceneReplaceParams 场景ID替换参数,格式为{oldId:string,newId:string}[] */ const regenerateVideoSegment = useCallback( async ( shotPrompt: LensType[], dialogueContent: ContentItem[], roleReplaceParams: { oldId: string; newId: string }[], sceneReplaceParams: { oldId: string; newId: string }[] ) => { if (!videoSegmentEditUseCase) { setError("视频片段编辑用例未初始化"); return; } try { setLoading(true); setError(null); const updatedVideoSegment = await videoSegmentEditUseCase.regenerateVideoSegment( shotPrompt, dialogueContent, roleReplaceParams, sceneReplaceParams ); setSelectedVideoSegment(new VideoSegmentItem(updatedVideoSegment)); } catch (err) { setError( `重新生成视频片段失败: ${err instanceof Error ? err.message : "未知错误"}` ); } finally { setLoading(false); } }, [videoSegmentEditUseCase] ); return { // 响应式状态 - 用于UI组件订阅和渲染 /** 视频片段列表 - 当前项目的所有视频片段数据 */ videoSegmentList, /** 当前选中的视频片段 - 包含视频片段实体和编辑状态 */ selectedVideoSegment, /** 当前视频片段的草图数据URL - 从视频片段实体中获取的草图图片链接 */ videoSegmentSketchData, /** 当前视频片段的视频数据URL - 从视频片段实体中获取的视频链接 */ videoSegmentVideoData, /** 用户角色库 - 当前用户可用的所有角色数据 */ userRoleLibrary, /** 当前视频片段的视频剧本片段 - 通过接口获取的剧本内容 */ videoSegmentVideoScript, /** 加载状态 - 标识当前是否有异步操作正在进行 */ loading, /** 错误信息 - 记录最近一次操作的错误信息 */ error, // 操作方法 - 提供给UI组件调用的业务逻辑方法 /** 获取视频片段列表 - 根据项目ID获取所有视频片段数据 */ fetchVideoSegmentList, /** 选择视频片段并获取详情 - 选择指定视频片段并初始化相关数据 */ selectVideoSegment, /** 修改视频片段对话内容 - 更新视频片段的对话内容,保持ContentItem结构不变 */ updateVideoSegmentContent: updateVideoSegmentContentHandler, /** 获取用户角色库 - 获取当前用户的所有角色数据 */ fetchUserRoleLibrary, /** 替换视频片段角色 - 将视频片段中的角色替换为角色库中的另一个角色 */ replaceVideoSegmentRole: replaceVideoSegmentRoleHandler, /** 获取视频片段视频剧本内容 - 通过接口获取视频剧本片段 */ fetchVideoSegmentVideoScript, /** 获取视频片段关联的角色信息 - 获取当前视频片段可用的角色列表 */ getVideoSegmentRoles, /** 获取视频片段关联的场景信息 - 获取当前视频片段可用的场景列表 */ getVideoSegmentScenes, /** 重新生成视频片段 - 使用新参数重新生成视频片段内容 */ regenerateVideoSegment, }; };