forked from 77media/video-flow
新的阶段
This commit is contained in:
parent
e405f4bd7d
commit
85687f5840
@ -45,6 +45,41 @@ export interface MovieStartDTO {
|
|||||||
/** 错误信息 */
|
/** 错误信息 */
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 电影故事任务详情 */
|
||||||
|
export interface MovieStoryTaskDetail {
|
||||||
|
/** 任务ID */
|
||||||
|
task_id: string;
|
||||||
|
/** 状态 */
|
||||||
|
status: string;
|
||||||
|
/** 进度 */
|
||||||
|
progress: number;
|
||||||
|
/** 当前步骤 */
|
||||||
|
current_step: string;
|
||||||
|
/** 步骤消息 */
|
||||||
|
step_message: string;
|
||||||
|
/** 已用时间 */
|
||||||
|
elapsed_time: number;
|
||||||
|
/** 预计剩余时间 */
|
||||||
|
estimated_remaining: number | null;
|
||||||
|
/** 错误信息 */
|
||||||
|
error_message: string | null;
|
||||||
|
/** 结果 */
|
||||||
|
result: MovieStartDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**图片分析出故事的任务相关数据,用于轮询查状态 */
|
||||||
|
export interface StoryAnalysisTask{
|
||||||
|
/** 任务ID */
|
||||||
|
task_id:string;
|
||||||
|
/** 状态 */
|
||||||
|
status:string;
|
||||||
|
/** 消息 */
|
||||||
|
message:string;
|
||||||
|
/** 预计时长 */
|
||||||
|
estimated_duration:number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建电影项目V2请求参数 照片生成电影
|
* 创建电影项目V2请求参数 照片生成电影
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,5 +1,11 @@
|
|||||||
import { ApiResponse } from "./common";
|
import { ApiResponse } from "./common";
|
||||||
import { CreateMovieProjectV2Request, CreateMovieProjectResponse, MovieStartDTO } from "./DTO/movie_start_dto";
|
import {
|
||||||
|
CreateMovieProjectV2Request,
|
||||||
|
CreateMovieProjectResponse,
|
||||||
|
MovieStartDTO,
|
||||||
|
StoryAnalysisTask,
|
||||||
|
MovieStoryTaskDetail,
|
||||||
|
} from "./DTO/movie_start_dto";
|
||||||
import { get, post } from "./request";
|
import { get, post } from "./request";
|
||||||
import {
|
import {
|
||||||
StoryTemplateEntity,
|
StoryTemplateEntity,
|
||||||
@ -30,7 +36,7 @@ export const AIGenerateImageStory = async (request: {
|
|||||||
image_url: string;
|
image_url: string;
|
||||||
user_text: string;
|
user_text: string;
|
||||||
}) => {
|
}) => {
|
||||||
return await post<ApiResponse<MovieStartDTO>>(
|
return await post<ApiResponse<StoryAnalysisTask>>(
|
||||||
"/movie_story/generate",
|
"/movie_story/generate",
|
||||||
request
|
request
|
||||||
);
|
);
|
||||||
@ -63,3 +69,14 @@ export const createMovieProjectV3 = async (
|
|||||||
request
|
request
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取电影故事任务详情
|
||||||
|
* @param taskId - 任务ID
|
||||||
|
* @returns Promise<ApiResponse<MovieStoryTaskDetail>>
|
||||||
|
*/
|
||||||
|
export const getMovieStoryTask = async (taskId: string) => {
|
||||||
|
return await get<ApiResponse<MovieStoryTaskDetail>>(
|
||||||
|
`/movie_story/task/${taskId}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@ -8,7 +8,11 @@ import {
|
|||||||
Dispatch,
|
Dispatch,
|
||||||
SetStateAction,
|
SetStateAction,
|
||||||
} from "react";
|
} from "react";
|
||||||
import { CharacterAnalysis, CreateMovieProjectV2Request, CreateMovieProjectResponse } from "@/api/DTO/movie_start_dto";
|
import {
|
||||||
|
CharacterAnalysis,
|
||||||
|
CreateMovieProjectV2Request,
|
||||||
|
CreateMovieProjectResponse,
|
||||||
|
} from "@/api/DTO/movie_start_dto";
|
||||||
import { createMovieProjectV2 } from "@/api/movie_start";
|
import { createMovieProjectV2 } from "@/api/movie_start";
|
||||||
|
|
||||||
interface UseImageStoryService {
|
interface UseImageStoryService {
|
||||||
@ -32,6 +36,8 @@ interface UseImageStoryService {
|
|||||||
avatarComputed: Array<{ name: string; url: string }>;
|
avatarComputed: Array<{ name: string; url: string }>;
|
||||||
/** 原始用户描述 */
|
/** 原始用户描述 */
|
||||||
originalUserDescription: string;
|
originalUserDescription: string;
|
||||||
|
/** 分析任务进度 */
|
||||||
|
taskProgress: number;
|
||||||
/** 上传图片并分析 */
|
/** 上传图片并分析 */
|
||||||
uploadAndAnalyzeImage: () => Promise<void>;
|
uploadAndAnalyzeImage: () => Promise<void>;
|
||||||
/** 触发文件选择 */
|
/** 触发文件选择 */
|
||||||
@ -52,13 +58,15 @@ interface UseImageStoryService {
|
|||||||
mode?: "auto" | "manual",
|
mode?: "auto" | "manual",
|
||||||
resolution?: "720p" | "1080p" | "4k",
|
resolution?: "720p" | "1080p" | "4k",
|
||||||
language?: string
|
language?: string
|
||||||
) => Promise<CreateMovieProjectResponse|undefined>;
|
) => Promise<CreateMovieProjectResponse | undefined>;
|
||||||
/** 设置角色分析 */
|
/** 设置角色分析 */
|
||||||
setCharactersAnalysis: Dispatch<SetStateAction<CharacterAnalysis[]>>;
|
setCharactersAnalysis: Dispatch<SetStateAction<CharacterAnalysis[]>>;
|
||||||
/** 设置原始用户描述 */
|
/** 设置原始用户描述 */
|
||||||
setOriginalUserDescription: Dispatch<SetStateAction<string>>;
|
setOriginalUserDescription: Dispatch<SetStateAction<string>>;
|
||||||
/** 上传人物头像并分析特征,替换旧的角色数据 */
|
/** 上传人物头像并分析特征,替换旧的角色数据 */
|
||||||
uploadCharacterAvatarAndAnalyzeFeatures: (characterName: string) => Promise<void>;
|
uploadCharacterAvatarAndAnalyzeFeatures: (
|
||||||
|
characterName: string
|
||||||
|
) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useImageStoryServiceHook = (): UseImageStoryService => {
|
export const useImageStoryServiceHook = (): UseImageStoryService => {
|
||||||
@ -91,7 +99,8 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
// 流程状态
|
// 流程状态
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [hasAnalyzed, setHasAnalyzed] = useState(false);
|
const [hasAnalyzed, setHasAnalyzed] = useState(false);
|
||||||
|
/** 分析任务进度 */
|
||||||
|
const [taskProgress, setTaskProgress] = useState(0);
|
||||||
// 使用上传文件Hook
|
// 使用上传文件Hook
|
||||||
const { uploadFile } = useUploadFile();
|
const { uploadFile } = useUploadFile();
|
||||||
|
|
||||||
@ -217,8 +226,9 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
return charactersAnalysis.map((character) => {
|
return charactersAnalysis
|
||||||
console.log('character', character)
|
.map((character) => {
|
||||||
|
console.log("character", character);
|
||||||
// 如果已经有头像URL,直接返回
|
// 如果已经有头像URL,直接返回
|
||||||
if (character.crop_url) {
|
if (character.crop_url) {
|
||||||
return {
|
return {
|
||||||
@ -234,7 +244,8 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
// name: character.role_name,
|
// name: character.role_name,
|
||||||
// url: "", // 初始为空,异步生成完成后会更新
|
// url: "", // 初始为空,异步生成完成后会更新
|
||||||
// };
|
// };
|
||||||
}).filter(Boolean) as { name: string; url: string }[];
|
})
|
||||||
|
.filter(Boolean) as { name: string; url: string }[];
|
||||||
}, [charactersAnalysis, activeImageUrl, generateAvatarFromRegion]);
|
}, [charactersAnalysis, activeImageUrl, generateAvatarFromRegion]);
|
||||||
/**
|
/**
|
||||||
* 上传图片并分析
|
* 上传图片并分析
|
||||||
@ -243,11 +254,9 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
const uploadAndAnalyzeImage = useCallback(async (): Promise<void> => {
|
const uploadAndAnalyzeImage = useCallback(async (): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
setTaskProgress(1);
|
||||||
|
|
||||||
// 调用用例处理图片上传和分析
|
const setData = () => {
|
||||||
const newImageStory = await imageStoryUseCase.handleImageUpload(
|
|
||||||
activeImageUrl
|
|
||||||
);
|
|
||||||
setOriginalUserDescription(storyContent);
|
setOriginalUserDescription(storyContent);
|
||||||
// 获取更新后的数据
|
// 获取更新后的数据
|
||||||
const updatedStory = imageStoryUseCase.storyLogline;
|
const updatedStory = imageStoryUseCase.storyLogline;
|
||||||
@ -265,6 +274,34 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
|
|
||||||
// 标记已分析
|
// 标记已分析
|
||||||
setHasAnalyzed(true);
|
setHasAnalyzed(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 调用用例处理图片上传和分析
|
||||||
|
const taskId = await imageStoryUseCase.handleImageUpload(activeImageUrl);
|
||||||
|
|
||||||
|
for await (const result of await imageStoryUseCase.pollTaskStatus(
|
||||||
|
taskId
|
||||||
|
)) {
|
||||||
|
setTaskProgress(result.progress);
|
||||||
|
switch (result.status) {
|
||||||
|
case "submitted":
|
||||||
|
break;
|
||||||
|
case "processing":
|
||||||
|
setData();
|
||||||
|
break;
|
||||||
|
case "completed":
|
||||||
|
setData();
|
||||||
|
setHasAnalyzed(true);
|
||||||
|
setTaskProgress(0);
|
||||||
|
return
|
||||||
|
case "failed":
|
||||||
|
setHasAnalyzed(false);
|
||||||
|
setTaskProgress(0);
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("图片上传分析失败:", error);
|
console.error("图片上传分析失败:", error);
|
||||||
setHasAnalyzed(false);
|
setHasAnalyzed(false);
|
||||||
@ -275,7 +312,6 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
}
|
}
|
||||||
}, [imageStoryUseCase, activeImageUrl, storyContent]);
|
}, [imageStoryUseCase, activeImageUrl, storyContent]);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新故事类型
|
* 更新故事类型
|
||||||
* @param {string} storyType - 新的故事类型
|
* @param {string} storyType - 新的故事类型
|
||||||
@ -415,7 +451,8 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
});
|
});
|
||||||
}, [uploadFile]);
|
}, [uploadFile]);
|
||||||
|
|
||||||
const actionMovie = useCallback(async (
|
const actionMovie = useCallback(
|
||||||
|
async (
|
||||||
user_id: string,
|
user_id: string,
|
||||||
mode: "auto" | "manual" = "auto",
|
mode: "auto" | "manual" = "auto",
|
||||||
resolution: "720p" | "1080p" | "4k" = "720p",
|
resolution: "720p" | "1080p" | "4k" = "720p",
|
||||||
@ -424,13 +461,13 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
try {
|
try {
|
||||||
if (hasAnalyzed) {
|
if (hasAnalyzed) {
|
||||||
// 从charactersAnalysis中提取whisk_caption字段组成数组
|
// 从charactersAnalysis中提取whisk_caption字段组成数组
|
||||||
const character_briefs = charactersAnalysis.map(char => {
|
const character_briefs = charactersAnalysis.map((char) => {
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name:char.role_name,
|
name: char.role_name,
|
||||||
image_url:char.crop_url,
|
image_url: char.crop_url,
|
||||||
character_analysis:JSON.parse(char.whisk_caption).character_analysis
|
character_analysis: JSON.parse(char.whisk_caption)
|
||||||
}
|
.character_analysis,
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const params: CreateMovieProjectV2Request = {
|
const params: CreateMovieProjectV2Request = {
|
||||||
@ -445,24 +482,34 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 调用create_movie_project_v2接口
|
// 调用create_movie_project_v2接口
|
||||||
const result = await createMovieProjectV2(params)
|
const result = await createMovieProjectV2(params);
|
||||||
return result.data;
|
return result.data;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("创建电影项目失败:", error);
|
console.error("创建电影项目失败:", error);
|
||||||
}
|
}
|
||||||
}, [hasAnalyzed, storyContent, charactersAnalysis, selectedCategory, activeImageUrl]);
|
},
|
||||||
|
[
|
||||||
|
hasAnalyzed,
|
||||||
|
storyContent,
|
||||||
|
charactersAnalysis,
|
||||||
|
selectedCategory,
|
||||||
|
activeImageUrl,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传人物头像并分析特征,替换旧的角色数据
|
* 上传人物头像并分析特征,替换旧的角色数据
|
||||||
* @param {string} characterName - 角色名称
|
* @param {string} characterName - 角色名称
|
||||||
*/
|
*/
|
||||||
const uploadCharacterAvatarAndAnalyzeFeatures = useCallback(async (characterName: string): Promise<void> => {
|
const uploadCharacterAvatarAndAnalyzeFeatures = useCallback(
|
||||||
|
async (characterName: string): Promise<void> => {
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
|
|
||||||
// 调用用例处理人物头像上传和特征分析
|
// 调用用例处理人物头像上传和特征分析
|
||||||
const result = await imageStoryUseCase.uploadCharacterAvatarAndAnalyzeFeatures(
|
const result =
|
||||||
|
await imageStoryUseCase.uploadCharacterAvatarAndAnalyzeFeatures(
|
||||||
uploadFile
|
uploadFile
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -473,7 +520,7 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
? {
|
? {
|
||||||
...char,
|
...char,
|
||||||
crop_url: result.crop_url,
|
crop_url: result.crop_url,
|
||||||
whisk_caption: result.whisk_caption
|
whisk_caption: result.whisk_caption,
|
||||||
}
|
}
|
||||||
: char
|
: char
|
||||||
)
|
)
|
||||||
@ -486,7 +533,9 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
}, [imageStoryUseCase, uploadFile]);
|
},
|
||||||
|
[imageStoryUseCase, uploadFile]
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
imageStory,
|
imageStory,
|
||||||
@ -499,6 +548,7 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
|
|||||||
hasAnalyzed,
|
hasAnalyzed,
|
||||||
avatarComputed,
|
avatarComputed,
|
||||||
originalUserDescription,
|
originalUserDescription,
|
||||||
|
taskProgress,
|
||||||
setCharactersAnalysis,
|
setCharactersAnalysis,
|
||||||
uploadAndAnalyzeImage,
|
uploadAndAnalyzeImage,
|
||||||
triggerFileSelection,
|
triggerFileSelection,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ImageStoryEntity } from "../domain/Entities";
|
import { ImageStoryEntity } from "../domain/Entities";
|
||||||
import { AIGenerateImageStory } from "@/api/movie_start";
|
import { AIGenerateImageStory, getMovieStoryTask } from "@/api/movie_start";
|
||||||
import { MovieStartDTO, CharacterAnalysis } from "@/api/DTO/movie_start_dto";
|
import { MovieStartDTO, CharacterAnalysis } from "@/api/DTO/movie_start_dto";
|
||||||
import { generateCharacterBrief } from "@/api/video_flow";
|
import { generateCharacterBrief } from "@/api/video_flow";
|
||||||
|
|
||||||
@ -32,6 +32,7 @@ export class ImageStoryUseCase {
|
|||||||
|
|
||||||
/** 是否正在上传 */
|
/** 是否正在上传 */
|
||||||
isUploading: boolean = false;
|
isUploading: boolean = false;
|
||||||
|
|
||||||
constructor() {}
|
constructor() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -88,10 +89,9 @@ export class ImageStoryUseCase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用AI分析图片
|
* 使用AI分析图片
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<string>}
|
||||||
*/
|
*/
|
||||||
async analyzeImageWithAI() {
|
async analyzeImageWithAI() {
|
||||||
console.log("this.imageStory.imageUrl", this.imageStory.imageUrl);
|
|
||||||
try {
|
try {
|
||||||
//
|
//
|
||||||
// 调用AI分析接口
|
// 调用AI分析接口
|
||||||
@ -100,27 +100,53 @@ export class ImageStoryUseCase {
|
|||||||
user_text: this.imageStory.imageStory || "",
|
user_text: this.imageStory.imageStory || "",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.successful && response.data) {
|
return response.data.task_id;
|
||||||
// ! 后端实际返回的是对象 但是由于前端只是做字符串数据的转交,所以这里就处理成字符串
|
|
||||||
// ! 至于为什么这里是前端来处理,因为后端这个数据,很多时候都说要以对象方式使用,唯独给AI时,是字符串
|
|
||||||
// ! 然后后端就不处理这个东西了,就给前端来处理了,真 懒
|
|
||||||
response.data.characters_analysis.forEach((character) => {
|
|
||||||
character.whisk_caption = JSON.stringify(character.whisk_caption);
|
|
||||||
});
|
|
||||||
// 解析并存储新的数据结构
|
|
||||||
this.parseAndStoreAnalysisData(response.data);
|
|
||||||
|
|
||||||
// 组合成ImageStoryEntity
|
|
||||||
this.composeImageStoryEntity(response.data);
|
|
||||||
return this.imageStory;
|
|
||||||
} else {
|
|
||||||
throw new Error("AI分析失败");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("AI分析失败:", error);
|
console.error("AI分析失败:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 轮询查状态
|
||||||
|
* @param taskId - 任务ID
|
||||||
|
* @param interval - 轮询间隔时间
|
||||||
|
*/
|
||||||
|
async pollTaskStatus(taskId: string, interval: number = 1000) {
|
||||||
|
// 好老套方案,但是有效
|
||||||
|
let self = this;
|
||||||
|
return {
|
||||||
|
async *[Symbol.asyncIterator]() {
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
const response = await getMovieStoryTask(taskId);
|
||||||
|
console.log("taskId", taskId,response);
|
||||||
|
if (response.successful && response.data) {
|
||||||
|
if (response.data.result) {
|
||||||
|
response.data.result.characters_analysis?.forEach((character) => {
|
||||||
|
character.whisk_caption = JSON.stringify(
|
||||||
|
character.whisk_caption
|
||||||
|
);
|
||||||
|
});
|
||||||
|
// 解析并存储新的数据结构
|
||||||
|
self.parseAndStoreAnalysisData(response.data.result);
|
||||||
|
|
||||||
|
// 组合成ImageStoryEntity
|
||||||
|
self.composeImageStoryEntity(response.data.result);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield {
|
||||||
|
status: response.data.status,
|
||||||
|
imageStory: self.imageStory,
|
||||||
|
progress: response.data.progress,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error("AI分析失败");
|
||||||
|
}
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, interval));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析并存储分析数据到类属性中
|
* 解析并存储分析数据到类属性中
|
||||||
@ -159,7 +185,7 @@ export class ImageStoryUseCase {
|
|||||||
this.setImageStory({
|
this.setImageStory({
|
||||||
...this.imageStory,
|
...this.imageStory,
|
||||||
imageAnalysis: data.story_logline || "",
|
imageAnalysis: data.story_logline || "",
|
||||||
storyType: data.potential_genres[0] || "", // 使用第一个分类作为故事类型
|
storyType: data.potential_genres?.[0] || "", // 使用第一个分类作为故事类型
|
||||||
roleImage,
|
roleImage,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -271,7 +297,9 @@ export class ImageStoryUseCase {
|
|||||||
// 3. 返回新的头像URL和特征描述,用于替换旧数据
|
// 3. 返回新的头像URL和特征描述,用于替换旧数据
|
||||||
const result = {
|
const result = {
|
||||||
crop_url: imageUrl,
|
crop_url: imageUrl,
|
||||||
whisk_caption: JSON.stringify(analysisResult.data.character_brief),
|
whisk_caption: JSON.stringify(
|
||||||
|
analysisResult.data.character_brief
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 清理临时元素
|
// 清理临时元素
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import {
|
import {
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronUp,
|
ChevronUp,
|
||||||
@ -819,6 +819,7 @@ const PhotoStoryModal = ({
|
|||||||
selectedCategory,
|
selectedCategory,
|
||||||
isLoading,
|
isLoading,
|
||||||
hasAnalyzed,
|
hasAnalyzed,
|
||||||
|
taskProgress,
|
||||||
updateStoryType,
|
updateStoryType,
|
||||||
updateStoryContent,
|
updateStoryContent,
|
||||||
updateCharacterName,
|
updateCharacterName,
|
||||||
@ -839,6 +840,11 @@ const PhotoStoryModal = ({
|
|||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const taskProgressRef = useRef(taskProgress);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
taskProgressRef.current = taskProgress;
|
||||||
|
}, [taskProgress]);
|
||||||
// 处理图片上传
|
// 处理图片上传
|
||||||
const handleImageUpload = async (e: any) => {
|
const handleImageUpload = async (e: any) => {
|
||||||
const target = e.target as HTMLImageElement;
|
const target = e.target as HTMLImageElement;
|
||||||
@ -889,9 +895,10 @@ const PhotoStoryModal = ({
|
|||||||
let timeout = 100;
|
let timeout = 100;
|
||||||
let timer: NodeJS.Timeout;
|
let timer: NodeJS.Timeout;
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => {
|
||||||
|
const currentProgress = taskProgressRef.current;
|
||||||
setLocalLoading((prev) => {
|
setLocalLoading((prev) => {
|
||||||
if (prev >= 95) {
|
if (prev >= currentProgress && currentProgress != 0) {
|
||||||
return 95;
|
return currentProgress;
|
||||||
}
|
}
|
||||||
return prev + 0.1;
|
return prev + 0.1;
|
||||||
});
|
});
|
||||||
@ -899,17 +906,8 @@ const PhotoStoryModal = ({
|
|||||||
try {
|
try {
|
||||||
await uploadAndAnalyzeImage();
|
await uploadAndAnalyzeImage();
|
||||||
} finally {
|
} finally {
|
||||||
timeout = 10;
|
|
||||||
clearInterval(timer);
|
clearInterval(timer);
|
||||||
timer = setInterval(() => {
|
setLocalLoading(0);
|
||||||
setLocalLoading((prev) => {
|
|
||||||
if (prev >= 100) {
|
|
||||||
clearInterval(timer);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return prev + 1;
|
|
||||||
});
|
|
||||||
}, timeout);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user