forked from 77media/video-flow
238 lines
8.5 KiB
TypeScript
238 lines
8.5 KiB
TypeScript
import { StoryTemplateEntity } from "../domain/Entities";
|
||
|
||
/** 模板角色接口 */
|
||
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";
|
||
|
||
interface UseTemplateStoryService {
|
||
/** 模板列表 */
|
||
templateStoryList: StoryTemplateEntity[];
|
||
/** 当前选中要使用的模板 */
|
||
selectedTemplate: StoryTemplateEntity | null;
|
||
/** 当前选中的活跃角色索引 */
|
||
activeRoleIndex: number;
|
||
/** 计算属性:当前活跃角色信息 */
|
||
activeRole: TemplateRole | null;
|
||
/** 加载状态 */
|
||
isLoading: boolean;
|
||
/** 获取模板列表函数 */
|
||
getTemplateStoryList: () => Promise<void>;
|
||
/** action 生成电影函数 */
|
||
actionStory: () => Promise<string>;
|
||
/** 设置选中的模板 */
|
||
setSelectedTemplate: (template: StoryTemplateEntity | null) => void;
|
||
/** 设置活跃角色索引 */
|
||
setActiveRoleIndex: (index: number) => void;
|
||
/** 设置当前活跃角色的图片URL */
|
||
setActiveRoleImage: (imageUrl: string) => void;
|
||
/** 设置当前活跃角色的音频URL */
|
||
setActiveRoleAudio: (audioUrl: string) => void;
|
||
/**清空数据 */
|
||
clearData: () => 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);
|
||
|
||
/** 模板故事用例实例 */
|
||
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();
|
||
|
||
const templates = await new Promise<StoryTemplateEntity[]>((resolve) => {
|
||
setTimeout(() => {
|
||
resolve([
|
||
{
|
||
id: '1',
|
||
name: '奇幻冒险故事',
|
||
image_url: ['/assets/3dr_howlcastle.png', '/assets/3dr_spirited.jpg'],
|
||
generateText: '一个关于勇气与友谊的奇幻冒险故事,主角在神秘世界中寻找失落的宝藏,结识了各种奇特的生物和伙伴。',
|
||
storyRole: [
|
||
{
|
||
role_name: '艾莉娅',
|
||
role_description: '一个勇敢的女孩,拥有强大的魔法力量,她的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_chihiro.png',
|
||
voice_url:""
|
||
},
|
||
{
|
||
role_name: '魔法师梅林',
|
||
role_description: '一个智慧的魔法师,拥有强大的魔法力量,他的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_mono.png',
|
||
voice_url:""
|
||
},
|
||
{
|
||
role_name: '守护者龙',
|
||
role_description: '一个强大的守护者,拥有强大的魔法力量,他的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_howlbg.jpg',
|
||
voice_url:""
|
||
}
|
||
]
|
||
},
|
||
{
|
||
id: '2',
|
||
name: '科幻探索之旅',
|
||
image_url: ['/assets/3dr_monobg.jpg'],
|
||
generateText: '未来世界的太空探索故事,人类在浩瀚宇宙中寻找新的家园,面对未知的挑战和外星文明的接触。',
|
||
storyRole: [
|
||
{
|
||
role_name: '船长凯特',
|
||
role_description: '一个勇敢的船长,拥有强大的魔法力量,他的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_chihiro.png',
|
||
voice_url:""
|
||
},
|
||
{
|
||
role_name: 'AI助手诺娃',
|
||
role_description: '一个强大的AI助手,拥有强大的魔法力量,他的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_mono.png',
|
||
voice_url: ''
|
||
}
|
||
]
|
||
},
|
||
{
|
||
id: '3',
|
||
name: '温馨家庭喜剧',
|
||
image_url: ['/assets/3dr_spirited.jpg'],
|
||
generateText: '一个充满欢笑和温情的家庭故事,讲述家庭成员之间的日常趣事,以及如何一起面对生活中的小挑战。',
|
||
storyRole: [
|
||
{
|
||
role_name: '妈妈莉莉',
|
||
role_description: '一个温柔的妈妈,拥有强大的魔法力量,她的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_chihiro.png',
|
||
voice_url:""
|
||
},
|
||
{
|
||
role_name: '爸爸汤姆',
|
||
role_description: '一个勇敢的爸爸,拥有强大的魔法力量,他的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_mono.png',
|
||
voice_url:""
|
||
},
|
||
{
|
||
role_name: '孩子小杰',
|
||
role_description: '一个聪明的孩子,拥有强大的魔法力量,他的冒险旅程充满了危险和挑战。',
|
||
photo_url: '/assets/3dr_howlbg.jpg',
|
||
voice_url:""
|
||
}
|
||
]
|
||
}
|
||
]);
|
||
}, 10000);
|
||
});
|
||
|
||
setTemplateStoryList(templates);
|
||
setSelectedTemplate(templates[0]);
|
||
} catch (err) {
|
||
console.error('获取模板列表失败:', err);
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
}, [templateStoryUseCase]);
|
||
|
||
/**
|
||
* action 生成电影函数
|
||
*/
|
||
const actionStory = useCallback(async (): Promise<string> => {
|
||
if (!selectedTemplate) {
|
||
throw new Error('请先选择一个故事模板');
|
||
}
|
||
|
||
try {
|
||
setIsLoading(true);
|
||
console.log('selectedTemplate', selectedTemplate)
|
||
// const projectId = await templateStoryUseCase.actionStory(selectedTemplate);
|
||
return 'projectId';
|
||
} catch (err) {
|
||
console.error('生成电影失败:', err);
|
||
throw err;
|
||
} finally {
|
||
setIsLoading(false);
|
||
}
|
||
}, [selectedTemplate, templateStoryUseCase]);
|
||
|
||
/**
|
||
* 设置活跃角色索引
|
||
*/
|
||
const handleSetActiveRoleIndex = useCallback((index: number): void => {
|
||
setActiveRoleIndex(index);
|
||
}, []);
|
||
|
||
/**
|
||
* 设置当前活跃角色的图片URL
|
||
*/
|
||
const setActiveRoleImage = useCallback((imageUrl: string): void => {
|
||
if (!selectedTemplate || activeRoleIndex < 0 || activeRoleIndex >= selectedTemplate.storyRole.length) {
|
||
return;
|
||
}
|
||
|
||
const updatedTemplate = {
|
||
...selectedTemplate,
|
||
storyRole: selectedTemplate.storyRole.map((role, index) =>
|
||
index === activeRoleIndex ? { ...role, photo_url: imageUrl } : role
|
||
),
|
||
};
|
||
setSelectedTemplate(updatedTemplate);
|
||
}, [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]);
|
||
|
||
return {
|
||
templateStoryList,
|
||
selectedTemplate,
|
||
activeRoleIndex,
|
||
activeRole,
|
||
isLoading,
|
||
getTemplateStoryList,
|
||
actionStory,
|
||
setSelectedTemplate,
|
||
setActiveRoleIndex: handleSetActiveRoleIndex,
|
||
setActiveRoleImage,
|
||
setActiveRoleAudio,
|
||
clearData: () => {
|
||
setTemplateStoryList([]);
|
||
setSelectedTemplate(null);
|
||
setActiveRoleIndex(0);
|
||
}
|
||
};
|
||
};
|