/** * AI剪辑按钮组件 - video-flow-b集成OpenCut AI剪辑功能 * 文件路径: video-flow-b/components/pages/work-flow/ai-editing-button.tsx */ "use client"; import React, { useState, useCallback } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import { Zap, Loader2, CheckCircle, AlertCircle, Film, Sparkles, Play, Download } from 'lucide-react'; import { GlassIconButton } from '@/components/ui/glass-icon-button'; import { createAIEditingAdapter, VideoFlowTaskObject, AIEditingAdapter } from './ai-editing-adapter'; interface AIEditingButtonProps { /** 项目ID */ projectId: string; /** video-flow-b任务对象 */ taskObject: VideoFlowTaskObject; /** 是否禁用按钮 */ disabled?: boolean; /** 按钮大小 */ size?: 'sm' | 'md' | 'lg'; /** 完成回调 */ onComplete?: (finalVideoUrl: string) => void; /** 错误回调 */ onError?: (error: string) => void; } interface ProgressState { progress: number; message: string; stage: 'idle' | 'processing' | 'completed' | 'error'; } /** * AI剪辑按钮组件 * 提供一键AI剪辑功能,集成OpenCut的智能剪辑算法 */ export const AIEditingButton: React.FC = ({ projectId, taskObject, disabled = false, size = 'md', onComplete, onError }) => { const [progressState, setProgressState] = useState({ progress: 0, message: '', stage: 'idle' }); const [isProcessing, setIsProcessing] = useState(false); const [finalVideoUrl, setFinalVideoUrl] = useState(null); // 检查是否可以执行AI剪辑 const canExecute = AIEditingAdapter.canExecuteAIEditing(taskObject); const availableVideoCount = AIEditingAdapter.getAvailableVideoCount(taskObject); /** * 执行AI剪辑的主要逻辑 */ const handleAIEditing = useCallback(async () => { if (!canExecute || isProcessing) { return; } setIsProcessing(true); setProgressState({ progress: 0, message: '准备开始AI剪辑...', stage: 'processing' }); try { // 创建AI剪辑适配器 const adapter = createAIEditingAdapter(projectId, taskObject, { onProgress: (progress, message) => { setProgressState({ progress, message, stage: 'processing' }); }, onComplete: (url) => { setFinalVideoUrl(url); setProgressState({ progress: 100, message: 'AI剪辑完成!', stage: 'completed' }); onComplete?.(url); }, onError: (error) => { setProgressState({ progress: 0, message: error, stage: 'error' }); onError?.(error); } }); // 执行自动化AI剪辑 const resultUrl = await adapter.executeAutoAIEditing(); console.log('✅ AI剪辑完成,视频URL:', resultUrl); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'AI剪辑过程中发生未知错误'; console.error('❌ AI剪辑失败:', error); setProgressState({ progress: 0, message: errorMessage, stage: 'error' }); onError?.(errorMessage); } finally { setIsProcessing(false); // 3秒后重置状态 setTimeout(() => { if (progressState.stage !== 'processing') { setProgressState({ progress: 0, message: '', stage: 'idle' }); } }, 3000); } }, [projectId, taskObject, canExecute, isProcessing, onComplete, onError, progressState.stage]); /** * 获取按钮显示内容 */ const getButtonContent = () => { switch (progressState.stage) { case 'processing': return { icon: Loader2, text: '剪辑中...', className: 'animate-spin' }; case 'completed': return { icon: CheckCircle, text: '完成', className: 'text-green-500' }; case 'error': return { icon: AlertCircle, text: '失败', className: 'text-red-500' }; default: return { icon: Zap, text: 'AI一键剪辑', className: 'text-blue-500' }; } }; const buttonContent = getButtonContent(); const Icon = buttonContent.icon; return (
{/* 主按钮 */} {buttonContent.text} {/* 闪烁效果 */} {progressState.stage === 'idle' && canExecute && ( )} {/* 进度条 */} {progressState.stage === 'processing' && (
AI剪辑进行中 {Math.round(progressState.progress)}%
{/* 进度条 */}
{/* 状态消息 */}

{progressState.message}

)}
{/* 不可用提示 */} {!canExecute && ( 需要至少1个完成的视频片段
)} {/* 视频信息提示 */} {canExecute && ( {availableVideoCount}个视频片段可用 )} {/* 完成后的下载按钮 */} {finalVideoUrl && progressState.stage === 'completed' && ( )}
); }; /** * 简化版AI剪辑图标按钮 * 用于空间受限的场景 */ export const AIEditingIconButton: React.FC & { size?: 'sm' | 'md' | 'lg' }> = ({ projectId, taskObject, disabled = false, size = 'md', onComplete, onError }) => { const [isProcessing, setIsProcessing] = useState(false); const canExecute = AIEditingAdapter.canExecuteAIEditing(taskObject); const handleClick = useCallback(async () => { if (!canExecute || isProcessing) return; setIsProcessing(true); try { const adapter = createAIEditingAdapter(projectId, taskObject, { onComplete: (url) => { onComplete?.(url); setIsProcessing(false); }, onError: (error) => { onError?.(error); setIsProcessing(false); } }); await adapter.executeAutoAIEditing(); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'AI剪辑失败'; onError?.(errorMessage); setIsProcessing(false); } }, [projectId, taskObject, canExecute, isProcessing, onComplete, onError]); return ( ); }; export default AIEditingButton;