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