forked from 77media/video-flow
227 lines
6.3 KiB
TypeScript
227 lines
6.3 KiB
TypeScript
import { ImageStoryEntity } from "../domain/Entities";
|
||
import { AIGenerateImageStory } from "@/api/movie_start";
|
||
import { MovieStartDTO, CharacterAnalysis } from "@/api/DTO/movie_start_dto";
|
||
|
||
/**
|
||
* 图片故事用例
|
||
* 负责管理图片故事模式的业务逻辑,包括图片上传、AI分析和故事生成
|
||
*/
|
||
export class ImageStoryUseCase {
|
||
/** 当前图片故事数据 */
|
||
imageStory: ImageStoryEntity = {
|
||
id: "",
|
||
imageAnalysis: "",
|
||
roleImage: [],
|
||
imageUrl: "",
|
||
imageStory: "",
|
||
storyType: "",
|
||
};
|
||
|
||
/** 故事梗概 */
|
||
storyLogline: string = "";
|
||
|
||
/** 角色头像及名称数据 */
|
||
charactersAnalysis: CharacterAnalysis[] = [];
|
||
|
||
/** 分类数据 */
|
||
potentialGenres: string[] = [];
|
||
|
||
/** 是否正在分析图片 */
|
||
isAnalyzing: boolean = false;
|
||
|
||
/** 是否正在上传 */
|
||
isUploading: boolean = false;
|
||
constructor() {}
|
||
|
||
|
||
|
||
/**
|
||
* 设置图片故事数据
|
||
* @param {Partial<ImageStoryEntity>} data - 要设置的图片故事数据
|
||
*/
|
||
setImageStory(data: Partial<ImageStoryEntity>): void {
|
||
this.imageStory = { ...this.imageStory, ...data };
|
||
}
|
||
|
||
/**
|
||
* 重置图片故事数据
|
||
*/
|
||
resetImageStory(): void {
|
||
this.imageStory = {
|
||
id: "",
|
||
imageAnalysis: "",
|
||
roleImage: [],
|
||
imageUrl: "",
|
||
imageStory: "",
|
||
storyType: "",
|
||
};
|
||
this.storyLogline = "";
|
||
this.charactersAnalysis = [];
|
||
this.potentialGenres = [];
|
||
this.isAnalyzing = false;
|
||
this.isUploading = false;
|
||
}
|
||
|
||
/**
|
||
* 处理图片上传
|
||
* @param {string} imageUrl - 已上传的图片URL
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async handleImageUpload(imageUrl: string) {
|
||
try {
|
||
this.isUploading = false; // 图片已上传,设置上传状态为false
|
||
this.isAnalyzing = true;
|
||
console.log('imageUrl', imageUrl)
|
||
// 设置上传后的图片URL
|
||
this.setImageStory({ imageUrl });
|
||
|
||
// 调用AI分析接口
|
||
return await this.analyzeImageWithAI();
|
||
|
||
} catch (error) {
|
||
console.error("图片分析失败:", error);
|
||
// 分析失败时清空图片URL
|
||
this.setImageStory({ imageUrl: "" });
|
||
throw error;
|
||
} finally {
|
||
this.isAnalyzing = false;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 使用AI分析图片
|
||
* @returns {Promise<void>}
|
||
*/
|
||
async analyzeImageWithAI() {
|
||
console.log('this.imageStory.imageUrl', this.imageStory.imageUrl)
|
||
try {
|
||
//
|
||
// 调用AI分析接口
|
||
const response = await AIGenerateImageStory({
|
||
image_url: this.imageStory.imageUrl || "",
|
||
user_text: this.imageStory.imageStory || "",
|
||
});
|
||
|
||
if (response.successful && response.data) {
|
||
// 解析并存储新的数据结构
|
||
this.parseAndStoreAnalysisData(response.data);
|
||
|
||
// 组合成ImageStoryEntity
|
||
this.composeImageStoryEntity(response.data);
|
||
return this.imageStory;
|
||
} else {
|
||
throw new Error("AI分析失败");
|
||
}
|
||
} catch (error) {
|
||
console.error("AI分析失败:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析并存储分析数据到类属性中
|
||
* @param {MovieStartDTO} data - AI分析返回的数据
|
||
*/
|
||
parseAndStoreAnalysisData(data: MovieStartDTO): void {
|
||
// 存储故事梗概
|
||
this.storyLogline = data.story_logline || "";
|
||
|
||
// 存储角色头像及名称数据
|
||
this.charactersAnalysis = data.characters_analysis || [];
|
||
|
||
// 存储分类数据
|
||
this.potentialGenres = data.potential_genres || [];
|
||
}
|
||
|
||
/**
|
||
* 组合成ImageStoryEntity
|
||
* @param {MovieStartDTO} data - AI分析返回的数据
|
||
*/
|
||
composeImageStoryEntity(data: MovieStartDTO): void {
|
||
// 将角色数据转换为ImageStoryEntity需要的格式
|
||
const roleImage = data.characters_analysis?.map(character => ({
|
||
name: character.role_name,
|
||
avatar_url: "", // 这里需要根据实际情况设置头像URL
|
||
region: {
|
||
x: character.region?.x || 0,
|
||
y: character.region?.y || 0,
|
||
width: character.region?.width || 0,
|
||
height: character.region?.height || 0,
|
||
},
|
||
|
||
})) || [];
|
||
|
||
// 更新ImageStoryEntity
|
||
this.setImageStory({
|
||
...this.imageStory,
|
||
imageAnalysis: data.story_logline || "",
|
||
storyType: data.potential_genres[0] || "", // 使用第一个分类作为故事类型
|
||
roleImage,
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 更新故事类型
|
||
* @param {string} storyType - 新的故事类型
|
||
*/
|
||
updateStoryType(storyType: string): void {
|
||
this.setImageStory({ storyType });
|
||
}
|
||
|
||
/**
|
||
* 更新故事内容
|
||
* @param {string} storyContent - 新的故事内容
|
||
*/
|
||
updateStoryContent(storyContent: string): void {
|
||
this.setImageStory({ imageStory: storyContent });
|
||
}
|
||
/**
|
||
* 处理角色数据,解析并存储到类属性中
|
||
* @param {CharacterAnalysis[]} characters - 角色分析数据
|
||
*/
|
||
processCharacterData(characters: CharacterAnalysis[]): void {
|
||
this.charactersAnalysis = characters.map(character => ({
|
||
...character,
|
||
region: {
|
||
x: character.region?.x || 0,
|
||
y: character.region?.y || 0,
|
||
width: character.region?.width || 0,
|
||
height: character.region?.height || 0,
|
||
}
|
||
}));
|
||
}
|
||
|
||
/**
|
||
* 获取指定角色的区域坐标
|
||
* @param {string} characterName - 角色名称
|
||
* @returns {CharacterAnalysis['region'] | null} 角色区域坐标,如果未找到则返回null
|
||
*/
|
||
getCharacterRegion(characterName: string): CharacterAnalysis['region'] | null {
|
||
const character = this.charactersAnalysis.find(char => char.role_name === characterName);
|
||
return character ? character.region : null;
|
||
}
|
||
|
||
/**
|
||
* 更新角色头像URL
|
||
* @param {string} characterName - 角色名称
|
||
* @param {string} avatarUrl - 头像URL
|
||
*/
|
||
updateCharacterAvatar(characterName: string, avatarUrl: string): void {
|
||
const character = this.charactersAnalysis.find(char => char.role_name === characterName);
|
||
if (character) {
|
||
// 更新角色头像URL(这里需要根据实际的数据结构来调整)
|
||
// 由于CharacterAnalysis接口中没有avatar_url字段,这里只是示例
|
||
console.log(`更新角色 ${characterName} 的头像URL: ${avatarUrl}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取所有角色名称
|
||
* @returns {string[]} 角色名称数组
|
||
*/
|
||
getAllCharacterNames(): string[] {
|
||
return this.charactersAnalysis.map(char => char.role_name);
|
||
}
|
||
}
|
||
|