forked from 77media/video-flow
250 lines
7.3 KiB
TypeScript
250 lines
7.3 KiB
TypeScript
import { message } from "antd";
|
|
import { StoryTemplateEntity } from "../domain/Entities";
|
|
import { useUploadFile } from "../domain/service";
|
|
|
|
/** 模板角色接口 */
|
|
interface TemplateRole {
|
|
/** 角色名 */
|
|
role_name: string;
|
|
/** 照片URL */
|
|
photo_url: string;
|
|
/** 声音URL */
|
|
voice_url: string;
|
|
}
|
|
import { TemplateStoryUseCase } from "../usecase/templateStoryUseCase";
|
|
import { getUploadToken, uploadToQiniu } from "@/api/common";
|
|
import { useState, useCallback, useMemo } from "react";
|
|
import { createMovieProjectV3 } from "@/api/movie_start";
|
|
import { CreateMovieProjectV3Request } from "@/api/DTO/movie_start_dto";
|
|
|
|
interface UseTemplateStoryService {
|
|
/** 模板列表 */
|
|
templateStoryList: StoryTemplateEntity[];
|
|
/** 当前选中要使用的模板 */
|
|
selectedTemplate: StoryTemplateEntity | null;
|
|
/** 当前选中的活跃角色索引 */
|
|
activeRoleIndex: number;
|
|
/** 计算属性:当前活跃角色信息 */
|
|
activeRole: TemplateRole | null;
|
|
/** 加载状态 */
|
|
isLoading: boolean;
|
|
/** 获取模板列表函数 */
|
|
/** 获取模板列表函数 */
|
|
getTemplateStoryList: () => Promise<void>;
|
|
/**
|
|
* action 生成电影函数
|
|
* @param {string} user_id - 用户ID
|
|
* @param {"auto" | "manual"} mode - 生成模式
|
|
* @param {"720p" | "1080p" | "4k"} resolution - 分辨率
|
|
* @param {string} language - 语言
|
|
* @returns {Promise<string>} - 生成的电影ID
|
|
*/
|
|
actionStory: (
|
|
user_id: string,
|
|
mode: "auto" | "manual",
|
|
resolution: "720p" | "1080p" | "4k" ,
|
|
language: string
|
|
) => Promise<string|undefined>;
|
|
/** 设置选中的模板 */
|
|
setSelectedTemplate: (template: StoryTemplateEntity | null) => void;
|
|
/** 设置活跃角色索引 */
|
|
setActiveRoleIndex: (index: number) => void;
|
|
|
|
/** 设置当前活跃角色的音频URL */
|
|
setActiveRoleAudio: (audioUrl: string) => void;
|
|
/**清空数据 */
|
|
clearData: () => void;
|
|
/** 上传人物头像并分析 */
|
|
AvatarAndAnalyzeFeatures: (imageUrl: string) => Promise<void>;
|
|
}
|
|
|
|
export const useTemplateStoryServiceHook = (): UseTemplateStoryService => {
|
|
const [templateStoryList, setTemplateStoryList] = useState<
|
|
StoryTemplateEntity[]
|
|
>([]);
|
|
const [selectedTemplate, setSelectedTemplate] =
|
|
useState<StoryTemplateEntity | null>(null);
|
|
const [activeRoleIndex, setActiveRoleIndex] = useState<number>(0);
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
// 使用上传文件Hook
|
|
const { uploadFile } = useUploadFile();
|
|
|
|
/** 模板故事用例实例 */
|
|
const templateStoryUseCase = useMemo(() => new TemplateStoryUseCase(), []);
|
|
|
|
/** 计算属性:当前活跃角色信息 */
|
|
const activeRole = useMemo(() => {
|
|
if (
|
|
!selectedTemplate ||
|
|
activeRoleIndex < 0 ||
|
|
activeRoleIndex >= selectedTemplate.storyRole.length
|
|
) {
|
|
return null;
|
|
}
|
|
return selectedTemplate.storyRole[activeRoleIndex];
|
|
}, [selectedTemplate, activeRoleIndex]);
|
|
|
|
/**
|
|
* 获取模板列表函数
|
|
*/
|
|
const getTemplateStoryList = useCallback(async (): Promise<void> => {
|
|
try {
|
|
setIsLoading(true);
|
|
|
|
const templates = await templateStoryUseCase.getTemplateStoryList();
|
|
|
|
setTemplateStoryList(templates);
|
|
setSelectedTemplate(templates[0]);
|
|
setActiveRoleIndex(0);
|
|
console.log(selectedTemplate, activeRoleIndex)
|
|
} catch (err) {
|
|
console.error("获取模板列表失败:", err);
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}, [templateStoryUseCase]);
|
|
|
|
/**
|
|
* 设置活跃角色索引
|
|
*/
|
|
const handleSetActiveRoleIndex = useCallback((index: number): void => {
|
|
setActiveRoleIndex(index);
|
|
}, []);
|
|
|
|
/**
|
|
* 设置当前活跃角色的图片URL
|
|
*/
|
|
const setActiveRoleData = useCallback(
|
|
(imageUrl: string, desc: string): void => {
|
|
if (
|
|
!selectedTemplate ||
|
|
activeRoleIndex < 0 ||
|
|
activeRoleIndex >= selectedTemplate.storyRole.length
|
|
) {
|
|
console.log(selectedTemplate, activeRoleIndex);
|
|
return;
|
|
}
|
|
try {
|
|
|
|
const character_briefs = {
|
|
name: selectedTemplate.storyRole[activeRoleIndex].role_name,
|
|
image_url: imageUrl,
|
|
character_analysis: JSON.parse(desc).character_analysis,
|
|
};
|
|
console.log("character_briefs", character_briefs);
|
|
const updatedTemplate = {
|
|
...selectedTemplate,
|
|
storyRole: selectedTemplate.storyRole.map((role, index) =>
|
|
index === activeRoleIndex
|
|
? {
|
|
...role,
|
|
photo_url: imageUrl,
|
|
role_description: JSON.stringify(character_briefs),
|
|
}
|
|
: role
|
|
),
|
|
};
|
|
|
|
setSelectedTemplate(updatedTemplate);
|
|
} catch (error) {
|
|
message.error("Image analysis failed");
|
|
console.log("error", error);
|
|
}
|
|
},
|
|
[selectedTemplate, activeRoleIndex]
|
|
);
|
|
|
|
/**
|
|
* 设置当前活跃角色的音频URL
|
|
*/
|
|
const setActiveRoleAudio = useCallback(
|
|
(audioUrl: string): void => {
|
|
if (
|
|
!selectedTemplate ||
|
|
activeRoleIndex < 0 ||
|
|
activeRoleIndex >= selectedTemplate.storyRole.length
|
|
) {
|
|
return;
|
|
}
|
|
|
|
const updatedTemplate = {
|
|
...selectedTemplate,
|
|
storyRole: selectedTemplate.storyRole.map((role, index) =>
|
|
index === activeRoleIndex ? { ...role, voice_url: audioUrl } : role
|
|
),
|
|
};
|
|
setSelectedTemplate(updatedTemplate);
|
|
},
|
|
[selectedTemplate, activeRoleIndex]
|
|
);
|
|
|
|
/**
|
|
* 上传人物头像并分析特征,替换旧的角色数据
|
|
* @param {string} characterName - 角色名称
|
|
*/
|
|
const AvatarAndAnalyzeFeatures = useCallback(
|
|
async (imageUrl: string): Promise<void> => {
|
|
try {
|
|
setIsLoading(true);
|
|
|
|
// 调用用例处理人物头像上传和特征分析
|
|
const result = await templateStoryUseCase.AvatarAndAnalyzeFeatures(
|
|
imageUrl
|
|
);
|
|
|
|
setActiveRoleData(result.crop_url, result.whisk_caption);
|
|
console.log("人物头像和特征描述更新成功:", result);
|
|
} catch (error) {
|
|
console.error("人物头像上传和特征分析失败:", error);
|
|
throw error;
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
},
|
|
[templateStoryUseCase]
|
|
);
|
|
const actionStory = useCallback(
|
|
async (
|
|
user_id: string,
|
|
mode: "auto" | "manual" = "auto",
|
|
resolution: "720p" | "1080p" | "4k" = "720p",
|
|
language: string = "English"
|
|
) => {
|
|
try {
|
|
const params: CreateMovieProjectV3Request = {
|
|
user_id,
|
|
mode,
|
|
resolution,
|
|
storyRole: selectedTemplate?.storyRole || [],
|
|
language,
|
|
template_id: selectedTemplate?.template_id || "",
|
|
};
|
|
|
|
const result = await createMovieProjectV3(params);
|
|
return result.data.project_id as string;
|
|
} catch (error) {
|
|
console.error("创建电影项目失败:", error);
|
|
}
|
|
},
|
|
[selectedTemplate]
|
|
);
|
|
return {
|
|
templateStoryList,
|
|
selectedTemplate,
|
|
activeRoleIndex,
|
|
activeRole,
|
|
isLoading,
|
|
getTemplateStoryList,
|
|
actionStory,
|
|
setSelectedTemplate,
|
|
setActiveRoleIndex: handleSetActiveRoleIndex,
|
|
setActiveRoleAudio,
|
|
AvatarAndAnalyzeFeatures,
|
|
clearData: () => {
|
|
setTemplateStoryList([]);
|
|
setSelectedTemplate(null);
|
|
setActiveRoleIndex(0);
|
|
},
|
|
};
|
|
};
|