auto-save 2026-05-14 09:24 (~2)
This commit is contained in:
@@ -1,19 +1,5 @@
|
||||
{
|
||||
"entries": [
|
||||
{
|
||||
"files_changed": 1,
|
||||
"hash": "8e3b365",
|
||||
"message": "auto-save 2026-05-12 22:36 (~1)",
|
||||
"ts": "2026-05-12T22:36:36+08:00",
|
||||
"type": "commit"
|
||||
},
|
||||
{
|
||||
"files_changed": 1,
|
||||
"hash": "2009c43",
|
||||
"message": "auto-save 2026-05-12 22:41 (~1)",
|
||||
"ts": "2026-05-12T22:42:07+08:00",
|
||||
"type": "commit"
|
||||
},
|
||||
{
|
||||
"files_changed": 1,
|
||||
"hash": "9279e55",
|
||||
@@ -3331,6 +3317,19 @@
|
||||
"type": "session-heartbeat",
|
||||
"message": "Codex 会话活跃 · 最近命令:codex · 1 项未提交变更 · 最近提交:auto-save 2026-05-14 09:13 (~1)",
|
||||
"files_changed": 1
|
||||
},
|
||||
{
|
||||
"ts": "2026-05-14T09:19:35+08:00",
|
||||
"type": "commit",
|
||||
"message": "auto-save 2026-05-14 09:19 (~2)",
|
||||
"hash": "1ac55e5",
|
||||
"files_changed": 2
|
||||
},
|
||||
{
|
||||
"ts": "2026-05-14T01:20:31Z",
|
||||
"type": "session-heartbeat",
|
||||
"message": "Claude 会话活跃 · 最近命令:claude · 1 项未提交变更 · 最近提交:auto-save 2026-05-14 09:19 (~2)",
|
||||
"files_changed": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -696,7 +696,7 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
|
||||
} : {
|
||||
top: 80,
|
||||
right: 16,
|
||||
width: 740,
|
||||
width: isProductTab ? "min(1280px, calc(100vw - 32px))" : 740,
|
||||
maxHeight: "calc(100vh - 96px)",
|
||||
boxShadow: "0 40px 100px -20px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.05)",
|
||||
animation: "drawer-in 0.24s cubic-bezier(0.32, 0.72, 0, 1)",
|
||||
@@ -930,118 +930,237 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
|
||||
</span>
|
||||
</div>
|
||||
<div className="mb-2 rounded-md border border-white/10 bg-black/25 px-2 py-1.5 text-[10px] leading-relaxed text-white/50">
|
||||
每行一条镜头:产品图、白底人物图、人物图上的产品区域、场景图和描述词一一对应。
|
||||
6 条视频镜头从上到下排列;每条都能直接看到产品图、白底人物、融合区域、场景、描述和秒数。
|
||||
</div>
|
||||
<div className="mb-3 space-y-1.5">
|
||||
<div className="space-y-2">
|
||||
{fusionShots.map((shot, i) => {
|
||||
const active = i === activeFusionShot
|
||||
const productUrl = shot.product_image ? resolveImageRefUrl(jobId, shot.product_image) : ""
|
||||
const personUrl = shot.person_image ? resolveImageRefUrl(jobId, shot.person_image) : ""
|
||||
const sceneUrl = shot.scene_image ? resolveImageRefUrl(jobId, shot.scene_image) : ""
|
||||
const ready = !!(shot.product_image && shot.person_image && shot.product_region && shot.scene_image && shot.action_text?.trim())
|
||||
const busy = fusionGenerating === i || fusionGenerating === "all"
|
||||
const pasteIntoSlot = (slot: "product_image" | "person_image" | "scene_image", label: string) => {
|
||||
setActiveFusionShot(i)
|
||||
if (clipboard) {
|
||||
assignFusionImage(slot, clipboard, i)
|
||||
toast.success(`已粘贴到镜头 ${i + 1}「${label}」:${clipboard.label || "剪贴板图片"}`)
|
||||
return
|
||||
}
|
||||
setFusionUploadTarget(slot)
|
||||
toast.message(`镜头 ${i + 1} 已选中「${label}」槽位,现在可 Cmd+V 粘贴系统图片`)
|
||||
}
|
||||
const imageSlot = (slot: "product_image" | "scene_image", label: string, url: string) => {
|
||||
const ref = shot[slot]
|
||||
return (
|
||||
<div className="overflow-hidden rounded-md border border-white/10 bg-black/24">
|
||||
<div className="relative aspect-square bg-white">
|
||||
{url ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveFusionShot(i)}
|
||||
className="absolute inset-0 cursor-pointer"
|
||||
title={`选中镜头 ${i + 1}`}
|
||||
>
|
||||
<img src={url} alt={label} className="h-full w-full object-contain" draggable={false} />
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openFusionUpload(slot, i)}
|
||||
className="absolute inset-0 flex flex-col items-center justify-center gap-1 text-[9.5px] text-black/35 hover:text-black/65"
|
||||
>
|
||||
<Upload className="h-3.5 w-3.5" />
|
||||
上传
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="border-t border-white/10 px-1 py-1">
|
||||
<div className="mb-1 truncate text-[8.5px] text-white/42">{ref?.label || label}</div>
|
||||
<div className="grid grid-cols-2 gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => pasteIntoSlot(slot, label)}
|
||||
className={`rounded px-1 py-0.5 text-[8.5px] transition ${
|
||||
clipboard ? "bg-violet-500/60 text-white hover:bg-violet-400/70" : "bg-white/10 text-white/58 hover:bg-white/18 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
粘贴
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openFusionUpload(slot, i)}
|
||||
className="rounded bg-white/10 px-1 py-0.5 text-[8.5px] text-white/65 transition hover:bg-white/18 hover:text-white"
|
||||
>
|
||||
上传
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<button
|
||||
<div
|
||||
key={shot.id}
|
||||
type="button"
|
||||
onClick={() => setActiveFusionShot(i)}
|
||||
className={`grid w-full grid-cols-[40px_1fr_1fr_54px] items-center gap-1.5 rounded-md border px-2 py-1.5 text-left transition ${
|
||||
className={`rounded-lg border p-2 transition ${
|
||||
active
|
||||
? "border-amber-300/70 bg-amber-500/18 text-white"
|
||||
: "border-white/10 bg-black/22 text-white/55 hover:border-amber-300/35 hover:text-white"
|
||||
? "border-amber-300/70 bg-amber-500/16 shadow-[0_0_0_1px_rgba(251,191,36,0.14)]"
|
||||
: "border-white/10 bg-black/20 hover:border-amber-300/35"
|
||||
}`}
|
||||
>
|
||||
<span className="font-mono text-[10px]">#{i + 1}</span>
|
||||
<span className="truncate text-[10px]">{shot.product_image?.label || "产品图空"}</span>
|
||||
<span className="truncate text-[10px]">{shot.scene_image?.label || "场景图空"}</span>
|
||||
<span className={`rounded px-1 py-0.5 text-center text-[9px] ${ready ? "bg-emerald-400/80 text-black" : "bg-white/10 text-white/45"}`}>
|
||||
{ready ? "就绪" : "待补"}
|
||||
</span>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
<div className="grid grid-cols-3 gap-2">
|
||||
{([
|
||||
["product_image", "产品图", currentFusionProductUrl],
|
||||
["person_image", "白底人物图", currentFusionPersonUrl],
|
||||
["scene_image", "场景图", currentFusionSceneUrl],
|
||||
] as const).map(([slot, label, url]) => (
|
||||
<div key={slot} className="overflow-hidden rounded-md border border-white/10 bg-black/25">
|
||||
<div className="relative bg-white" style={{ aspectRatio: "1/1" }}>
|
||||
{url ? (
|
||||
<img src={url} alt={label} className="absolute inset-0 h-full w-full object-contain" />
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openFusionUpload(slot)}
|
||||
className="absolute inset-0 flex flex-col items-center justify-center gap-1 text-[10px] text-black/35 hover:text-black/65"
|
||||
>
|
||||
<Upload className="h-4 w-4" />
|
||||
上传/粘贴
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center justify-between gap-1 border-t border-white/10 px-1.5 py-1">
|
||||
<span className="truncate text-[9.5px] text-white/55">{label}</span>
|
||||
<div className="flex items-center gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (clipboard) {
|
||||
assignFusionImage(slot, clipboard)
|
||||
toast.success(`已粘贴到「${label}」:${clipboard.label || "剪贴板图片"}`)
|
||||
return
|
||||
}
|
||||
setFusionUploadTarget(slot)
|
||||
toast.message(`应用剪贴板为空;已选中「${label}」槽位,现在可 Cmd+V 粘贴系统图片`)
|
||||
}}
|
||||
className={`rounded px-1.5 py-0.5 text-[9px] hover:bg-white/18 hover:text-white ${
|
||||
clipboard ? "bg-violet-500/60 text-white" : "bg-white/10 text-white/60"
|
||||
}`}
|
||||
title={clipboard ? `粘贴应用剪贴板:${clipboard.label || "图片"}` : "应用剪贴板为空;可先点槽位后 Cmd+V 粘贴系统图片"}
|
||||
>
|
||||
粘贴
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openFusionUpload(slot)}
|
||||
className="rounded bg-white/10 px-1.5 py-0.5 text-[9px] text-white/70 hover:bg-white/18 hover:text-white"
|
||||
>
|
||||
上传
|
||||
</button>
|
||||
<div className="grid grid-cols-[34px_82px_112px_82px_minmax(150px,1fr)_78px] items-start gap-2">
|
||||
<div className="flex flex-col items-center gap-1 pt-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveFusionShot(i)}
|
||||
className={`h-8 w-8 rounded-md border text-[10px] font-mono transition ${
|
||||
active
|
||||
? "border-amber-200/70 bg-amber-300/20 text-amber-50"
|
||||
: "border-white/10 bg-white/7 text-white/48 hover:border-amber-300/35 hover:text-white"
|
||||
}`}
|
||||
title={`切到镜头 ${i + 1}`}
|
||||
>
|
||||
{String(i + 1).padStart(2, "0")}
|
||||
</button>
|
||||
<span className={`rounded px-1 py-0.5 text-[8.5px] ${ready ? "bg-emerald-400/80 text-black" : "bg-white/10 text-white/45"}`}>
|
||||
{ready ? "就绪" : "待补"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{imageSlot("product_image", "产品图", productUrl)}
|
||||
|
||||
<div className="overflow-hidden rounded-md border border-white/10 bg-black/24">
|
||||
<div
|
||||
ref={active ? fusionPersonWrapRef : undefined}
|
||||
onMouseDown={personUrl ? (ev) => {
|
||||
setActiveFusionShot(i)
|
||||
if (active) onFusionRegionDown(ev)
|
||||
} : undefined}
|
||||
onMouseMove={active ? onFusionRegionMove : undefined}
|
||||
onMouseUp={active ? onFusionRegionUp : undefined}
|
||||
onMouseLeave={active ? onFusionRegionUp : undefined}
|
||||
className={`relative aspect-[4/5] bg-white ${
|
||||
personUrl ? (active ? "cursor-crosshair" : "cursor-pointer") : ""
|
||||
}`}
|
||||
title={personUrl ? (active ? "拖动画出产品融合区域" : "点击后编辑此镜头区域") : "上传白底人物图"}
|
||||
>
|
||||
{personUrl ? (
|
||||
<>
|
||||
<img src={personUrl} alt="白底人物图" className="h-full w-full select-none object-contain" draggable={false} />
|
||||
{!active && (
|
||||
<div className="absolute inset-x-1 bottom-1 rounded bg-black/55 px-1 py-0.5 text-center text-[8px] text-white/75">
|
||||
点此编辑区域
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openFusionUpload("person_image", i)}
|
||||
className="absolute inset-0 flex flex-col items-center justify-center gap-1 text-[9.5px] text-black/35 hover:text-black/65"
|
||||
>
|
||||
<Upload className="h-3.5 w-3.5" />
|
||||
白底人物
|
||||
</button>
|
||||
)}
|
||||
{[shot.product_region, active ? fusionDraftRegion : null].filter(Boolean).map((region, regionIdx) => region && (
|
||||
<div
|
||||
key={regionIdx}
|
||||
className={`absolute pointer-events-none border-2 ${regionIdx === 0 ? "border-amber-300 bg-amber-300/10" : "border-dashed border-cyan-300"}`}
|
||||
style={{
|
||||
left: `${region.x * 100}%`,
|
||||
top: `${region.y * 100}%`,
|
||||
width: `${region.w * 100}%`,
|
||||
height: `${region.h * 100}%`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="border-t border-white/10 px-1 py-1">
|
||||
<div className="mb-1 truncate text-[8.5px] text-white/42">
|
||||
{shot.person_image?.label || (shot.product_region ? "人物图 · 已画区域" : "白底人物图")}
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-1">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => pasteIntoSlot("person_image", "白底人物图")}
|
||||
className={`rounded px-1 py-0.5 text-[8.5px] transition ${
|
||||
clipboard ? "bg-violet-500/60 text-white hover:bg-violet-400/70" : "bg-white/10 text-white/58 hover:bg-white/18 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
粘贴
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => openFusionUpload("person_image", i)}
|
||||
className="rounded bg-white/10 px-1 py-0.5 text-[8.5px] text-white/65 transition hover:bg-white/18 hover:text-white"
|
||||
>
|
||||
上传
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{imageSlot("scene_image", "场景图", sceneUrl)}
|
||||
|
||||
<label className="block">
|
||||
<div className="mb-1 flex items-center justify-between gap-2">
|
||||
<span className="text-[9px] text-white/38">描述词 · 人在干什么</span>
|
||||
<span className="text-[8.5px] text-white/30">#{i + 1}</span>
|
||||
</div>
|
||||
<textarea
|
||||
value={shot.action_text ?? ""}
|
||||
onFocus={() => setActiveFusionShot(i)}
|
||||
onChange={(e) => updateFusionShot(i, { action_text: e.target.value })}
|
||||
onBlur={(e) => {
|
||||
const next = fusionShots.map((item, idx) => (idx === i ? { ...item, action_text: e.currentTarget.value } : item))
|
||||
void persistFusionShots(next)
|
||||
}}
|
||||
placeholder="描述这个镜头里人物和产品的动作、位置、节奏。"
|
||||
className="h-[92px] w-full resize-none rounded-md border border-white/10 bg-black/35 px-2 py-1.5 text-[10px] leading-relaxed text-white/75 outline-none placeholder:text-white/25 focus:border-amber-300/45"
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<select
|
||||
value={shot.duration ?? 5}
|
||||
onFocus={() => setActiveFusionShot(i)}
|
||||
onChange={(e) => updateFusionShot(i, { duration: Number(e.target.value) }, true)}
|
||||
className="h-7 w-full rounded-md border border-white/10 bg-black/35 px-1.5 text-[10px] text-white/75 outline-none focus:border-amber-300/45"
|
||||
title="视频秒数"
|
||||
>
|
||||
{FUSION_DURATIONS.map((seconds) => (
|
||||
<option key={seconds} value={seconds}>{seconds}s</option>
|
||||
))}
|
||||
</select>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setActiveFusionShot(i)
|
||||
void runFusionVideo(i)
|
||||
}}
|
||||
disabled={!!fusionGenerating || !onGenerateProductFusionVideo}
|
||||
className="inline-flex h-9 items-center justify-center gap-1 rounded-md bg-amber-500/75 px-1.5 text-[10px] font-medium text-white transition hover:bg-amber-400 disabled:cursor-not-allowed disabled:opacity-40"
|
||||
>
|
||||
{busy ? <Loader2 className="h-3 w-3 animate-spin" /> : <Play className="h-3 w-3" />}
|
||||
生成
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setActiveFusionShot(i)}
|
||||
className={`h-7 rounded-md border px-1.5 text-[9px] transition ${
|
||||
active
|
||||
? "border-amber-300/55 bg-amber-500/18 text-amber-50"
|
||||
: "border-white/10 bg-white/7 text-white/50 hover:border-amber-300/35 hover:text-white"
|
||||
}`}
|
||||
>
|
||||
{active ? "当前" : "编辑"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-3 rounded-lg border border-white/10 bg-black/30 p-2">
|
||||
<div className="mb-2 flex items-center justify-between gap-2">
|
||||
<div className="text-[11px] font-semibold text-white">产品区域 · 在人物图上画框</div>
|
||||
<span className="text-[9px] text-white/35">产品只在框内融合</span>
|
||||
</div>
|
||||
<div
|
||||
ref={fusionPersonWrapRef}
|
||||
onMouseDown={onFusionRegionDown}
|
||||
onMouseMove={onFusionRegionMove}
|
||||
onMouseUp={onFusionRegionUp}
|
||||
onMouseLeave={onFusionRegionUp}
|
||||
className={`relative overflow-hidden rounded-md border border-white/10 bg-white ${currentFusionPersonUrl ? "cursor-crosshair" : ""}`}
|
||||
>
|
||||
{currentFusionPersonUrl ? (
|
||||
<img src={currentFusionPersonUrl} alt="fusion person" className="block w-full select-none object-contain" draggable={false} />
|
||||
) : (
|
||||
<div className="flex h-64 items-center justify-center text-[11px] text-black/35">先上传白底人物图</div>
|
||||
)}
|
||||
{[currentFusionShot?.product_region, fusionDraftRegion].filter(Boolean).map((region, i) => region && (
|
||||
<div
|
||||
key={i}
|
||||
className={`absolute pointer-events-none border-2 ${i === 0 ? "border-amber-300 bg-amber-300/10" : "border-dashed border-cyan-300"}`}
|
||||
style={{
|
||||
left: `${region.x * 100}%`,
|
||||
top: `${region.y * 100}%`,
|
||||
width: `${region.w * 100}%`,
|
||||
height: `${region.h * 100}%`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
) : (
|
||||
@@ -1412,7 +1531,7 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
|
||||
<>
|
||||
<section className="rounded-lg border border-amber-300/18 bg-amber-500/[0.08] p-2.5 text-[10.5px] leading-relaxed text-white/58">
|
||||
<div className="mb-2 flex items-center justify-between gap-2">
|
||||
<div className="text-[12px] font-semibold text-white">镜头 {activeFusionShot + 1} 设置</div>
|
||||
<div className="text-[12px] font-semibold text-white">产品融合辅助</div>
|
||||
<span className="text-[9px] text-white/40">{fusionSaving ? "保存中" : "自动保存"}</span>
|
||||
</div>
|
||||
<div className="mb-2 grid grid-cols-2 gap-1.5">
|
||||
@@ -1425,46 +1544,29 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
|
||||
<div className="text-white/80">Seedance</div>
|
||||
</div>
|
||||
</div>
|
||||
<label className="mb-2 block">
|
||||
<span className="mb-1 block text-[9px] text-white/35">视频秒数</span>
|
||||
<select
|
||||
value={currentFusionShot?.duration ?? 5}
|
||||
onChange={(e) => updateFusionShot(activeFusionShot, { duration: Number(e.target.value) }, true)}
|
||||
className="h-8 w-full rounded-md border border-white/10 bg-black/35 px-2 text-[11px] text-white/75 outline-none"
|
||||
>
|
||||
{FUSION_DURATIONS.map((seconds) => (
|
||||
<option key={seconds} value={seconds}>{seconds} 秒</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
<label className="mb-2 block">
|
||||
<div className="mb-2 rounded-md border border-white/10 bg-black/25 px-2 py-1.5">
|
||||
<div className="mb-1 flex items-center justify-between gap-2">
|
||||
<span className="text-[9px] text-white/35">描述词 · 人在干什么</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={draftFusionDescriptions}
|
||||
className="rounded bg-white/10 px-1.5 py-0.5 text-[9.5px] text-white/60 hover:bg-white/18 hover:text-white"
|
||||
>
|
||||
AI 草拟 6 条
|
||||
</button>
|
||||
<span className="font-mono text-[10px] text-amber-100">当前镜头 {activeFusionShot + 1}</span>
|
||||
<span className="text-[9px] text-white/38">{currentFusionShot?.duration ?? 5}s</span>
|
||||
</div>
|
||||
<textarea
|
||||
value={currentFusionShot?.action_text ?? ""}
|
||||
onChange={(e) => updateFusionShot(activeFusionShot, { action_text: e.target.value })}
|
||||
onBlur={() => void persistFusionShots(fusionShots)}
|
||||
placeholder="例如:人物把 SKG 颈部按摩仪戴到脖子上,手部轻轻调整两侧机身,场景是办公桌前。"
|
||||
className="h-24 w-full resize-none rounded-md border border-white/10 bg-black/35 px-2 py-1.5 text-[10px] leading-relaxed text-white/75 outline-none placeholder:text-white/25"
|
||||
/>
|
||||
</label>
|
||||
<div className="grid grid-cols-2 gap-x-2 gap-y-1 text-[9.5px]">
|
||||
<span className={currentFusionShot?.product_image ? "text-emerald-200/80" : "text-white/35"}>产品图</span>
|
||||
<span className={currentFusionShot?.person_image ? "text-emerald-200/80" : "text-white/35"}>白底人物</span>
|
||||
<span className={currentFusionShot?.product_region ? "text-emerald-200/80" : "text-white/35"}>产品区域</span>
|
||||
<span className={currentFusionShot?.scene_image ? "text-emerald-200/80" : "text-white/35"}>场景图</span>
|
||||
</div>
|
||||
<div className={`mt-1 truncate text-[9.5px] ${currentFusionShot?.action_text?.trim() ? "text-white/58" : "text-white/32"}`}>
|
||||
{currentFusionShot?.action_text?.trim() || "描述词未填写"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-1.5">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => void runFusionVideo(activeFusionShot)}
|
||||
disabled={!!fusionGenerating || !onGenerateProductFusionVideo}
|
||||
className="rounded-md bg-amber-500/75 px-2 py-1.5 text-[11px] font-medium text-white transition hover:bg-amber-400 disabled:cursor-not-allowed disabled:opacity-40 inline-flex items-center justify-center gap-1"
|
||||
onClick={draftFusionDescriptions}
|
||||
className="rounded-md bg-white/10 px-2 py-1.5 text-[11px] font-medium text-white/75 transition hover:bg-white/18 hover:text-white inline-flex items-center justify-center gap-1"
|
||||
>
|
||||
{fusionGenerating === activeFusionShot ? <Loader2 className="h-3 w-3 animate-spin" /> : <Play className="h-3 w-3" />}
|
||||
生成本条
|
||||
<Sparkles className="h-3 w-3" />
|
||||
AI 草拟 6 条
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -1481,8 +1583,8 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
|
||||
jobId={jobId}
|
||||
compact
|
||||
buttonLabel="选用"
|
||||
title="当前镜头产品图"
|
||||
onPick={(ref) => assignFusionImage("product_image", ref)}
|
||||
title={`镜头 ${activeFusionShot + 1} 产品图`}
|
||||
onPick={(ref) => assignFusionImage("product_image", ref, activeFusionShot)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user