97 lines
3.0 KiB
TypeScript
97 lines
3.0 KiB
TypeScript
import { z } from "zod";
|
|
export const storyTaskAttachmentSchema = z.discriminatedUnion("type", [
|
|
z.object({
|
|
type: z.literal("story-asset"),
|
|
nodeId: z.string().min(1),
|
|
asset: z.object({
|
|
id: z.string().min(1),
|
|
name: z.string(),
|
|
description: z.string(),
|
|
imageUrl: z.string(),
|
|
type: z.string(),
|
|
}),
|
|
}),
|
|
z.object({
|
|
type: z.literal("story-prompts"),
|
|
nodeId: z.string().min(1),
|
|
rows: z
|
|
.array(z.object({ id: z.string().min(1) }).catchall(z.unknown()))
|
|
.min(1)
|
|
.max(120),
|
|
}),
|
|
]);
|
|
export type StoryTaskAttachment = z.infer<typeof storyTaskAttachmentSchema>;
|
|
export function requireStoryPromptResult(data: any, attachment?: StoryTaskAttachment) {
|
|
if (attachment?.type !== "story-prompts") return;
|
|
if (
|
|
!Array.isArray(data?.analysisRows) ||
|
|
data.analysisRows.length !== attachment.rows.length ||
|
|
data.analysisRows.some(
|
|
(row: any) => !String(row.imagePrompt || "").trim() || !String(row.motionPrompt || "").trim(),
|
|
)
|
|
)
|
|
throw Error("未返回完整镜头提示词,原内容已保留");
|
|
}
|
|
export function mergeStoryTaskResult(
|
|
draft: Record<string, any>,
|
|
attachment: StoryTaskAttachment,
|
|
data: any,
|
|
taskId: string,
|
|
) {
|
|
if (draft.storyTaskResults?.[taskId]) return draft;
|
|
let conflict = false;
|
|
let patch: Record<string, any> = {};
|
|
if (attachment.type === "story-asset") {
|
|
let found = false;
|
|
const url = data.images?.[0]?.originalUrl || data.images?.[0]?.thumbnailUrl;
|
|
patch.storyAssets = (draft.storyAssets || []).map((asset: any) => {
|
|
if (asset.id !== attachment.asset.id) return asset;
|
|
found = true;
|
|
if (
|
|
!url ||
|
|
["name", "description", "type", "imageUrl"].some(
|
|
(key) => asset[key] !== attachment.asset[key as keyof typeof attachment.asset],
|
|
)
|
|
) {
|
|
conflict = true;
|
|
return asset;
|
|
}
|
|
return { ...asset, imageUrl: url };
|
|
});
|
|
if (!found) conflict = true;
|
|
} else {
|
|
requireStoryPromptResult(data, attachment);
|
|
const byId = new Map(attachment.rows.map((row, index) => [row.id, { row, index }]));
|
|
let found = 0;
|
|
patch.rows = (draft.rows || []).map((row: any) => {
|
|
const expected = byId.get(row.id);
|
|
if (!expected) return row;
|
|
found++;
|
|
if (
|
|
Object.keys(expected.row).some(
|
|
(key) => JSON.stringify(row[key]) !== JSON.stringify(expected.row[key]),
|
|
)
|
|
) {
|
|
conflict = true;
|
|
return row;
|
|
}
|
|
const generated = data.analysisRows[expected.index];
|
|
return { ...row, imagePrompt: generated.imagePrompt, motionPrompt: generated.motionPrompt };
|
|
});
|
|
if (found !== attachment.rows.length) conflict = true;
|
|
}
|
|
return {
|
|
...draft,
|
|
...patch,
|
|
storyTaskResults: {
|
|
...draft.storyTaskResults,
|
|
[taskId]: {
|
|
status: conflict ? "conflict" : "applied",
|
|
message: conflict
|
|
? "生成期间内容有修改或删除,已保留原内容;新结果在画布的生成节点中。"
|
|
: "生成结果已同步到脚本。",
|
|
},
|
|
},
|
|
};
|
|
}
|