video-flow-b/app/service/Interaction/ImageStoryService.ts

227 lines
6.5 KiB
TypeScript

import { ImageStoryEntity } from "../domain/Entities";
import { useUploadFile } from "../domain/service";
import { ImageStoryUseCase } from "../usecase/imageStoryUseCase";
import { useState, useCallback, useMemo } from "react";
interface UseImageStoryService {
/** 当前图片故事数据 */
imageStory: Partial<ImageStoryEntity>;
/** 当前活跃的图片地址 */
activeImageUrl: string;
/** 分析故事结果内容 */
analyzedStoryContent: string;
/** 当前选中的分类 */
selectedCategory: string;
/** 是否正在分析图片 */
isAnalyzing: boolean;
/** 是否正在上传 */
isUploading: boolean;
/** 故事类型选项 */
storyTypeOptions: Array<{ key: string; label: string }>;
/** 上传图片并分析 */
uploadAndAnalyzeImage: (imageUrl: string) => Promise<void>;
/** 触发文件选择并自动分析 */
triggerFileSelectionAndAnalyze: () => Promise<void>;
/** 触发生成剧本函数 */
generateScript: () => Promise<string>;
/** 更新故事类型 */
updateStoryType: (storyType: string) => void;
/** 更新故事内容 */
updateStoryContent: (content: string) => void;
/** 重置图片故事数据 */
resetImageStory: () => void;
}
export const useImageStoryServiceHook = (
): UseImageStoryService => {
const [imageStory, setImageStory] = useState<Partial<ImageStoryEntity>>({
imageUrl: "",
imageStory: "",
storyType: "auto",
});
const [isAnalyzing, setIsAnalyzing] = useState(false);
const [isUploading, setIsUploading] = useState(false);
// 使用上传文件Hook
const { uploadFile } = useUploadFile();
/** 图片故事用例实例 */
const imageStoryUseCase = useMemo(() => new ImageStoryUseCase(), []);
/** 当前活跃的图片地址 */
const [activeImageUrl, setActiveImageUrl] = useState<string>("");
/** 分析故事结果内容 */
const [analyzedStoryContent, setAnalyzedStoryContent] = useState<string>("");
/** 当前选中的分类 */
const [selectedCategory, setSelectedCategory] = useState<string>("auto");
/** 故事类型选项 */
const storyTypeOptions = useMemo(() => imageStoryUseCase.getStoryTypeOptions(), [imageStoryUseCase]);
/**
* 上传图片并分析
* @param {string} imageUrl - 已上传的图片URL
*/
const uploadAndAnalyzeImage = useCallback(async (imageUrl: string): Promise<void> => {
try {
setIsUploading(true);
setIsAnalyzing(true);
// 调用用例处理图片上传和分析
await imageStoryUseCase.handleImageUpload(imageUrl);
// 获取更新后的数据
const updatedStory = imageStoryUseCase.getImageStory();
setImageStory(updatedStory);
// 更新活跃状态
setActiveImageUrl(imageUrl);
setAnalyzedStoryContent(updatedStory.imageStory || "");
setSelectedCategory(updatedStory.storyType || "auto");
} catch (error) {
console.error('图片上传分析失败:', error);
throw error;
} finally {
setIsUploading(false);
setIsAnalyzing(false);
}
}, [imageStoryUseCase]);
/**
* 触发生成剧本函数
* @returns {Promise<string>} 生成的剧本ID或内容
*/
const generateScript = useCallback(async (): Promise<string> => {
if (!activeImageUrl) {
throw new Error('请先上传图片');
}
if (!analyzedStoryContent) {
throw new Error('请先输入或生成故事内容');
}
try {
setIsAnalyzing(true);
// 这里可以调用后端API生成剧本
// 暂时返回一个模拟的剧本ID
const scriptId = `script_${Date.now()}`;
// TODO: 实现实际的剧本生成逻辑
// const response = await generateScriptFromImage(imageStory);
// return response.scriptId;
return scriptId;
} catch (error) {
console.error('生成剧本失败:', error);
throw error;
} finally {
setIsAnalyzing(false);
}
}, [activeImageUrl, analyzedStoryContent, imageStory]);
/**
* 更新故事类型
* @param {string} storyType - 新的故事类型
*/
const updateStoryType = useCallback((storyType: string): void => {
imageStoryUseCase.updateStoryType(storyType);
setImageStory(prev => ({ ...prev, storyType }));
setSelectedCategory(storyType);
}, [imageStoryUseCase]);
/**
* 更新故事内容
* @param {string} content - 新的故事内容
*/
const updateStoryContent = useCallback((content: string): void => {
imageStoryUseCase.updateStoryContent(content);
setImageStory(prev => ({ ...prev, imageStory: content }));
setAnalyzedStoryContent(content);
}, [imageStoryUseCase]);
/**
* 重置图片故事数据
*/
const resetImageStory = useCallback((): void => {
imageStoryUseCase.resetImageStory();
setImageStory({
imageUrl: "",
imageStory: "",
storyType: "auto",
});
// 重置活跃状态
setActiveImageUrl("");
setAnalyzedStoryContent("");
setSelectedCategory("auto");
setIsAnalyzing(false);
setIsUploading(false);
}, [imageStoryUseCase]);
/**
* 触发文件选择并自动分析
*/
const triggerFileSelectionAndAnalyze = useCallback(async (): Promise<void> => {
return new Promise((resolve, reject) => {
// 创建文件输入元素
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = "image/*";
fileInput.style.display = "none";
fileInput.onchange = async (e) => {
try {
const target = e.target as HTMLInputElement;
if (target.files && target.files[0]) {
// 使用传入的文件上传函数
const uploadedImageUrl = await uploadFile(target.files[0], (progress) => {
console.log("上传进度:", progress);
});
console.log('uploadedImageUrl', uploadedImageUrl)
// await uploadAndAnalyzeImage(uploadedImageUrl);
setActiveImageUrl(uploadedImageUrl);
}
resolve();
} catch (error) {
reject(error);
} finally {
// 清理DOM
document.body.removeChild(fileInput);
}
};
fileInput.oncancel = () => {
document.body.removeChild(fileInput);
reject();
};
document.body.appendChild(fileInput);
fileInput.click();
});
}, [uploadFile]);
return {
imageStory,
activeImageUrl,
analyzedStoryContent,
selectedCategory,
isAnalyzing,
isUploading,
storyTypeOptions,
uploadAndAnalyzeImage,
triggerFileSelectionAndAnalyze,
generateScript,
updateStoryType,
updateStoryContent,
resetImageStory,
};
};