auto-save 2026-05-14 02:30 (+2, ~4)

This commit is contained in:
2026-05-14 02:31:01 +08:00
parent eace01e94a
commit 95fbb0cbc6
6 changed files with 364 additions and 56 deletions

View File

@@ -9,13 +9,11 @@ import {
import { Toaster, toast } from "sonner"
import { LayoutGrid } from "lucide-react"
import {
InputNode, KeyframeNode, AudioNode,
StoryboardNode, VideoGenNode, ComposeNode, KeyframePanelNode,
InputNode, VisualLabNode, AudioNode,
ComposeNode, KeyframePanelNode,
type NodeData,
} from "@/components/nodes"
import { ThemeToggle } from "@/components/theme-toggle"
import { StoryboardBar } from "@/components/storyboard-bar"
import { StoryboardWorkbench } from "@/components/storyboard-workbench"
import {
addManualFrame, analyzeJob, createJob, getJob, listJobs, uploadJob, deleteFrame, deleteGeneratedImage,
deleteGeneratedVideo, deleteCutout, generateStoryboardVideo,
@@ -25,10 +23,8 @@ import { VideoLightbox } from "@/components/video-lightbox"
const NODE_TYPES = {
input: InputNode,
keyframe: KeyframeNode,
visual: VisualLabNode,
audio: AudioNode,
storyboard: StoryboardNode,
videogen: VideoGenNode,
compose: ComposeNode,
keyframePanel: KeyframePanelNode,
}
@@ -36,15 +32,13 @@ const NODE_TYPES = {
const KEYFRAME_PANEL_ID = "keyframe-detail-panel"
// 合并 input + download + split 为一个节点
// 分叉:上路 input → keyframe → storyboard → videogen
// 分叉:上路 input → visual lab
// 下路 input → audio ──────────────────────────→ compose
const LAYOUT: Array<{ id: string; type: keyof typeof NODE_TYPES; x: number; y: number; w: number }> = [
{ id: "input", type: "input", x: 40, y: 240, w: 320 },
{ id: "keyframe", type: "keyframe", x: 460, y: 60, w: 360 },
{ id: "visual", type: "visual", x: 460, y: 60, w: 620 },
{ id: "audio", type: "audio", x: 460, y: 440, w: 320 },
{ id: "storyboard", type: "storyboard", x: 880, y: 60, w: 360 },
{ id: "videogen", type: "videogen", x: 1260, y: 60, w: 280 },
{ id: "compose", type: "compose", x: 1640, y: 240, w: 320 },
{ id: "compose", type: "compose", x: 1160, y: 240, w: 320 },
]
const NODE_SIZES_KEY = "skg-tk:node-sizes:v2"
@@ -74,11 +68,9 @@ function loadNodePins(): string[] {
}
const EDGES_RAW: Array<[string, string]> = [
["input", "keyframe"],
["input", "visual"],
["input", "audio"],
["keyframe", "storyboard"],
["storyboard", "videogen"],
["videogen", "compose"],
["visual", "compose"],
["audio", "compose"],
]
@@ -521,9 +513,7 @@ export default function Home() {
// 按管线列分组(顶 → 底):图层 1 输入 → 5 合成
const COLUMNS: string[][] = [
["input"],
["keyframe", "audio"],
["storyboard"],
["videogen"],
["visual", "audio"],
["compose"],
]
const GAP_X = 80
@@ -602,11 +592,11 @@ export default function Home() {
let shouldFocusNewPanel = false
setNodes((prev) => {
const keyframeNode = prev.find((n) => n.id === "keyframe")
const visualNode = prev.find((n) => n.id === "visual")
const inputNode = prev.find((n) => n.id === "input")
const defaultPosition = {
x: (inputNode?.position.x ?? 40) - 820,
y: (keyframeNode?.position.y ?? 60),
y: (visualNode?.position.y ?? 60),
}
const exists = prev.some((n) => n.id === KEYFRAME_PANEL_ID)
if (exists) {
@@ -637,7 +627,7 @@ export default function Home() {
if (shouldFocusNewPanel) {
window.setTimeout(() => {
flowRef.current?.fitView?.({
nodes: [{ id: KEYFRAME_PANEL_ID }, { id: "keyframe" }],
nodes: [{ id: KEYFRAME_PANEL_ID }, { id: "visual" }],
padding: 0.18,
duration: 260,
})
@@ -649,11 +639,10 @@ export default function Home() {
useEffect(() => {
const doneOf: Record<string, boolean> = {
input: !!job?.video_url,
keyframe: !!job && job.frames.length > 0,
visual: !!job && (job.frames.length > 0 || (job.generated_videos?.length ?? 0) > 0),
asr: !!job && job.transcript.length > 0,
translate: !!job && (job.transcript.some((s) => s.zh) ?? false),
rewrite: !!job && (job.transcript.some((s) => s.zh) ?? false),
storyboard: selectedFrames.size > 0,
}
setEdges((prev) => prev.map((e) => ({ ...e, animated: !!doneOf[e.source] })))
}, [job, setEdges])