auto-save 2026-05-14 10:51 (~7)
This commit is contained in:
@@ -19,7 +19,7 @@ import { ThemeToggle } from "@/components/theme-toggle"
|
||||
import { AudioStrip } from "@/components/audio-strip"
|
||||
import {
|
||||
addManualFrame, analyzeJob, createJob, getJob, listJobs, uploadJob, deleteJob, deleteFrame, deleteGeneratedImage,
|
||||
deleteGeneratedVideo, deleteCutout, generateStoryboardVideo, createProductFusionGuide,
|
||||
deleteGeneratedVideo, deleteCutout, generateStoryboardVideo, createProductFusionGuide, triggerTranscribe,
|
||||
type Job, type ImageRef, type ProductFusionShot, type StoryboardScene, type FrameExtractMode, type FrameExtractQuality, type FrameExtractTarget,
|
||||
} from "@/lib/api"
|
||||
import { TRANSPARENT_HUMAN_NEGATIVE_PROMPT, TRANSPARENT_HUMAN_VIDEO_PROMPT } from "@/lib/workflow-target"
|
||||
@@ -385,6 +385,36 @@ export default function Home() {
|
||||
toast.success(`已复制:${ref.label || (ref.kind === "keyframe" ? "关键帧" : "元素")} · 到分镜头编排工作台粘贴`)
|
||||
}, [])
|
||||
|
||||
const handleTranscribeAudio = useCallback(async (jobId?: string, options?: { silent?: boolean }) => {
|
||||
const targetId = jobId ?? activeJobId
|
||||
if (!targetId) return
|
||||
const target = jobs.find((item) => item.id === targetId)
|
||||
if (!target) return
|
||||
if (!["frames_extracted", "transcribed", "failed"].includes(target.status)) {
|
||||
if (!options?.silent) toast.info("先完成抽帧,音频轨会自动开始处理")
|
||||
return
|
||||
}
|
||||
try {
|
||||
const updated = await triggerTranscribe(targetId)
|
||||
updateJobInList(updated)
|
||||
if (!options?.silent) toast.success("音频处理已开始")
|
||||
} catch (e) {
|
||||
if (!options?.silent) toast.error("音频处理启动失败:" + (e instanceof Error ? e.message : String(e)))
|
||||
}
|
||||
}, [activeJobId, jobs, updateJobInList])
|
||||
|
||||
const autoAudioStartedRef = useRef<Set<string>>(new Set())
|
||||
useEffect(() => {
|
||||
for (const item of jobs) {
|
||||
const audioStatus = item.audio_script?.status ?? "idle"
|
||||
const hasAudioOutput = item.transcript.length > 0 || !!item.audio_script?.rewritten_text
|
||||
const ready = item.status === "frames_extracted" && !hasAudioOutput && audioStatus !== "rewriting"
|
||||
if (!ready || autoAudioStartedRef.current.has(item.id)) continue
|
||||
autoAudioStartedRef.current.add(item.id)
|
||||
void handleTranscribeAudio(item.id, { silent: true })
|
||||
}
|
||||
}, [jobs, handleTranscribeAudio])
|
||||
|
||||
const handleQuickGenerateVideo = useCallback(async (frameIdx: number, scene: StoryboardScene, model: string) => {
|
||||
if (!job) return
|
||||
const frame = job.frames.find((f) => f.index === frameIdx)
|
||||
@@ -696,9 +726,10 @@ export default function Home() {
|
||||
clipboard,
|
||||
onCopyImage: handleCopyImage,
|
||||
onGenerateProductFusionVideo: handleGenerateProductFusionVideo,
|
||||
onTranscribeAudio: handleTranscribeAudio,
|
||||
pinnedNodes,
|
||||
onToggleNodePin: handleToggleNodePin,
|
||||
}), [job, jobs, activeJobId, submitting, analyzing, frameTargets, frameCounts, frameQualities, selectedFrames, expandedFrame, framePanelScale, framePanelPinned, framePanelDock, videoPanelJobId, videoPanelScale, videoPanelDock, handleSubmit, handleUpload, handleAnalyze, handleAnalyzeJob, handleFrameTargetChange, handleFrameCountChange, handleFrameQualityChange, handleToggleFrame, handleOpenFramePanel, handleFramePanelScaleChange, handleCloseExpandedFrame, handleAddManualFrame, handleAddManualFrameForJob, handleOpenVideoPanel, handleVideoPanelScaleChange, handleSwitchJob, updateJobInList, handleDeleteJob, handleDeleteFrame, handleDeleteFrameForJob, handleDeleteGenerated, handleDeleteVideo, handleDeleteCutout, handleOpenStoryboard, handleOpenWorkbench, clipboard, handleCopyImage, handleGenerateProductFusionVideo, pinnedNodes, handleToggleNodePin])
|
||||
}), [job, jobs, activeJobId, submitting, analyzing, frameTargets, frameCounts, frameQualities, selectedFrames, expandedFrame, framePanelScale, framePanelPinned, framePanelDock, videoPanelJobId, videoPanelScale, videoPanelDock, handleSubmit, handleUpload, handleAnalyze, handleAnalyzeJob, handleFrameTargetChange, handleFrameCountChange, handleFrameQualityChange, handleToggleFrame, handleOpenFramePanel, handleFramePanelScaleChange, handleCloseExpandedFrame, handleAddManualFrame, handleAddManualFrameForJob, handleOpenVideoPanel, handleVideoPanelScaleChange, handleSwitchJob, updateJobInList, handleDeleteJob, handleDeleteFrame, handleDeleteFrameForJob, handleDeleteGenerated, handleDeleteVideo, handleDeleteCutout, handleOpenStoryboard, handleOpenWorkbench, clipboard, handleCopyImage, handleGenerateProductFusionVideo, handleTranscribeAudio, pinnedNodes, handleToggleNodePin])
|
||||
|
||||
// 用 useNodesState 让 ReactFlow 自己管位置(避免轮询时重置 drag)
|
||||
const savedSizes = useMemo(() => loadNodeSizes(), [])
|
||||
|
||||
Reference in New Issue
Block a user