fix(canvas): 媒体提示词 - 统一 Agent 更新与画布生成读取生成合同
This commit is contained in:
@@ -22,7 +22,7 @@ import { getContextResourceNodes } from "@/lib/canvas/canvas-resource-references
|
||||
import { getPublicCanvasShare } from "@/services/api/canvas-share";
|
||||
import { useCanvasThemeStore, useCanvasThemeScope } from "@/stores/canvas/use-canvas-theme-store";
|
||||
import { CanvasNodeType, type CanvasNodeData, type Position, type ViewportTransform } from "@/types/canvas";
|
||||
|
||||
import { nodeGenerationPrompt } from "@/lib/canvas/generation-contract";
|
||||
type ContextMenu = { x: number; y: number; world: Position; nodeId?: string };
|
||||
type DragState = { primaryId: string; nodeIds: string[]; startX: number; startY: number; origins: Map<string, Position>; moved: boolean };
|
||||
|
||||
@@ -314,7 +314,7 @@ function SharedConfigNode({ node, onUnauthorized }: { node: CanvasNodeData; onUn
|
||||
const theme = canvasThemes[useCanvasThemeStore((state) => state.theme)];
|
||||
return <div className="flex h-full w-full flex-col overflow-hidden rounded-[var(--panel-radius)]">
|
||||
<div className="flex h-10 shrink-0 items-center gap-2 border-b px-4" style={{ background: theme.node.panel, borderColor: theme.node.stroke }}><ImageIcon className="size-4" /><span className="min-w-0 flex-1 truncate text-sm font-semibold">{node.title}</span></div>
|
||||
<div className="min-h-0 flex-1 whitespace-pre-wrap break-words p-4 text-sm leading-6" style={{ color: theme.node.muted }}>{node.metadata?.composerContent || node.metadata?.prompt || "未填写提示词"}</div>
|
||||
<div className="min-h-0 flex-1 whitespace-pre-wrap break-words p-4 text-sm leading-6" style={{ color: theme.node.muted }}>{nodeGenerationPrompt(node) || "未填写提示词"}</div>
|
||||
<div className="flex h-12 shrink-0 items-center justify-end border-t px-3" style={{ borderColor: theme.node.stroke }}><Button size="small" icon={<Send className="size-3.5" />} onMouseDown={(event) => event.stopPropagation()} onClick={(event) => { event.stopPropagation(); onUnauthorized(); }}>生成</Button></div>
|
||||
</div>;
|
||||
}
|
||||
@@ -325,6 +325,6 @@ function SharedScriptNode({ node, onUnauthorized }: { node: CanvasNodeData; onUn
|
||||
return <div className="flex h-full w-full flex-col overflow-hidden rounded-[var(--panel-radius)]">
|
||||
<div className="flex h-10 shrink-0 items-center gap-2 border-b px-4" style={{ background: theme.node.panel, borderColor: theme.node.stroke }}><Clapperboard className="size-4" /><span className="min-w-0 flex-1 truncate text-sm font-semibold">{node.title}</span><span className="text-xs" style={{ color: theme.node.muted }}>{rows.length} 镜</span><button type="button" className="grid size-7 place-items-center rounded hover:bg-black/5 dark:hover:bg-white/10" onMouseDown={(event) => event.stopPropagation()} onClick={(event) => { event.stopPropagation(); onUnauthorized(); }} aria-label="一键创建视频节点"><Video className="size-3.5" /></button></div>
|
||||
<div data-canvas-wheel-scroll className="min-h-0 flex-1 overflow-y-auto" onWheel={(event) => event.stopPropagation()}>{rows.length ? rows.map((row) => <div key={row.id} className="grid grid-cols-[52px_72px_minmax(180px,1fr)_minmax(150px,.8fr)] border-b text-xs leading-5" style={{ minHeight: 48, borderColor: theme.node.stroke }}><span className="grid place-items-center border-r" style={{ borderColor: theme.node.stroke, color: theme.node.muted }}>#{row.shotNumber}</span><span className="grid place-items-center border-r" style={{ borderColor: theme.node.stroke }}>{row.durationSeconds}s</span><span className="border-r px-3 py-2" style={{ borderColor: theme.node.stroke }}>{row.plotDescription || "-"}</span><span className="px-3 py-2" style={{ color: theme.node.muted }}>{row.dialogue || "-"}</span></div>) : <div className="grid h-full place-items-center text-sm" style={{ color: theme.node.muted }}>暂无分镜</div>}</div>
|
||||
{node.metadata?.composerContent ? <div className="max-h-24 shrink-0 overflow-y-auto border-t px-3 py-2 text-xs leading-5" style={{ borderColor: theme.node.stroke, color: theme.node.muted }}>{node.metadata.composerContent}</div> : null}
|
||||
{nodeGenerationPrompt(node) ? <div className="max-h-24 shrink-0 overflow-y-auto border-t px-3 py-2 text-xs leading-5" style={{ borderColor: theme.node.stroke, color: theme.node.muted }}>{nodeGenerationPrompt(node)}</div> : null}
|
||||
</div>;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { nanoid } from "nanoid";
|
||||
import { generationBatchStatus, isGenerationCostUncertainError } from "@/lib/canvas/canvas-generation-batch";
|
||||
import { buildGenerationConfig, createGenerationRetryContext, generationTaskMetadata, resetGenerationTaskMetadata } from "@/lib/canvas/canvas-project-generation";
|
||||
import { unchangedModeratedPrompt } from "@/lib/generation-error";
|
||||
import { nodeGenerationPrompt } from "@/lib/canvas/generation-contract";
|
||||
import { listGenerationTasks } from "@/services/api/task-center";
|
||||
import { useConfigStore, useEffectiveConfig } from "@/stores/use-config-store";
|
||||
import { useUserStore } from "@/stores/use-user-store";
|
||||
@@ -207,7 +208,7 @@ export function useCanvasGenerationBatches({ projectId, projectLoaded, nodes, no
|
||||
updateBatch(batch.sourceNodeId, batch.id, (current) => withUpdatedItem(current, item.id, { status: "failed", errorDetails: "生成模型未配置,请完成配置后重试" }));
|
||||
continue;
|
||||
}
|
||||
const prompt = (node.metadata?.composerContent || node.metadata?.prompt || "").trim();
|
||||
const prompt = nodeGenerationPrompt(node).trim();
|
||||
if (!prompt) {
|
||||
updateBatch(batch.sourceNodeId, batch.id, (current) => withUpdatedItem(current, item.id, { status: "failed", errorDetails: "生成提示词为空" }));
|
||||
continue;
|
||||
@@ -242,7 +243,7 @@ export function useCanvasGenerationBatches({ projectId, projectLoaded, nodes, no
|
||||
const nodeById = new Map(nodesRef.current.map((node) => [node.id, node]));
|
||||
const blockedItems = failedItems.filter((item) => {
|
||||
const node = nodeById.get(item.nodeId);
|
||||
return unchangedModeratedPrompt(node?.metadata, node?.metadata?.composerContent || node?.metadata?.prompt || "");
|
||||
return unchangedModeratedPrompt(node?.metadata, node ? nodeGenerationPrompt(node) : "");
|
||||
});
|
||||
const retryableItems = failedItems.filter((item) => !blockedItems.includes(item));
|
||||
if (blockedItems.length) message.warning(`${blockedItems.length} 个镜头未通过内容审核,请先修改提示词`);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useCallback, type Dispatch, type SetStateAction } from "react";
|
||||
import { App } from "antd";
|
||||
|
||||
import { buildNodeGenerationContext, hydrateNodeGenerationContext } from "@/components/canvas/canvas-node-generation";
|
||||
import { nodeGenerationPrompt } from "@/lib/canvas/generation-contract";
|
||||
import { producedModelCandidateForGeneration } from "@/lib/canvas/produced-model";
|
||||
import type { CanvasNodeGenerationMode } from "@/components/canvas/canvas-node-prompt-panel";
|
||||
import { buildEmotionImageArtifacts, emotionGenerationSize, emotionProviderMask, normalizeEmotionPromptForProvider, resolveEmotionEditPlan } from "@/lib/canvas/canvas-emotion";
|
||||
@@ -132,7 +133,7 @@ export function useCanvasGenerationRetry({
|
||||
return;
|
||||
}
|
||||
|
||||
const retryPromptSource = sourceNode.metadata?.composerContent || sourceNode.metadata?.prompt || node.metadata?.prompt || "";
|
||||
const retryPromptSource = nodeGenerationPrompt(sourceNode) || nodeGenerationPrompt(node);
|
||||
const retryContextPrompt = retryMode === "image" && sourceNode.metadata?.portraitTexture ? buildPortraitTexturePrompt(retryPromptSource, sourceNode.metadata.portraitTexture) : retryPromptSource;
|
||||
if (unchangedModeratedPrompt(node.metadata, retryPromptSource)) {
|
||||
message.warning("该提示词未通过内容审核,请先修改提示词再重新生成");
|
||||
|
||||
@@ -8,6 +8,7 @@ import { buildCanvasNodeMentionReferenceMap, buildCanvasResourceReferences, buil
|
||||
import { buildSkillMentionReferences } from "@/lib/canvas/canvas-skill-mentions";
|
||||
import { buildCanvasSpatialIndex, canvasNodeBounds, type CanvasSpatialIndex, type CanvasSpatialIndexEntry } from "@/lib/canvas/canvas-spatial-index";
|
||||
import { canvasOverviewMode, resolveCanvasNodeLOD, type CanvasNodeRenderLOD } from "@/lib/canvas/canvas-node-lod";
|
||||
import { nodeGenerationPrompt } from "@/lib/canvas/generation-contract";
|
||||
import { intersectsCanvasBounds, selectCanvasVisibleNodes } from "@/lib/canvas/canvas-node-visibility";
|
||||
import type { Skill } from "@/services/api/skills";
|
||||
import type { Asset, ImageAsset } from "@/stores/use-asset-store";
|
||||
@@ -410,7 +411,7 @@ export function useCanvasRenderModel({
|
||||
const toolMentionReferencesByNodeId = useMemo(() => {
|
||||
const map = new Map<string, ReturnType<typeof buildToolMentionReference>[]>();
|
||||
for (const node of semanticNodes) {
|
||||
const text = node.metadata?.composerContent ?? node.metadata?.prompt ?? "";
|
||||
const text = nodeGenerationPrompt(node);
|
||||
const tokens = parseToolMentionTokens(text);
|
||||
if (!tokens.length) continue;
|
||||
const seen = new Set<string>();
|
||||
|
||||
Reference in New Issue
Block a user