diff --git a/.memory/worklog.json b/.memory/worklog.json index b8cc7c1..bcd85da 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -447,6 +447,13 @@ "message": "auto-save 2026-05-12 23:10 (~2)", "hash": "3612d62", "files_changed": 2 + }, + { + "ts": "2026-05-12T23:16:27+08:00", + "type": "commit", + "message": "auto-save 2026-05-12 23:16 (~1)", + "hash": "affe487", + "files_changed": 1 } ] } diff --git a/web/components/lightbox.tsx b/web/components/lightbox.tsx index a253cf4..37f1810 100644 --- a/web/components/lightbox.tsx +++ b/web/components/lightbox.tsx @@ -1,6 +1,6 @@ "use client" -import { useEffect } from "react" -import { X, ChevronLeft, ChevronRight, Check } from "lucide-react" +import { useEffect, useState } from "react" +import { X, ChevronLeft, ChevronRight, Check, Sparkles, Wand2, Loader2, Eye } from "lucide-react" import { frameUrl, type KeyFrame } from "@/lib/api" interface Props { @@ -14,13 +14,15 @@ interface Props { } export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, onChange, onToggleSelect }: Props) { + const [extractPrompt, setExtractPrompt] = useState("") + useEffect(() => { if (activeIndex === null) return const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") onClose() if (e.key === "ArrowLeft" && activeIndex > 0) onChange(activeIndex - 1) if (e.key === "ArrowRight" && activeIndex < frames.length - 1) onChange(activeIndex + 1) - if (e.key === " " || e.key === "Enter") { + if ((e.key === " " || e.key === "Enter") && (e.target as HTMLElement).tagName !== "INPUT" && (e.target as HTMLElement).tagName !== "TEXTAREA") { e.preventDefault() onToggleSelect(activeIndex) } @@ -41,7 +43,7 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o {/* 关闭 */} @@ -59,38 +61,121 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o {activeIndex < frames.length - 1 && ( )} - {/* 大图 — 关键帧是静态素材(传给生图节点垫图用),不播放视频 */} -
e.stopPropagation()} className="flex flex-col items-center gap-4 max-w-[92vw] max-h-[92vh]"> - {`frame -
-
- {String(f.index + 1).padStart(2, "0")} / {String(frames.length).padStart(2, "0")} - · - {f.timestamp.toFixed(2)}s + {/* 主体:左大图 + 右识别面板 */} +
e.stopPropagation()} + className="flex gap-4 max-w-[92vw] max-h-[92vh] items-start" + > + {/* 左侧:大图 + 底部 meta */} +
+ {`frame +
+
+ {String(f.index + 1).padStart(2, "0")} / {String(frames.length).padStart(2, "0")} + · + {f.timestamp.toFixed(2)}s +
+
- +
←/→ 切换 · Space 选用 · ESC 关闭
+
+ + {/* 右侧:识别 + 提取面板 */} +
+ {/* 识别到的元素 */} +
+
+
+ + 识别到的元素 +
+ +
+
+
+ + 等待 Vision 模型 +
+ 点击「↻ 刷新」识别图中元素后,这里会列出: +
    +
  • • 主体物(人 / 产品 / 道具)
  • +
  • • 场景 / 背景描述
  • +
  • • 风格 / 打光 / 色调
  • +
+
+ 依赖:Gemini Vision · SKG 网关 image 渠道待开通 +
+
+
+ + {/* 自定义提取 */} +
+
+ + 自定义提取元素 +
+