video-flow-b/app/service/usecase/ShotEditUsecase.ts

205 lines
7.1 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 { VideoSegmentEntity, RoleEntity, SceneEntity, AITextEntity, TagEntity } from '../domain/Entities';
import { ContentItem, LensType } from '../domain/valueObject';
import { VideoSegmentItem, RoleItem, SceneItem, TextItem, TagItem } from '../domain/Item';
import {
getShotRoles,
getShotScenes,
getShotData,
regenerateShot,
updateShotContent
} from '@/api/video_flow';
/**
* 视频片段编辑用例
* 负责视频片段内容的初始化、修改和优化
*/
export class VideoSegmentEditUseCase {
constructor(private videoSegmentItem: VideoSegmentItem) {
}
/**
* 获取视频片段关联的角色信息列表
* @description 获取当前视频片段可以使用的角色列表
* @returns Promise<RoleEntity[]> 角色信息列表
* @throws {Error} 当API调用失败时抛出错误
*/
async getVideoSegmentRoles(): Promise<RoleEntity[]> {
const videoSegmentId = this.videoSegmentItem.entity.id;
if (!videoSegmentId) {
throw new Error('视频片段ID不存在无法获取角色信息');
}
const response = await getShotRoles({
shotId: videoSegmentId
});
if (response.successful) {
return response.data;
} else {
throw new Error(`获取视频片段角色信息失败: ${response.message}`);
}
}
/**
* 获取视频片段关联的场景信息列表
* @description 获取当前视频片段可以使用的场景列表
* @returns Promise<SceneEntity[]> 场景信息列表
* @throws {Error} 当API调用失败时抛出错误
*/
async getVideoSegmentScenes(): Promise<SceneEntity[]> {
const videoSegmentId = this.videoSegmentItem.entity.id;
if (!videoSegmentId) {
throw new Error('视频片段ID不存在无法获取场景信息');
}
const response = await getShotScenes({
shotId: videoSegmentId
});
if (response.successful) {
return response.data;
} else {
throw new Error(`获取视频片段场景信息失败: ${response.message}`);
}
}
/**
* 重新获取当前视频片段信息
* @description 从服务器重新获取当前视频片段的详细数据,并更新当前实体
* @returns Promise<{ text: AITextEntity; tags: TagEntity[] }> 视频片段相关的AI文本和标签数据
* @throws {Error} 当API调用失败时抛出错误
*/
async refreshVideoSegmentData(): Promise<{ text: AITextEntity; tags: TagEntity[] }> {
const videoSegmentId = this.videoSegmentItem.entity.id;
if (!videoSegmentId) {
throw new Error('视频片段ID不存在无法获取视频片段数据');
}
const response = await getShotData({
shotId: videoSegmentId
});
if (response.successful) {
// 更新当前视频片段的实体数据
const { text, tags } = response.data;
// 更新视频片段实体中的相关字段
const updatedVideoSegmentEntity = {
...this.videoSegmentItem.entity,
generateTextId: text.id, // 更新AI文本ID
tagIds: tags.map((tag: TagEntity) => tag.id), // 更新标签ID列表
updatedAt: Date.now(), // 更新时间戳
};
// 更新当前UseCase中的实体
this.videoSegmentItem.setEntity(updatedVideoSegmentEntity);
// 检查状态是否需要更新为视频状态
this.checkAndUpdateVideoStatus(updatedVideoSegmentEntity);
return response.data;
} else {
throw new Error(`获取视频片段数据失败: ${response.message}`);
}
}
/**
* 重新生成当前视频片段
* @description 使用镜头、对话内容、角色ID替换参数、场景ID替换参数重新生成视频片段
* @param shotPrompt 镜头描述
* @param dialogueContent 对话内容
* @param roleReplaceParams 角色ID替换参数格式为{oldId:string,newId:string}[]
* @param sceneReplaceParams 场景ID替换参数格式为{oldId:string,newId:string}[]
* @returns Promise<VideoSegmentEntity> 重新生成的视频片段实体
* @throws {Error} 当API调用失败时抛出错误
*/
async regenerateVideoSegment(
shotPrompt: LensType[],
dialogueContent: ContentItem[],
roleReplaceParams: { oldId: string; newId: string }[],
sceneReplaceParams: { oldId: string; newId: string }[]
): Promise<VideoSegmentEntity> {
const videoSegmentId = this.videoSegmentItem.entity.id;
if (!videoSegmentId) {
throw new Error('视频片段ID不存在无法重新生成视频片段');
}
// 调用重新生成视频片段接口
const response = await regenerateShot({
shotId: videoSegmentId,
shotPrompt: shotPrompt,
dialogueContent: dialogueContent,
roleReplaceParams: roleReplaceParams,
sceneReplaceParams: sceneReplaceParams,
});
if (response.successful) {
const videoSegmentEntity = response.data;
this.videoSegmentItem.setEntity(videoSegmentEntity);
// 检查状态是否需要更新为视频状态
this.checkAndUpdateVideoStatus(videoSegmentEntity);
return videoSegmentEntity;
} else {
throw new Error(`重新生成视频片段失败: ${response.message}`);
}
}
/**
* 修改视频片段对话内容
* @description 更新视频片段的对话内容ContentItem数量和ID顺序不能变只能修改content字段
* @param newContent 新的对话内容数组
* @returns Promise<VideoSegmentEntity> 修改后的视频片段实体
* @throws {Error} 当API调用失败时抛出错误
*/
async updateVideoSegmentContent(newContent: Array<{ roleId: string; content: string }>): Promise<VideoSegmentEntity> {
const videoSegmentId = this.videoSegmentItem.entity.id;
if (!videoSegmentId) {
throw new Error('视频片段ID不存在无法修改对话内容');
}
// 验证ContentItem数量和ID顺序
const currentContent = this.videoSegmentItem.entity.content;
if (newContent.length !== currentContent.length) {
throw new Error('ContentItem数量不能改变');
}
// 验证角色ID顺序
for (let i = 0; i < newContent.length; i++) {
if (newContent[i].roleId !== currentContent[i].roleId) {
throw new Error('ContentItem的roleId顺序不能改变');
}
}
const response = await updateShotContent({
shotId: videoSegmentId,
content: newContent,
});
if (response.successful) {
const videoSegmentEntity = response.data;
this.videoSegmentItem.setEntity(videoSegmentEntity);
// 检查状态是否需要更新为视频状态
this.checkAndUpdateVideoStatus(videoSegmentEntity);
return videoSegmentEntity;
} else {
throw new Error(`修改视频片段对话内容失败: ${response.message}`);
}
}
/**
* 检查并更新视频状态
* @description 当视频片段状态变为视频加载中或完成时调用updateToVideoStatus
* @param videoSegmentEntity 视频片段实体
*/
private checkAndUpdateVideoStatus(videoSegmentEntity: VideoSegmentEntity): void {
// 当状态为视频加载中或完成时,更新为视频状态
if (videoSegmentEntity.status === 1 || videoSegmentEntity.status === 2) { // videoLoading 或 finished
this.videoSegmentItem.updateToVideoStatus();
}
}
}