auto-save 2026-05-14 04:21 (~6)

This commit is contained in:
2026-05-14 04:21:26 +08:00
parent b52642ba77
commit ec96e81c02
6 changed files with 93 additions and 23 deletions

View File

@@ -19,7 +19,7 @@ import { ThemeToggle } from "@/components/theme-toggle"
import {
addManualFrame, analyzeJob, createJob, getJob, listJobs, uploadJob, deleteJob, deleteFrame, deleteGeneratedImage,
deleteGeneratedVideo, deleteCutout, generateStoryboardVideo,
type Job, type ImageRef, type StoryboardScene, type FrameExtractMode, type FrameExtractTarget,
type Job, type ImageRef, type StoryboardScene, type FrameExtractMode, type FrameExtractQuality, type FrameExtractTarget,
} from "@/lib/api"
const NODE_TYPES = {
@@ -41,6 +41,11 @@ const FRAME_TARGET_LABELS: Record<FrameExtractTarget, string> = {
expression: "表情瞬间",
motion: "动作峰值",
}
const FRAME_QUALITY_LABELS: Record<FrameExtractQuality, string> = {
fast: "快速",
accurate: "精细",
ultra: "极准",
}
// 合并 input + download + split 为一个节点
// 分叉:上路 input → visual lab ↘
@@ -94,6 +99,7 @@ export default function Home() {
const [analyzing, setAnalyzing] = useState(false)
const [frameTargets, setFrameTargets] = useState<Record<string, FrameExtractTarget>>({})
const [frameCounts, setFrameCounts] = useState<Record<string, number>>({})
const [frameQualities, setFrameQualities] = useState<Record<string, FrameExtractQuality>>({})
const [selectedFrames, setSelectedFrames] = useState<Set<number>>(new Set())
const [expandedFrame, setExpandedFrame] = useState<number | null>(null)
const [framePanelScale, setFramePanelScale] = useState(1)
@@ -172,17 +178,18 @@ export default function Home() {
if (!targetJob) return
const frameTarget = frameTargets[jobId] ?? "balanced"
const frameCount = frameCounts[jobId] ?? 5
const frameQuality = frameQualities[jobId] ?? "accurate"
const mode = options?.mode ?? (targetJob.frames.length > 0 ? "append" : "replace")
setActiveJobId(jobId)
setAnalyzing(true)
if (mode === "replace") setSelectedFrames(new Set())
try {
await analyzeJob(jobId, frameCount, frameTarget, mode)
toast.info(`${mode === "append" ? "追加抽帧" : "开始解析"}${FRAME_TARGET_LABELS[frameTarget]} · ${frameCount}`)
await analyzeJob(jobId, frameCount, frameTarget, mode, frameQuality)
toast.info(`${mode === "append" ? "追加抽帧" : "开始解析"}${FRAME_QUALITY_LABELS[frameQuality]} · ${FRAME_TARGET_LABELS[frameTarget]} · ${frameCount}`)
setJobs((prev) => prev.map((item) => item.id === jobId ? {
...item,
status: "splitting",
message: `${mode === "append" ? "追加抽帧中" : "拆轨中"} · ${FRAME_TARGET_LABELS[frameTarget]}`,
message: `${mode === "append" ? "追加抽帧中" : "拆轨中"} · ${FRAME_QUALITY_LABELS[frameQuality]} · ${FRAME_TARGET_LABELS[frameTarget]}`,
progress: 30,
} : item))
} catch (e) {
@@ -190,7 +197,7 @@ export default function Home() {
} finally {
setAnalyzing(false)
}
}, [jobs, frameCounts, frameTargets])
}, [jobs, frameCounts, frameQualities, frameTargets])
const handleAnalyze = useCallback(async (options?: { mode?: FrameExtractMode }) => {
if (!job) return
@@ -205,6 +212,10 @@ export default function Home() {
setFrameCounts((prev) => ({ ...prev, [jobId]: Math.max(1, Math.min(20, count)) }))
}, [])
const handleFrameQualityChange = useCallback((jobId: string, quality: FrameExtractQuality) => {
setFrameQualities((prev) => ({ ...prev, [jobId]: quality }))
}, [])
const handleAddManualFrameForJob = useCallback(async (jobId: string, t: number) => {
try {
const updated = await addManualFrame(jobId, t)
@@ -529,6 +540,7 @@ export default function Home() {
analyzing,
frameTargets,
frameCounts,
frameQualities,
selectedFrames,
expandedFrame,
framePanelScale,
@@ -543,6 +555,7 @@ export default function Home() {
onAnalyzeJob: handleAnalyzeJob,
onFrameTargetChange: handleFrameTargetChange,
onFrameCountChange: handleFrameCountChange,
onFrameQualityChange: handleFrameQualityChange,
onToggleFrame: handleToggleFrame,
onExpandFrame: setExpandedFrame,
onOpenFramePanel: handleOpenFramePanel,
@@ -572,7 +585,7 @@ export default function Home() {
onCopyImage: handleCopyImage,
pinnedNodes,
onToggleNodePin: handleToggleNodePin,
}), [job, jobs, activeJobId, submitting, analyzing, frameTargets, frameCounts, selectedFrames, expandedFrame, framePanelScale, framePanelPinned, framePanelDock, videoPanelJobId, videoPanelScale, videoPanelDock, handleSubmit, handleUpload, handleAnalyze, handleAnalyzeJob, handleFrameTargetChange, handleFrameCountChange, handleToggleFrame, handleOpenFramePanel, handleFramePanelScaleChange, handleAddManualFrame, handleAddManualFrameForJob, handleOpenVideoPanel, handleVideoPanelScaleChange, handleSwitchJob, setJob, handleDeleteJob, handleDeleteFrame, handleDeleteFrameForJob, handleDeleteGenerated, handleDeleteVideo, handleDeleteCutout, handleCopyImage, 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, handleAddManualFrame, handleAddManualFrameForJob, handleOpenVideoPanel, handleVideoPanelScaleChange, handleSwitchJob, setJob, handleDeleteJob, handleDeleteFrame, handleDeleteFrameForJob, handleDeleteGenerated, handleDeleteVideo, handleDeleteCutout, handleCopyImage, pinnedNodes, handleToggleNodePin])
// 用 useNodesState 让 ReactFlow 自己管位置(避免轮询时重置 drag
const savedSizes = useMemo(() => loadNodeSizes(), [])