Save current image generation workspace

This commit is contained in:
2026-06-22 23:36:52 +08:00
parent d2a1968d53
commit 36e6bedf1a
62 changed files with 13107 additions and 6948 deletions
+92
View File
@@ -0,0 +1,92 @@
import type {
CanvasConnection,
CanvasImageNodeMetadata,
CanvasNode,
} from "@/lib/canvas/types";
export type PromptMentionSource = {
alias: string;
token: string;
nodeId: string;
label: string;
description: string;
imageUrl: string;
index: number;
};
const mentionUrlPrefix = "canvas-image://";
export function getPromptMentionSources(
nodes: CanvasNode[],
connections: CanvasConnection[],
promptNodeId: string,
) {
const imageById = new Map(
nodes
.filter((node) => node.type === "image")
.map((node) => [node.id, node] as const),
);
return connections
.filter((connection) => connection.toNodeId === promptNodeId)
.map((connection) => imageById.get(connection.fromNodeId))
.filter((node): node is CanvasNode => Boolean(node))
.map((node, index) => {
const metadata = node.metadata as CanvasImageNodeMetadata;
return {
alias: `@图${index + 1}`,
token: createPromptMentionToken(`${index + 1}`, node.id),
nodeId: node.id,
label: `${index + 1}`,
index: index + 1,
description:
metadata.prompt?.trim() || node.title.trim() || `已连接素材 ${index + 1}`,
imageUrl: metadata.imageUrl,
} satisfies PromptMentionSource;
})
.filter((item) => Boolean(item.imageUrl));
}
export function createPromptMentionToken(label: string, nodeId: string) {
return `[${label}](${mentionUrlPrefix}${nodeId})`;
}
export function parsePromptMentionUrl(value: string) {
return value.startsWith(mentionUrlPrefix)
? value.slice(mentionUrlPrefix.length)
: null;
}
export function resolvePromptMentions(
prompt: string,
mentions: PromptMentionSource[],
) {
const explicitlyReferencedNodeIds: string[] = [];
let resolvedPrompt = prompt;
for (const mention of mentions) {
const replacement = `${mention.label}(第 ${mention.index} 张输入参考图)`;
const usedMarkdownToken = resolvedPrompt.includes(mention.token);
const usedAlias = resolvedPrompt.includes(mention.alias);
if (!usedMarkdownToken && !usedAlias) continue;
explicitlyReferencedNodeIds.push(mention.nodeId);
resolvedPrompt = resolvedPrompt.split(mention.token).join(replacement);
resolvedPrompt = resolvedPrompt.split(mention.alias).join(replacement);
}
if (mentions.length > 0) {
const referenceGuide = mentions
.map(
(mention) =>
`${mention.label} = 第 ${mention.index} 张输入参考图:${mention.description}`,
)
.join("\n");
resolvedPrompt = `${resolvedPrompt.trim()}\n\n已连接参考图编号:\n${referenceGuide}`;
}
return {
prompt: resolvedPrompt.trim(),
referencedNodeIds: mentions.map((mention) => mention.nodeId),
explicitlyReferencedNodeIds,
};
}