diff --git a/components/SmartChatBox/api.ts b/components/SmartChatBox/api.ts index 6804d64..51d551f 100644 --- a/components/SmartChatBox/api.ts +++ b/components/SmartChatBox/api.ts @@ -75,6 +75,10 @@ function isShotVideoGeneration(data: any): data is ShotVideoGeneration { return data && 'prompt_json' in data && 'urls' in data && 'completed_count' in data && 'total_count' in data; } +function displayText(title: string, content: string, isLast: boolean = false) { + return `${content ? `${title}: ${content}${isLast ? '' : '\n'}` : ''}` +} + /** * 系统消息转换为blocks数组 */ @@ -153,7 +157,7 @@ function transformSystemMessage( if (isShotSketchGeneration(customData)) { blocks = [{ type: 'text', - text: `🎬 Storyboard static frame generation \nShot type: ${customData.shot_type}\nAtmosphere: ${customData.atmosphere}\nKey action: ${customData.key_action}` + text: `🎬 Storyboard static frame generation \n${displayText('Shot type', customData.shot_type)}${displayText('Atmosphere', customData.atmosphere)}${displayText('Key action', customData.key_action, true)}` }, { type: 'image', url: customData.url diff --git a/components/layout/top-bar.tsx b/components/layout/top-bar.tsx index 3a40c78..1f78b40 100644 --- a/components/layout/top-bar.tsx +++ b/components/layout/top-bar.tsx @@ -48,7 +48,7 @@ export function TopBar({ collapsed }: { collapsed: boolean }) { const [isLogin, setIsLogin] = useState(false); const [isManagingSubscription, setIsManagingSubscription] = useState(false); const [subscriptionStatus, setSubscriptionStatus] = useState(""); - const [credits, setCredits] = useState(100); + const [credits, setCredits] = useState(0); const [isLoadingSubscription, setIsLoadingSubscription] = useState(false); // 获取用户订阅信息 diff --git a/components/pages/create-to-video2.tsx b/components/pages/create-to-video2.tsx index 0a1fe47..7f4da38 100644 --- a/components/pages/create-to-video2.tsx +++ b/components/pages/create-to-video2.tsx @@ -1,7 +1,7 @@ "use client"; import { useState, useEffect, useRef, useCallback } from 'react'; -import { Loader2, Check, Pencil, Trash } from 'lucide-react'; +import { Loader2, Check, Pencil, Trash, Download } from 'lucide-react'; import { useRouter } from 'next/navigation'; import './style/create-to-video2.css'; @@ -10,6 +10,9 @@ import { ChatInputBox } from '@/components/ChatInputBox/ChatInputBox'; import cover_image1 from '@/public/assets/cover_image3.jpg'; import { motion } from 'framer-motion'; import { Tooltip, Button } from 'antd'; +import { GlassIconButton } from '@/components/ui/glass-icon-button'; +import { downloadVideo } from '@/utils/tools'; + // ideaText已迁移到ChatInputBox组件中 @@ -217,6 +220,18 @@ export default function CreateToVideo2() { /> )} + {/* 下载按钮 右上角 */} + {(project.final_video_url || project.final_simple_video_url) && ( +
+ + + +
+ )} + + {/* 状态标签 - 左上角 */}
{StatusBadge((project.status === 'COMPLETED' || project.final_simple_video_url) ? 'completed' : project.status === 'FAILED' ? 'failed' : 'pending')} @@ -232,12 +247,12 @@ export default function CreateToVideo2() { {/* TODO 编辑标题 */} {/* - + */}
{/* TODO 删除 */} {/* - + */} diff --git a/components/pages/work-flow/media-viewer.tsx b/components/pages/work-flow/media-viewer.tsx index d005b41..c009940 100644 --- a/components/pages/work-flow/media-viewer.tsx +++ b/components/pages/work-flow/media-viewer.tsx @@ -10,7 +10,7 @@ import { mockScriptData } from '@/components/script-renderer/mock'; import { Skeleton } from '@/components/ui/skeleton'; import { TaskObject } from '@/api/DTO/movieEdit'; import { Button, Tooltip } from 'antd'; -import { Video } from 'lucide-react'; +import { downloadVideo } from '@/utils/tools'; interface MediaViewerProps { taskObject: TaskObject; @@ -273,14 +273,6 @@ export const MediaViewer = React.memo(function MediaViewer({ }; }, []); - // 下载视频 - const downloadVideo = (url: string) => { - const a = document.createElement('a'); - a.href = url; - a.download = url.split('/').pop() || ''; - a.click(); - }; - // 渲染音量控制组件 const renderVolumeControls = () => (
@@ -371,6 +363,12 @@ export const MediaViewer = React.memo(function MediaViewer({ onClick={() => handleEditClick('3', 'final')} /> + {/* 下载按钮 */} + + { + downloadVideo(taskObject.final.url); + }} /> + {showGotoCutButton && ( diff --git a/components/pages/work-flow/use-workflow-data.tsx b/components/pages/work-flow/use-workflow-data.tsx index aaab584..470ca09 100644 --- a/components/pages/work-flow/use-workflow-data.tsx +++ b/components/pages/work-flow/use-workflow-data.tsx @@ -115,25 +115,24 @@ 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 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]); - // 注释掉自动跳转逻辑,改为手动点击触发 - useEffect(() => { - if (!from && canGoToCut && taskObject.status !== 'COMPLETED') { - generateEditPlan(true); - } - }, [canGoToCut, taskObject.status]); + // useEffect(() => { + // if (!from && canGoToCut && taskObject.status !== 'COMPLETED') { + // generateEditPlan(true); + // } + // }, [canGoToCut, taskObject.status]); useUpdateEffect(() => { @@ -398,7 +397,7 @@ export function useWorkflowData() { const { current: taskCurrent } = tempTaskObject; - taskCurrent.title = title || 'generating...'; + taskCurrent.title = name || 'generating...'; taskCurrent.tags = tags || []; taskCurrent.status = status as Status; @@ -408,8 +407,8 @@ export function useWorkflowData() { const titleResponse = await getScriptTitle({ project_id: episodeId }); console.log('titleResponse', titleResponse); if (titleResponse.successful) { - taskCurrent.title = titleResponse.data.title; - taskCurrent.tags = titleResponse.data.tags || []; + taskCurrent.title = titleResponse.data.name; + taskCurrent.tags = titleResponse.data.description.tags || []; } } diff --git a/utils/tools.ts b/utils/tools.ts index 444a947..7a79fd3 100644 --- a/utils/tools.ts +++ b/utils/tools.ts @@ -77,3 +77,20 @@ export function createScreenAdapter(): void { // 将样式添加到head document.head.appendChild(style); } + +export const downloadVideo = async (url: string) => { + try { + const response = await fetch(url); + const blob = await response.blob(); + const blobUrl = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = blobUrl; + a.download = url.split('/').pop() || 'video.mp4'; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(blobUrl); + } catch (error) { + console.error('下载视频失败:', error); + } +}; \ No newline at end of file