326 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useCallback } from "react";
import { VideoSegmentEditUseCase } from "../usecase/ShotEditUsecase";
import { VideoSegmentEntity } from "../domain/Entities";
import { ContentItem, LensType } from "../domain/valueObject";
/**
* 视频片段服务Hook接口
* 定义视频片段服务Hook的所有状态和操作方法
*/
export interface UseShotService {
// 响应式状态
/** 加载状态 */
loading: boolean;
/** 视频片段列表 */
videoSegments: VideoSegmentEntity[];
/** 当前选中的视频片段 */
selectedSegment: VideoSegmentEntity | null;
/** 错误信息 */
error: string | null;
// 操作方法
/** 获取视频片段列表 */
getVideoSegmentList: (projectId: string) => Promise<void>;
/** 重新生成视频片段 */
regenerateVideoSegment: (
shotPrompt: LensType[],
shotId?: string,
roleReplaceParams?: { oldId: string; newId: string }[],
sceneReplaceParams?: { oldId: string; newId: string }[]
) => Promise<VideoSegmentEntity>;
/** AI优化视频内容 */
optimizeVideoContent: (
shotId: string,
userRequirement: string,
lensData: LensType[]
) => Promise<LensType[]>;
/** 更新视频内容 */
updateVideoContent: (
shotId: string,
content: Array<{ roleId: string; content: string }>
) => Promise<VideoSegmentEntity>;
/** 中断当前操作 */
abortOperation: () => void;
/** 设置选中的视频片段 */
setSelectedSegment: (segment: VideoSegmentEntity | null) => void;
/** 清除错误信息 */
clearError: () => void;
}
/**
* 视频片段服务Hook
* 提供视频片段相关的所有状态管理和操作方法
* 包括获取视频列表、重新生成视频、AI优化等功能
*/
export const useShotService = (): UseShotService => {
// 响应式状态
const [loading, setLoading] = useState<boolean>(false);
const [videoSegments, setVideoSegments] = useState<VideoSegmentEntity[]>([]);
const [selectedSegment, setSelectedSegment] = useState<VideoSegmentEntity | null>(null);
const [error, setError] = useState<string | null>(null);
// UseCase实例
const [shotEditUseCase] = useState<VideoSegmentEditUseCase>(
new VideoSegmentEditUseCase()
);
/**
* 获取视频片段列表
* @param projectId 项目ID
*/
const getVideoSegmentList = useCallback(
async (projectId: string): Promise<void> => {
try {
setLoading(true);
setError(null);
const segments = await shotEditUseCase.getVideoSegmentList(projectId);
setVideoSegments(segments);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "获取视频片段列表失败";
setError(errorMessage);
console.error("获取视频片段列表失败:", error);
} finally {
setLoading(false);
}
},
[shotEditUseCase]
);
/**
* 重新生成视频片段
* @param shotPrompt 镜头描述数据
* @param shotId 视频片段ID可选
* @param roleReplaceParams 角色替换参数(可选)
* @param sceneReplaceParams 场景替换参数(可选)
* @returns Promise<VideoSegmentEntity> 重新生成的视频片段
*/
const regenerateVideoSegment = useCallback(
async (
shotPrompt: LensType[],
shotId?: string,
roleReplaceParams?: { oldId: string; newId: string }[],
sceneReplaceParams?: { oldId: string; newId: string }[]
): Promise<VideoSegmentEntity> => {
try {
setLoading(true);
setError(null);
const regeneratedSegment = await shotEditUseCase.regenerateVideoSegment(
shotPrompt,
shotId,
roleReplaceParams,
sceneReplaceParams
);
// 如果重新生成的是现有片段,更新列表中的对应项
if (shotId) {
setVideoSegments(prev =>
prev.map(segment =>
segment.id === shotId ? regeneratedSegment : segment
)
);
} else {
// 如果是新生成的片段,添加到列表中
setVideoSegments(prev => [...prev, regeneratedSegment]);
}
return regeneratedSegment;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "重新生成视频片段失败";
setError(errorMessage);
console.error("重新生成视频片段失败:", error);
throw error;
} finally {
setLoading(false);
}
},
[shotEditUseCase]
);
/**
* AI优化视频内容
* @param shotId 视频片段ID
* @param userRequirement 用户优化需求
* @param lensData 镜头数据数组
* @returns Promise<LensType[]> 优化后的镜头数据
*/
const optimizeVideoContent = useCallback(
async (
shotId: string,
userRequirement: string,
lensData: LensType[]
): Promise<LensType[]> => {
try {
setLoading(true);
setError(null);
const optimizedLensData = await shotEditUseCase.optimizeVideoContent(
shotId,
userRequirement,
lensData
);
// 注意这里不再更新videoSegments状态因为返回的是LensType[]而不是VideoSegmentEntity
// 调用者需要自己处理优化后的镜头数据
return optimizedLensData;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "AI优化视频内容失败";
setError(errorMessage);
console.error("AI优化视频内容失败:", error);
throw error;
} finally {
setLoading(false);
}
},
[shotEditUseCase]
);
/**
* 更新视频内容
* @param shotId 视频片段ID
* @param content 新的对话内容
* @returns Promise<VideoSegmentEntity> 更新后的视频片段
*/
const updateVideoContent = useCallback(
async (
shotId: string,
content: Array<{ roleId: string; content: string }>
): Promise<VideoSegmentEntity> => {
try {
setLoading(true);
setError(null);
const updatedSegment = await shotEditUseCase.updateVideoContent(
shotId,
content
);
// 更新列表中的对应项
setVideoSegments(prev =>
prev.map(segment =>
segment.id === shotId ? updatedSegment : segment
)
);
return updatedSegment;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : "更新视频内容失败";
setError(errorMessage);
console.error("更新视频内容失败:", error);
throw error;
} finally {
setLoading(false);
}
},
[shotEditUseCase]
);
/**
* 中断当前操作
*/
const abortOperation = useCallback((): void => {
shotEditUseCase.abortOperation();
setLoading(false);
}, [shotEditUseCase]);
/**
* 设置选中的视频片段
*/
const setSelectedSegmentHandler = useCallback((segment: VideoSegmentEntity | null): void => {
setSelectedSegment(segment);
}, []);
/**
* 清除错误信息
*/
const clearError = useCallback((): void => {
setError(null);
}, []);
return {
// 响应式状态
loading,
videoSegments,
selectedSegment,
error,
// 操作方法
getVideoSegmentList,
regenerateVideoSegment,
optimizeVideoContent,
updateVideoContent,
abortOperation,
setSelectedSegment: setSelectedSegmentHandler,
clearError,
};
};
/**
* 使用示例:
*
* ```tsx
* import { useShotService } from '@/app/service/Interaction/ShotService';
*
* const VideoSegmentComponent = () => {
* const {
* loading,
* videoSegments,
* selectedSegment,
* error,
* getVideoSegmentList,
* regenerateVideoSegment,
* optimizeVideoContent,
* updateVideoContent,
* setSelectedSegment,
* clearError
* } = useShotService();
*
* // 获取视频片段列表
* useEffect(() => {
* getVideoSegmentList('project-id');
* }, [getVideoSegmentList]);
*
* // 重新生成视频片段
* const handleRegenerate = async () => {
* try {
* await regenerateVideoSegment([
* new LensType('特写', '镜头描述', '运镜')
* ]);
* } catch (error) {
* console.error('重新生成失败:', error);
* }
* };
*
* // AI优化镜头数据
* const handleOptimize = async () => {
* try {
* const optimizedLensData = await optimizeVideoContent(
* 'shot-id',
* '让镜头更加动态',
* [new LensType('特写', '当前镜头描述', '运镜')]
* );
*
* // 处理优化后的镜头数据
* console.log('优化后的镜头数据:', optimizedLensData);
* } catch (error) {
* console.error('优化失败:', error);
* }
* };
*
* return (
* <div>
* {loading && <div>加载中...</div>}
* {error && <div>错误: {error}</div>}
* {videoSegments.map(segment => (
* <div key={segment.id}>
* <h3>{segment.name}</h3>
* <p>状态: {segment.status}</p>
* </div>
* ))}
* </div>
* );
* };
* ```
*/