auto-save 2026-05-18 00:12 (~3)
This commit is contained in:
@@ -260,8 +260,42 @@ function closestFrameForTime(frames: KeyFrame[], time: number) {
|
||||
}
|
||||
|
||||
function isSimilarActorElement(element: KeyElement) {
|
||||
const name = `${element.name_zh || ""} ${element.name_en || ""}`.toLowerCase()
|
||||
return name.includes("相似主角") || name.includes("相似主体") || name.includes("similar ad actor") || name.includes("similar actor") || name.includes("similar subject")
|
||||
const zh = element.name_zh || ""
|
||||
const en = (element.name_en || "").toLowerCase()
|
||||
const combined = `${zh} ${en}`.toLowerCase()
|
||||
const zhSimilarSubject = zh.includes("相似") && (zh.includes("主体") || zh.includes("主角") || zh.includes("人物"))
|
||||
const enSimilarSubject = en.includes("similar") && (en.includes("subject") || en.includes("actor") || en.includes("humanoid") || en.includes("character"))
|
||||
return (
|
||||
zhSimilarSubject
|
||||
|| enSimilarSubject
|
||||
|| combined.includes("相似主角")
|
||||
|| combined.includes("相似主体")
|
||||
|| combined.includes("similar ad actor")
|
||||
|| combined.includes("similar actor")
|
||||
|| combined.includes("similar subject")
|
||||
|| combined.includes("transparent skeleton humanoid subject")
|
||||
)
|
||||
}
|
||||
|
||||
function findSimilarActorSource(preferredFrames: KeyFrame[], allFrames: KeyFrame[]) {
|
||||
const pools = [preferredFrames, allFrames]
|
||||
const seen = new Set<number>()
|
||||
for (const needsAssets of [true, false]) {
|
||||
for (const pool of pools) {
|
||||
const frames = [...pool].filter((frame) => {
|
||||
if (seen.has(frame.index)) return false
|
||||
seen.add(frame.index)
|
||||
return true
|
||||
}).reverse()
|
||||
for (const frame of frames) {
|
||||
const elements = [...(frame.elements || [])].reverse()
|
||||
const element = elements.find((item) => isSimilarActorElement(item) && (!needsAssets || !!item.subject_assets?.length))
|
||||
if (element) return { frame, element }
|
||||
}
|
||||
}
|
||||
seen.clear()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function buildSimilarSubjectPrompt(subjectStyle: SubjectStyleMode, direction: string) {
|
||||
@@ -306,6 +340,10 @@ function imageModelChain(models?: RuntimeModels) {
|
||||
return modelList(models?.image_fallbacks?.length ? models.image_fallbacks : [models?.image, "gemini-3.1-flash-image-preview", "gemini-2.5-flash-image"])
|
||||
}
|
||||
|
||||
function subjectImageModelChain(models?: RuntimeModels) {
|
||||
return modelList(models?.subject_image_fallbacks?.length ? models.subject_image_fallbacks : [models?.subject_image, "gpt-image-2", "gpt-image-1.5"])
|
||||
}
|
||||
|
||||
function resolveVideoModelLabel(models: RuntimeModels | undefined, model: string) {
|
||||
const concrete = models?.video_aliases?.[model] || (model === models?.video ? models.video : "")
|
||||
return concrete && concrete !== model ? `${model} -> ${concrete}` : modelValue(concrete || model)
|
||||
@@ -340,11 +378,11 @@ function productModelTrace(models?: RuntimeModels): ModelTraceSpec {
|
||||
function similarSubjectModelTrace(models: RuntimeModels | undefined, subjectStyle: SubjectStyleMode): ModelTraceSpec {
|
||||
return {
|
||||
title: subjectStyle === "transparent_human" ? "相似透明骨架主体" : "相似普通真人主体",
|
||||
model: imageModelChain(models),
|
||||
model: subjectImageModelChain(models),
|
||||
chain: [
|
||||
"参考帧策略:未勾选时使用全部关键帧,勾选后只使用已选关键帧",
|
||||
`主体类型:${subjectStyle === "transparent_human" ? "透明/半透明皮肤包裹可见白色骨架" : "普通商业广告真人"}`,
|
||||
`图像生成:${imageModelChain(models)} 逐张生成正、背、左、右、左前 45、右前 45`,
|
||||
`图像生成:${subjectImageModelChain(models)} 逐张生成正、背、左、右、左前 45、右前 45`,
|
||||
"身份锁定:六张必须是同一个主体,性别表现、年龄段、体型、材质和风格保持一致",
|
||||
],
|
||||
note: "这是生成类似主体,不是复制、抠出或复刻源视频人物身份。",
|
||||
@@ -1411,17 +1449,8 @@ function SourceReferenceBuildPanel({
|
||||
[frames, selectedReferenceFrames],
|
||||
)
|
||||
const actorSource = useMemo(() => {
|
||||
const pool = subjectReferenceFrames
|
||||
for (const frame of pool) {
|
||||
const element = frame.elements?.find(isSimilarActorElement)
|
||||
if (element?.subject_assets?.length) return { frame, element }
|
||||
}
|
||||
for (const frame of pool) {
|
||||
const element = frame.elements?.find(isSimilarActorElement)
|
||||
if (element) return { frame, element }
|
||||
}
|
||||
return null
|
||||
}, [subjectReferenceFrames])
|
||||
return findSimilarActorSource(subjectReferenceFrames, frames)
|
||||
}, [frames, subjectReferenceFrames])
|
||||
const actorAssets = actorSource?.element.subject_assets ?? []
|
||||
const previewFrame = framePreview ? frames.find((frame) => frame.index === framePreview.index) ?? null : null
|
||||
const referenceCountLabel = selectedReferenceFrames.length
|
||||
|
||||
Reference in New Issue
Block a user