forked from 77media/video-flow
重试视频,等待 接口 支持 完善
This commit is contained in:
parent
8616e2ab34
commit
150c1636bb
@ -665,6 +665,16 @@ export const regenerateShot = async (request: {
|
||||
return post("/movie/regenerate_shot_video", request);
|
||||
};
|
||||
|
||||
// 重新生成视频
|
||||
export const regenerateVideo = async (request: {
|
||||
/** 项目ID */
|
||||
project_id: string;
|
||||
/** 视频ID */
|
||||
video_id: string;
|
||||
}): Promise<ApiResponse<any>> => {
|
||||
return post("/movie_cut/regenerate_video", request);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 获取分镜列表
|
||||
|
||||
@ -139,6 +139,7 @@ const WorkFlow = React.memo(function WorkFlow() {
|
||||
taskObject={taskObject}
|
||||
currentSketchIndex={currentSketchIndex}
|
||||
onSketchSelect={setCurrentSketchIndex}
|
||||
onRetryVideo={handleRetryVideo}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -430,10 +430,14 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
{taskObject.videos.data[currentSketchIndex].video_status === 2 && (
|
||||
<div className="absolute inset-0 bg-red-500/10 flex items-center justify-center">
|
||||
<div
|
||||
className="text-red-500 text-2xl font-bold flex items-center gap-2"
|
||||
className="text-[#813b9dcc] text-2xl font-bold flex items-center gap-2"
|
||||
>
|
||||
<RotateCcw className="w-10 h-10" />
|
||||
<span>Retry</span>
|
||||
<RotateCcw className="w-10 h-10 cursor-pointer" onClick={() => {
|
||||
const video = taskObject.videos.data[currentSketchIndex];
|
||||
if (onRetryVideo && video?.video_id) {
|
||||
onRetryVideo(video.video_id);
|
||||
}
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -442,7 +446,7 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
|
||||
|
||||
{/* 视频 多个 取第一个 */}
|
||||
{ taskObject.videos.data[currentSketchIndex].urls && (
|
||||
{ taskObject.videos.data[currentSketchIndex].urls && taskObject.videos.data[currentSketchIndex].urls.length > 0 && (
|
||||
<>
|
||||
<motion.div
|
||||
initial={{ clipPath: "inset(0 100% 0 0)" }}
|
||||
@ -458,7 +462,6 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
autoPlay={isVideoPlaying}
|
||||
loop={true}
|
||||
playsInline
|
||||
onLoadedData={() => applyVolumeSettings(mainVideoRef.current!)}
|
||||
onEnded={() => {
|
||||
if (isVideoPlaying) {
|
||||
// 自动切换到下一个视频的逻辑在父组件处理
|
||||
@ -471,17 +474,6 @@ export const MediaViewer = React.memo(function MediaViewer({
|
||||
<div className="absolute top-4 right-4 z-[21] flex items-center gap-2 transition-right duration-100" style={{
|
||||
right: toosBtnRight
|
||||
}}>
|
||||
{/* 重试按钮 */}
|
||||
{taskObject.videos.data[currentSketchIndex].video_status === 2 && (
|
||||
<Tooltip placement="top" title="Retry video">
|
||||
<GlassIconButton icon={RotateCcw} size='sm' onClick={() => {
|
||||
const video = taskObject.videos.data[currentSketchIndex];
|
||||
if (onRetryVideo && video?.video_id) {
|
||||
onRetryVideo(video.video_id);
|
||||
}
|
||||
}} />
|
||||
</Tooltip>
|
||||
)}
|
||||
{/* 添加到chat去编辑 按钮 */}
|
||||
<Tooltip placement="top" title="Edit video with chat">
|
||||
<GlassIconButton icon={MessageCircleMore} size='sm' onClick={() => {
|
||||
|
||||
@ -12,13 +12,15 @@ interface ThumbnailGridProps {
|
||||
taskObject: TaskObject;
|
||||
currentSketchIndex: number;
|
||||
onSketchSelect: (index: number) => void;
|
||||
onRetryVideo: (video_id: string) => void;
|
||||
}
|
||||
|
||||
export function ThumbnailGrid({
|
||||
isDisabledFocus,
|
||||
taskObject,
|
||||
currentSketchIndex,
|
||||
onSketchSelect
|
||||
onSketchSelect,
|
||||
onRetryVideo
|
||||
}: ThumbnailGridProps) {
|
||||
const thumbnailsRef = useRef<HTMLDivElement>(null);
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
@ -186,19 +188,24 @@ export function ThumbnailGrid({
|
||||
)}
|
||||
{taskObject.videos.data[index].video_status === 2 && (
|
||||
<div className="absolute inset-0 bg-red-500/10 flex items-center justify-center z-20">
|
||||
<div className="text-red-500 text-xl font-bold flex items-center gap-2">
|
||||
<RotateCcw className="w-10 h-10" />
|
||||
<div className="text-[#813b9dcc] text-xl font-bold flex items-center gap-2">
|
||||
<RotateCcw className="w-10 h-10 cursor-pointer" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{taskObject.videos.data[index].urls ? (
|
||||
<video
|
||||
{taskObject.videos.data[index].urls && taskObject.videos.data[index].urls.length > 0 ? (
|
||||
// <video
|
||||
// className="w-full h-full object-cover"
|
||||
// src={taskObject.videos.data[index].urls[0]}
|
||||
// playsInline
|
||||
// loop
|
||||
// muted
|
||||
// />
|
||||
<img
|
||||
className="w-full h-full object-cover"
|
||||
src={taskObject.videos.data[index].urls[0]}
|
||||
playsInline
|
||||
loop
|
||||
muted
|
||||
src={`${taskObject.videos.data[index].urls[0]}?x-oss-process=video/snapshot,t_1000,f_jpg`}
|
||||
draggable="false"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full transform hover:scale-105 transition-transform duration-500">
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, pauseMovieProjectPlan, resumeMovieProjectPlan, getGenerateEditPlan, regenerateShot } from '@/api/video_flow';
|
||||
import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, pauseMovieProjectPlan, resumeMovieProjectPlan, getGenerateEditPlan, regenerateVideo } from '@/api/video_flow';
|
||||
import { useScriptService } from "@/app/service/Interaction/ScriptService";
|
||||
import { useUpdateEffect } from '@/app/hooks/useUpdateEffect';
|
||||
import { LOADING_TEXT_MAP, TaskObject, Status, Stage } from '@/api/DTO/movieEdit';
|
||||
@ -18,6 +18,8 @@ export function useWorkflowData() {
|
||||
const from = searchParams.get('from') || '';
|
||||
const token = localStorage.getItem('token') || '';
|
||||
const useid = JSON.parse(localStorage.getItem("currentUser") || '{}').id || NaN;
|
||||
// 查看缓存中 是否已经 加载过 这个项目的 剪辑计划
|
||||
const isLoaded = localStorage.getItem(`isLoaded_plan_${episodeId}`);
|
||||
|
||||
let tempTaskObject = useRef<TaskObject>({
|
||||
title: '',
|
||||
@ -114,7 +116,15 @@ export function useWorkflowData() {
|
||||
}, [taskObject.currentStage]);
|
||||
|
||||
const generateEditPlan = useCallback(async (isInit?: boolean) => {
|
||||
if (isLoaded) {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem(`isLoaded_plan_${episodeId}`, 'true');
|
||||
isInit && await getGenerateEditPlan({ project_id: episodeId });
|
||||
openEditPlan();
|
||||
}, [episodeId]);
|
||||
|
||||
const openEditPlan = useCallback(async () => {
|
||||
window.open(`https://smartcut.movieflow.ai/ai-editor/${episodeId}?token=${token}&user_id=${useid}`, '_target');
|
||||
}, [episodeId]);
|
||||
|
||||
@ -275,15 +285,17 @@ export function useWorkflowData() {
|
||||
taskCurrent.currentStage = 'video';
|
||||
// 正在生成视频中 替换视频数据
|
||||
const videoList = [];
|
||||
let videoUrls: string[] = [];
|
||||
let video_status = 0;
|
||||
for (const video of task.task_result.data) {
|
||||
videoUrls = video.urls ? video.urls.filter((url: null | string) => url !== null) : [];
|
||||
// 适配旧数据
|
||||
video_status = video.video_status === undefined ? (video.urls ? 1 : 0) : video.video_status;
|
||||
video_status = video.video_status === undefined ? (videoUrls.length > 0 ? 1 : 0) : video.video_status;
|
||||
// 完成 还是 0 就是 生成失败
|
||||
video_status = task.task_status === 'COMPLETED' && video_status === 0 ? 2 : video_status;
|
||||
// 每一项 video 有多个视频 先默认取第一个
|
||||
videoList.push({
|
||||
urls: video.urls,
|
||||
urls: videoUrls,
|
||||
video_id: video.video_id,
|
||||
video_status: video_status, // 0 生成中 1 生成完成 2 生成失败
|
||||
type: 'video'
|
||||
@ -452,13 +464,16 @@ export function useWorkflowData() {
|
||||
taskCurrent.currentStage = 'video';
|
||||
taskCurrent.videos.total_count = data.video.total_count;
|
||||
const videoList = [];
|
||||
let videoUrls: string[] = [];
|
||||
console.log('----------data.video.data', data.video.data);
|
||||
for (const video of data.video.data) {
|
||||
let video_status = video.video_status === undefined ? (video.urls ? 1 : 0) : video.video_status;
|
||||
videoUrls = video.urls ? video.urls.filter((url: null | string) => url !== null) : [];
|
||||
console.log('----------videoUrls', videoUrls);
|
||||
let video_status = video.video_status === undefined ? (videoUrls.length > 0 ? 1 : 0) : video.video_status;
|
||||
video_status = data.video.task_status === 'COMPLETED' && video_status === 0 ? 2 : video_status;
|
||||
// 每一项 video 有多个视频 默认取存在的项
|
||||
videoList.push({
|
||||
urls: video.urls,
|
||||
urls: videoUrls,
|
||||
video_id: video.video_id,
|
||||
video_status: video_status, // 0 生成中 1 生成完成 2 生成失败
|
||||
type: 'video'
|
||||
@ -527,23 +542,33 @@ export function useWorkflowData() {
|
||||
// 重试生成视频
|
||||
const handleRetryVideo = async (video_id: string) => {
|
||||
try {
|
||||
// 先停止轮询
|
||||
await new Promise(resolve => {
|
||||
setNeedStreamData(false);
|
||||
resolve(true);
|
||||
});
|
||||
// 重置视频状态为生成中
|
||||
setTaskObject(prev => {
|
||||
const newState = JSON.parse(JSON.stringify(prev));
|
||||
const videoIndex = newState.videos.data.findIndex((v: any) => v.video_id === video_id);
|
||||
if (videoIndex !== -1) {
|
||||
newState.videos.data[videoIndex].video_status = 0;
|
||||
}
|
||||
return newState;
|
||||
await new Promise(resolve => {
|
||||
setTaskObject(prev => {
|
||||
const newState = JSON.parse(JSON.stringify(prev));
|
||||
const videoIndex = newState.videos.data.findIndex((v: any) => v.video_id === video_id);
|
||||
if (videoIndex !== -1) {
|
||||
newState.videos.data[videoIndex].video_status = 0;
|
||||
}
|
||||
return newState;
|
||||
});
|
||||
resolve(true);
|
||||
});
|
||||
|
||||
// 调用重新生成接口
|
||||
await regenerateShot({ project_id: episodeId, shot_id: video_id });
|
||||
await regenerateVideo({ project_id: episodeId, video_id: video_id });
|
||||
|
||||
// 重新开启轮询 如果轮询结束的话
|
||||
if (!needStreamData) setNeedStreamData(true);
|
||||
// 重新开启轮询
|
||||
setNeedStreamData(true);
|
||||
} catch (error) {
|
||||
console.error('重试生成视频失败:', error);
|
||||
// 发生错误时也要恢复轮询状态
|
||||
setNeedStreamData(true);
|
||||
}
|
||||
};
|
||||
|
||||
@ -587,7 +612,7 @@ export function useWorkflowData() {
|
||||
originalText: state.originalText,
|
||||
// showGotoCutButton: from && currentLoadingText.includes('Post-production') ? true : false,
|
||||
showGotoCutButton: canGoToCut ? true : false,
|
||||
generateEditPlan,
|
||||
generateEditPlan: openEditPlan,
|
||||
handleRetryVideo
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user