- [x] 触发自动剪辑中,小剪刀 不要出来

Chatbox 快捷指令简化
This commit is contained in:
北枳 2025-09-05 15:24:19 +08:00
parent adb6f97366
commit 254b226c6e
3 changed files with 25 additions and 20 deletions

View File

@ -1,20 +1,22 @@
import React, { useRef, useCallback } from 'react'; import React, { useRef, useCallback } from 'react';
import { motion } from 'framer-motion'; import { motion } from 'framer-motion';
import { ChevronLeft, ChevronRight } from 'lucide-react'; import { ChevronLeft, ChevronRight, Cloudy, UserRound, PersonStanding, Shirt, Smile, RefreshCcw } from 'lucide-react';
/** 快捷操作标签的数据结构 */ /** 快捷操作标签的数据结构 */
export interface QuickAction { export interface QuickAction {
id: string; id: string;
label: string; label: string;
icon: any;
} }
/** 预设的快捷操作标签 */ /** 预设的快捷操作标签 */
export const DEFAULT_QUICK_ACTIONS: QuickAction[] = [ export const DEFAULT_QUICK_ACTIONS: QuickAction[] = [
{ id: 'weather', label: 'Change video scene weather' }, { id: 'weather', label: 'change weather', icon: Cloudy },
{ id: 'character', label: 'Change a character in the video' }, { id: 'character', label: 'change character', icon: UserRound },
{ id: 'costume', label: 'Change the clothing of a character in the video' }, { id: 'costume', label: 'change clothing', icon: Shirt },
{ id: 'scene', label: 'Change video scene background' }, { id: 'action', label: 'change action', icon: PersonStanding },
{ id: 'action', label: 'Change character action' } { id: 'emotion', label: 'change emotion', icon: Smile },
{ id: 'retry', label: 'retry failed video', icon: RefreshCcw }
]; ];
interface QuickActionTagsProps { interface QuickActionTagsProps {
@ -48,10 +50,10 @@ export function QuickActionTags({ actions = DEFAULT_QUICK_ACTIONS, onTagClick }:
return ( return (
<div <div
data-alt="quick-action-tags" data-alt="quick-action-tags"
className="relative flex items-center px-3 py-2 group" className="relative flex items-center px-3 py-2 group bg-gradient-to-r from-black/20 to-transparent"
> >
{/* 左侧渐变遮罩 */} {/* 左侧渐变遮罩 */}
<div className="absolute left-0 top-0 bottom-0 w-12 bg-gradient-to-r from-black/20 to-transparent pointer-events-none z-10" /> {/* <div className="absolute left-0 top-0 bottom-0 w-12 bg-gradient-to-r from-black/20 to-transparent pointer-events-none z-10" /> */}
{/* 左滚动按钮 */} {/* 左滚动按钮 */}
<motion.button <motion.button
@ -81,20 +83,21 @@ export function QuickActionTags({ actions = DEFAULT_QUICK_ACTIONS, onTagClick }:
onClick={() => onTagClick(action)} onClick={() => onTagClick(action)}
whileHover={{ scale: 1.05 }} whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }} whileTap={{ scale: 0.95 }}
className="flex-none px-[8px] py-[3px] rounded-full text-[10px] text-white/80 className="flex items-center flex-shrink-0 gap-1 px-[8px] py-[3px] rounded-full text-[10px] text-white/80
backdrop-blur-md bg-white/10 border border-white/20 backdrop-blur-md bg-white/10 border border-white/20
hover:bg-white/20 hover:text-white hover:bg-white/20 hover:text-white
transition-colors duration-200 transition-colors duration-200
shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-1px_rgba(0,0,0,0.06)]" shadow-[0_4px_6px_-1px_rgba(0,0,0,0.1),0_2px_4px_-1px_rgba(0,0,0,0.06)]"
data-alt={`quick-action-${action.id}`} data-alt={`quick-action-${action.id}`}
> >
{action.icon && <action.icon className="w-3 h-3" />}
{action.label} {action.label}
</motion.button> </motion.button>
))} ))}
</div> </div>
{/* 右侧渐变遮罩 */} {/* 右侧渐变遮罩 */}
<div className="absolute right-0 top-0 bottom-0 w-12 bg-gradient-to-l from-black/20 to-transparent pointer-events-none z-10" /> {/* <div className="absolute right-0 top-0 bottom-0 w-12 bg-gradient-to-l from-black/20 to-transparent pointer-events-none z-10" /> */}
{/* 右滚动按钮 */} {/* 右滚动按钮 */}
<motion.button <motion.button

View File

@ -40,6 +40,7 @@ const WorkFlow = React.memo(function WorkFlow() {
const [isHovered, setIsHovered] = React.useState(false); const [isHovered, setIsHovered] = React.useState(false);
const [aiEditingResult, setAiEditingResult] = React.useState<any>(null); const [aiEditingResult, setAiEditingResult] = React.useState<any>(null);
const aiEditingButtonRef = useRef<{ handleAIEditing: () => Promise<void> }>(null); const aiEditingButtonRef = useRef<{ handleAIEditing: () => Promise<void> }>(null);
const [editingStatus, setEditingStatus] = React.useState<'initial' | 'idle' | 'success' | 'error'>('initial');
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const episodeId = searchParams.get('episodeId') || ''; const episodeId = searchParams.get('episodeId') || '';
@ -53,6 +54,7 @@ const WorkFlow = React.memo(function WorkFlow() {
const handleEditPlanGenerated = useCallback(() => { const handleEditPlanGenerated = useCallback(() => {
console.log('✨ 编辑计划生成完成开始AI剪辑'); console.log('✨ 编辑计划生成完成开始AI剪辑');
setIsHandleEdit(true); setIsHandleEdit(true);
setEditingStatus('idle');
aiEditingButtonRef.current?.handleAIEditing(); aiEditingButtonRef.current?.handleAIEditing();
editingNotificationKey.current = `editing-${Date.now()}`; editingNotificationKey.current = `editing-${Date.now()}`;
showEditingNotification({ showEditingNotification({
@ -65,6 +67,7 @@ const WorkFlow = React.memo(function WorkFlow() {
console.log('Editing failed'); console.log('Editing failed');
// 清缓存 生成计划 视频重新分析 // 清缓存 生成计划 视频重新分析
localStorage.removeItem(`isLoaded_plan_${episodeId}`); localStorage.removeItem(`isLoaded_plan_${episodeId}`);
setEditingStatus('error');
// 3秒后关闭通知 // 3秒后关闭通知
setTimeout(() => { setTimeout(() => {
if (editingNotificationKey.current) { if (editingNotificationKey.current) {
@ -82,9 +85,7 @@ const WorkFlow = React.memo(function WorkFlow() {
isLoading, isLoading,
currentSketchIndex, currentSketchIndex,
currentLoadingText, currentLoadingText,
dataLoadError,
setCurrentSketchIndex, setCurrentSketchIndex,
retryLoadData,
isPauseWorkFlow, isPauseWorkFlow,
mode, mode,
setIsPauseWorkFlow, setIsPauseWorkFlow,
@ -122,6 +123,7 @@ const WorkFlow = React.memo(function WorkFlow() {
onComplete: () => { onComplete: () => {
console.log('Editing successful'); console.log('Editing successful');
localStorage.setItem(`isLoaded_plan_${episodeId}`, 'true'); localStorage.setItem(`isLoaded_plan_${episodeId}`, 'true');
setEditingStatus('success');
// 3秒后关闭通知 // 3秒后关闭通知
setTimeout(() => { setTimeout(() => {
if (editingNotificationKey.current) { if (editingNotificationKey.current) {
@ -200,7 +202,7 @@ const WorkFlow = React.memo(function WorkFlow() {
currentLoadingText={currentLoadingText} currentLoadingText={currentLoadingText}
roles={taskObject.roles.data} roles={taskObject.roles.data}
isPauseWorkFlow={isPauseWorkFlow} isPauseWorkFlow={isPauseWorkFlow}
showGotoCutButton={showGotoCutButton} showGotoCutButton={showGotoCutButton || editingStatus !== 'idle'}
onGotoCut={generateEditPlan} onGotoCut={generateEditPlan}
setIsPauseWorkFlow={setIsPauseWorkFlow} setIsPauseWorkFlow={setIsPauseWorkFlow}
/> />
@ -232,7 +234,7 @@ const WorkFlow = React.memo(function WorkFlow() {
setPreviewVideoUrl(url); setPreviewVideoUrl(url);
setPreviewVideoId(id); setPreviewVideoId(id);
}} }}
showGotoCutButton={showGotoCutButton} showGotoCutButton={showGotoCutButton || editingStatus !== 'idle'}
onGotoCut={generateEditPlan} onGotoCut={generateEditPlan}
isSmartChatBoxOpen={isSmartChatBoxOpen} isSmartChatBoxOpen={isSmartChatBoxOpen}
onRetryVideo={(video_id) => handleRetryVideo(video_id)} onRetryVideo={(video_id) => handleRetryVideo(video_id)}

View File

@ -148,8 +148,8 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps =
showEditingNotification({ showEditingNotification({
key: notificationKey, key: notificationKey,
description: 'Generating intelligent editing plan...', description: 'Generating intelligent editing plan...',
successDescription: 'Generating successful', successDescription: '剪辑计划生成完成',
timeoutDescription: 'Generating failed, please try again', timeoutDescription: '剪辑计划生成失败,请重试',
timeout: 3 * 60 * 1000 timeout: 3 * 60 * 1000
}); });
// 先停止轮询 // 先停止轮询
@ -168,8 +168,8 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps =
showEditingNotification({ showEditingNotification({
key: notificationKey, key: notificationKey,
isCompleted: true, isCompleted: true,
description: 'Generating intelligent editing plan...', description: '正在生成剪辑计划...',
successDescription: 'Generating successful', successDescription: '剪辑计划生成完成',
timeout: 3000 timeout: 3000
}); });
setTimeout(() => { setTimeout(() => {
@ -186,8 +186,8 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps =
// 显示失败通知3秒 // 显示失败通知3秒
showEditingNotification({ showEditingNotification({
key: notificationKey, key: notificationKey,
description: 'Generating intelligent editing plan...', description: '正在生成剪辑计划...',
timeoutDescription: 'Generating failed, please try again', timeoutDescription: '剪辑计划生成失败,请重试',
timeout: 3000 timeout: 3000
}); });
setTimeout(() => { setTimeout(() => {