fix(canvas): 画布引用 - 统一角色与图片编号并保持生成资源顺序
This commit is contained in:
@@ -20,7 +20,7 @@ export type CharacterBreakdown = {
|
||||
|
||||
export function normalizeCharacterImageMentions(prompt: string, imageCount: number, characterLabels: string[]) {
|
||||
if (imageCount > 0 || !characterLabels.length) return prompt;
|
||||
return prompt.replace(/@图片([1-9]\d*)(?=$|\s|[,.!?;:,。!?;:、)\]}】)])/g, (token, index: string) => {
|
||||
return prompt.replace(/@图片([1-9]\d*)(?![0-9])/g, (token, index: string) => {
|
||||
const label = characterLabels[Number(index) - 1];
|
||||
return label ? "@" + label : token;
|
||||
});
|
||||
|
||||
11
web/src/lib/canvas/canvas-reference-slots.ts
Normal file
11
web/src/lib/canvas/canvas-reference-slots.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export type CanvasReferenceLabelKind = "image" | "character" | "drawing" | "video" | "audio" | "text" | "skill" | "tool";
|
||||
|
||||
/** 图片、角色主图和绘图共享图片数组的位置;保留类型前缀供编辑器识别。 */
|
||||
export function createCanvasReferenceLabeler() {
|
||||
const counts: Record<CanvasReferenceLabelKind, number> = { image: 0, character: 0, drawing: 0, video: 0, audio: 0, text: 0, skill: 0, tool: 0 };
|
||||
const prefixes: Record<CanvasReferenceLabelKind, string> = { image: "图片", character: "角色", drawing: "绘图", video: "视频", audio: "音频", text: "文本", skill: "技能", tool: "工具" };
|
||||
return (kind: CanvasReferenceLabelKind) => {
|
||||
const counter = kind === "character" || kind === "drawing" ? "image" : kind;
|
||||
return `${prefixes[kind]}${++counts[counter]}`;
|
||||
};
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import { imageReferenceLabel } from "@/lib/image-reference-prompt";
|
||||
import { createCanvasReferenceLabeler } from "@/lib/canvas/canvas-reference-slots";
|
||||
import { normalizeCharacterImageMentions } from "@/lib/canvas/canvas-character-reference";
|
||||
import { canvasNodeVideoPreviewUrl, canvasVideoAssetPreviewUrl } from "@/lib/canvas/canvas-media-preview";
|
||||
import { nodeGenerationPrompt } from "@/lib/canvas/generation-contract";
|
||||
import { writeCanvasNodePrompt } from "@/lib/canvas/canvas-node-prompt";
|
||||
import { getNodeResourceKind } from "@/lib/canvas/node-registry";
|
||||
import { seedanceReferenceLabel } from "@/lib/seedance-video";
|
||||
import type { Skill } from "@/services/api/skills";
|
||||
import type { Asset, AssetCategory } from "@/stores/use-asset-store";
|
||||
import { CanvasNodeType, type CanvasConnection, type CanvasNodeData, type CanvasNodeTypeId } from "@/types/canvas";
|
||||
@@ -292,7 +291,7 @@ export function replaceCanvasMentionToken(value: string, token: string, replacem
|
||||
if (!token) return value;
|
||||
const escapedToken = token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
// Numbered media mentions can touch Chinese prose or another mention, but not a longer number.
|
||||
const boundary = /^@(图片|视频|音频|文本)\d+$/.test(token)
|
||||
const boundary = /^@(图片|角色|绘图|视频|音频|文本)\d+$/.test(token)
|
||||
? "(?![0-9])"
|
||||
: token.startsWith("@[node:") ? "" : `(?=${CANVAS_RESOURCE_MENTION_BOUNDARY.source})`;
|
||||
return value.replace(new RegExp(`${escapedToken}${boundary}`, "gu"), replacement);
|
||||
@@ -525,13 +524,11 @@ export function reorderCanvasResourceConnections(targetNodeId: string, orderedNo
|
||||
}
|
||||
|
||||
function labelResourceNodes(nodes: CanvasNodeData[], active: boolean) {
|
||||
const counts: Record<CanvasResourceKind, number> = { image: 0, video: 0, audio: 0, text: 0, skill: 0, character: 0, tool: 0 };
|
||||
let drawingCount = 0;
|
||||
const nextLabel = createCanvasReferenceLabeler();
|
||||
return nodes.flatMap((node): CanvasResourceReference[] => {
|
||||
const kind = resourceKind(node);
|
||||
if (!kind) return [];
|
||||
const index = node.type === CanvasNodeType.Drawing ? drawingCount++ : counts[kind]++;
|
||||
const label = node.type === CanvasNodeType.Drawing ? `绘图${index + 1}` : labelForKind(kind, index);
|
||||
const label = nextLabel(node.type === CanvasNodeType.Drawing ? "drawing" : kind);
|
||||
return [
|
||||
{
|
||||
id: node.id,
|
||||
@@ -558,16 +555,6 @@ function labelResourceNodes(nodes: CanvasNodeData[], active: boolean) {
|
||||
});
|
||||
}
|
||||
|
||||
function labelForKind(kind: CanvasResourceKind, index: number) {
|
||||
if (kind === "character") return `角色${index + 1}`;
|
||||
if (kind === "image") return imageReferenceLabel(index);
|
||||
if (kind === "video") return seedanceReferenceLabel("video", index);
|
||||
if (kind === "audio") return seedanceReferenceLabel("audio", index);
|
||||
if (kind === "skill") return `技能${index + 1}`;
|
||||
if (kind === "tool") return `工具${index + 1}`;
|
||||
return `文本${index + 1}`;
|
||||
}
|
||||
|
||||
function isResourceNode(node: CanvasNodeData) {
|
||||
return Boolean(resourceKind(node));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user