forked from 77media/video-flow
- [x] 触发自动剪辑中,小剪刀 不要出来
Chatbox 快捷指令简化
This commit is contained in:
parent
adb6f97366
commit
254b226c6e
@ -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
|
||||||
|
|||||||
@ -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)}
|
||||||
|
|||||||
@ -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(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user