fix(design): connect video preparation and playable history
This commit is contained in:
1 parent
4321c77613
commit
1acca836fe
21 files changed
+900
-115
No files matched your search
@@ -0,0 +1,104 @@
|
||||
import type {
|
||||
DesignAsset,
|
||||
DesignSpecificationValues,
|
||||
DesignUserFieldOperation,
|
||||
DesignWorkspace,
|
||||
} from '../../../shared/image-workspace';
|
||||
import {
|
||||
insertReferenceToken,
|
||||
promptReferencesImage,
|
||||
} from './reference-tokens';
|
||||
|
||||
type ReferenceValue = DesignSpecificationValues['references'][number];
|
||||
|
||||
function createReferenceId(): string {
|
||||
const random = globalThis.crypto?.randomUUID?.()
|
||||
?? `${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
||||
return `reference-${random}`.slice(0, 64);
|
||||
}
|
||||
|
||||
export function creatorPromptForWorkspace(workspace: DesignWorkspace): string {
|
||||
const values = workspace.form.specification.values;
|
||||
return values.content.concept?.trim()
|
||||
|| values.content.narrative?.trim()
|
||||
|| [
|
||||
...values.content.subjects.map((subject) => subject.description.trim()),
|
||||
values.content.action?.trim(),
|
||||
values.content.environment?.trim(),
|
||||
values.content.emotional_tone?.trim(),
|
||||
].filter((value): value is string => Boolean(value)).join(',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the explicit field changes for using an existing image as a video's
|
||||
* first frame. The asset is only bound to the design; it is never copied or
|
||||
* deleted, and existing reference rows stay in place so @图片 numbers remain
|
||||
* stable.
|
||||
*/
|
||||
export function createVideoFirstFrameOperations(
|
||||
workspace: DesignWorkspace,
|
||||
asset: DesignAsset,
|
||||
promptOverride?: string,
|
||||
): { operations: DesignUserFieldOperation[]; nextPrompt: string; referenceIndex: number } {
|
||||
if (asset.mediaType !== 'image') {
|
||||
throw new Error('视频开始画面必须使用图片');
|
||||
}
|
||||
|
||||
const values = workspace.form.specification.values;
|
||||
const references = values.references;
|
||||
const currentFirstFrameIndex = references.findIndex((reference) => (
|
||||
reference.role === 'first_frame'
|
||||
|| reference.asset_id === values.video.first_frame_asset_id
|
||||
));
|
||||
const selectedReferenceIndex = references.findIndex((reference) => (
|
||||
reference.asset_id === asset.assetId
|
||||
));
|
||||
|
||||
let nextReferences: ReferenceValue[];
|
||||
let referenceIndex: number;
|
||||
if (selectedReferenceIndex >= 0) {
|
||||
referenceIndex = selectedReferenceIndex;
|
||||
nextReferences = references.map((reference, index) => {
|
||||
if (index === referenceIndex) return { ...reference, role: 'first_frame' };
|
||||
if (index === currentFirstFrameIndex && index !== referenceIndex) {
|
||||
return { ...reference, role: 'inspiration' };
|
||||
}
|
||||
return reference;
|
||||
});
|
||||
} else if (currentFirstFrameIndex >= 0) {
|
||||
referenceIndex = currentFirstFrameIndex;
|
||||
nextReferences = references.map((reference, index) => (
|
||||
index === referenceIndex
|
||||
? { ...reference, asset_id: asset.assetId, asset_revision: null, role: 'first_frame' }
|
||||
: reference
|
||||
));
|
||||
} else {
|
||||
referenceIndex = references.length;
|
||||
nextReferences = [
|
||||
...references,
|
||||
{
|
||||
id: createReferenceId(),
|
||||
asset_id: asset.assetId,
|
||||
asset_revision: null,
|
||||
role: 'first_frame',
|
||||
preserve: [],
|
||||
adapt: [],
|
||||
do_not_copy: [],
|
||||
reviewed_observations: [],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const prompt = promptOverride ?? creatorPromptForWorkspace(workspace);
|
||||
const inserted = promptReferencesImage(prompt, referenceIndex)
|
||||
? { value: prompt }
|
||||
: insertReferenceToken(prompt, referenceIndex, null);
|
||||
const operations: DesignUserFieldOperation[] = [
|
||||
{ kind: 'set', path: 'references', value: nextReferences },
|
||||
{ kind: 'set', path: 'video.first_frame_asset_id', value: asset.assetId },
|
||||
];
|
||||
if (inserted.value.trim() !== prompt.trim()) {
|
||||
operations.push({ kind: 'set', path: 'content.concept', value: inserted.value.trim() });
|
||||
}
|
||||
return { operations, nextPrompt: inserted.value.trim(), referenceIndex };
|
||||
}
|
||||
Reference in new issue
Block a user