feat(runtime): 即梦本机运行时 - 接入安全生成闭环与桌面本机渠道
Refs #225 Co-authored-by: zkhyww <127009345+zkhyww@users.noreply.github.com>
This commit is contained in:
1 parent
f549767cda
commit
914717cae6
179 files changed
+49746
-1897
No files matched your search
@@ -2,11 +2,9 @@ import { nanoid } from "nanoid";
|
||||
|
||||
import { NODE_DEFAULT_SIZE } from "@/constant/canvas";
|
||||
import { canGenerateImageInPlace, findAvailableGenerationGroupPosition, imageGenerationChildPosition, imageGenerationGroupSize } from "@/lib/canvas/canvas-generation-layout";
|
||||
import { imageMetadata } from "@/lib/canvas/canvas-generation-task-sync";
|
||||
import { fitNodeSize, nodeSizeFromRatio } from "@/lib/canvas/canvas-node-size";
|
||||
import { buildImageGenerationMetadata, getGenerationCount, isGenerationCanceled, limitCanvasImageReferences, runBackendCanvasGenerationTask } from "@/lib/canvas/canvas-project-generation";
|
||||
import { nodeSizeFromRatio } from "@/lib/canvas/canvas-node-size";
|
||||
import { buildImageGenerationMetadata, getGenerationCount, isGenerationCanceled, limitCanvasImageReferences, runCanvasGenerationTaskToConsumer } from "@/lib/canvas/canvas-project-generation";
|
||||
import { CONTENT_MODERATION_ERROR_CODE, generationFailureMetadata, type GenerationFailureMetadata } from "@/lib/generation-error";
|
||||
import { uploadImage } from "@/services/image-storage";
|
||||
import { CanvasNodeType, type CanvasNodeData } from "@/types/canvas";
|
||||
|
||||
import type { CanvasGenerationExecution } from "./canvas-generation-executor-types";
|
||||
@@ -34,7 +32,10 @@ export async function executeImageGeneration({
|
||||
startGenerationRequest,
|
||||
finishGenerationRequest,
|
||||
bindGenerationTask,
|
||||
applyGenerationTaskResult,
|
||||
styleMetadata,
|
||||
taskContext,
|
||||
retryContext,
|
||||
showError,
|
||||
registerPendingNodeIds,
|
||||
}: CanvasGenerationExecution) {
|
||||
@@ -54,7 +55,7 @@ export async function executeImageGeneration({
|
||||
const imageConfig = requestedImageSize || imageDefaults;
|
||||
// auto 图生图沿用来源节点尺寸;用户明确选择比例时必须以目标比例创建节点。
|
||||
const referenceNode = referenceImages.length === 1 ? canvasNodes.find((node) => node.id === referenceImages[0].id && node.type === CanvasNodeType.Image) : undefined;
|
||||
const imageSizeSource = requestedImageSize ? undefined : (isImageNode && sourceNode?.metadata?.content ? sourceNode : referenceNode);
|
||||
const imageSizeSource = requestedImageSize ? undefined : isImageNode && sourceNode?.metadata?.content ? sourceNode : referenceNode;
|
||||
const outputNodeSize = imageSizeSource ? { width: imageSizeSource.width, height: imageSizeSource.height } : imageConfig;
|
||||
const parentPosition = sourceNode?.position || { x: 0, y: 0 };
|
||||
const parentWidth = sourceNode?.width || parentConfig.width;
|
||||
@@ -100,7 +101,16 @@ export async function executeImageGeneration({
|
||||
position: imageGenerationChildPosition(rootNode.position, rootNode.width, outputNodeSize, index),
|
||||
width: outputNodeSize.width,
|
||||
height: outputNodeSize.height,
|
||||
metadata: { prompt: effectivePrompt, status: NODE_STATUS_LOADING, size: generationConfig.size, batchRootId: count > 1 && !directCopiedBatch ? rootId : undefined, ...generationMetadata, ...styleMetadata, generationErrorCode: undefined, failedPromptFingerprint: undefined },
|
||||
metadata: {
|
||||
prompt: effectivePrompt,
|
||||
status: NODE_STATUS_LOADING,
|
||||
size: generationConfig.size,
|
||||
batchRootId: count > 1 && !directCopiedBatch ? rootId : undefined,
|
||||
...generationMetadata,
|
||||
...styleMetadata,
|
||||
generationErrorCode: undefined,
|
||||
failedPromptFingerprint: undefined,
|
||||
},
|
||||
}));
|
||||
const batchConnections = directCopiedBatch
|
||||
? childIds.map((childId) => ({ id: nanoid(), fromNodeId: nodeId, toNodeId: childId }))
|
||||
@@ -139,32 +149,65 @@ export async function executeImageGeneration({
|
||||
await Promise.all(
|
||||
targetIds.map(async (targetId) => {
|
||||
try {
|
||||
const result = await runBackendCanvasGenerationTask({
|
||||
projectId,
|
||||
nodeId: targetId,
|
||||
mode: "image",
|
||||
prompt: effectivePrompt,
|
||||
config: { ...generationConfig, count: "1" },
|
||||
referenceImages,
|
||||
signal: controller.signal,
|
||||
metadata: { sourceNodeId: nodeId, resolvedCharacterVersions: generationContext.resolvedCharacterVersions, promptTemplateOperation: sourceNode?.metadata?.promptTemplateOperation, promptTemplateVariables: sourceNode?.metadata?.promptTemplateVariables, ...styleMetadata },
|
||||
onTaskCreated: (task) => bindGenerationTask(targetId, task),
|
||||
});
|
||||
const image = result.images?.[0];
|
||||
if (!image?.dataUrl) throw new Error("后端任务没有返回图片");
|
||||
const uploaded = await uploadImage(image.dataUrl);
|
||||
const imageSize = imageSizeSource ? outputNodeSize : fitNodeSize(uploaded.width, uploaded.height, outputNodeSize.width, outputNodeSize.height);
|
||||
setNodes((current) => {
|
||||
const root = directCopiedBatch ? undefined : current.find((node) => node.id === rootId);
|
||||
return current.map((node) => {
|
||||
if (node.id !== targetId && (!root || node.id !== rootId)) return node;
|
||||
const center = { x: node.position.x + node.width / 2, y: node.position.y + node.height / 2 };
|
||||
const geometry = node.metadata?.locked ? {} : { position: { x: center.x - imageSize.width / 2, y: center.y - imageSize.height / 2 }, width: imageSize.width, height: imageSize.height };
|
||||
if (node.id === rootId && (targetId === rootId || !root?.metadata?.primaryImageId)) return { ...node, ...geometry, metadata: { ...node.metadata, ...imageMetadata(uploaded), primaryImageId: targetId } };
|
||||
if (node.id === targetId) return { ...node, ...geometry, metadata: { ...node.metadata, ...imageMetadata(uploaded) } };
|
||||
return node;
|
||||
await runCanvasGenerationTaskToConsumer(
|
||||
{
|
||||
projectId,
|
||||
nodeId: targetId,
|
||||
...retryContext,
|
||||
mode: "image",
|
||||
prompt: effectivePrompt,
|
||||
config: { ...generationConfig, count: "1" },
|
||||
referenceImages,
|
||||
signal: controller.signal,
|
||||
metadata: {
|
||||
sourceNodeId: nodeId,
|
||||
...taskContext,
|
||||
resolvedCharacterVersions: generationContext.resolvedCharacterVersions,
|
||||
promptTemplateOperation: sourceNode?.metadata?.promptTemplateOperation,
|
||||
promptTemplateVariables: sourceNode?.metadata?.promptTemplateVariables,
|
||||
...styleMetadata,
|
||||
},
|
||||
},
|
||||
{
|
||||
bindTask: (task) => bindGenerationTask(targetId, task),
|
||||
consumeTask: (task) => applyGenerationTaskResult(targetId, task),
|
||||
},
|
||||
);
|
||||
if (targetId !== rootId && !directCopiedBatch) {
|
||||
setNodes((current) => {
|
||||
const child = current.find((node) => node.id === targetId);
|
||||
const root = current.find((node) => node.id === rootId);
|
||||
if (!child?.metadata?.content || !root || root.metadata?.primaryImageId) return current;
|
||||
const center = { x: root.position.x + root.width / 2, y: root.position.y + root.height / 2 };
|
||||
const geometry = root.metadata?.locked
|
||||
? {}
|
||||
: {
|
||||
width: child.width,
|
||||
height: child.height,
|
||||
position: { x: center.x - child.width / 2, y: center.y - child.height / 2 },
|
||||
};
|
||||
return current.map((node) =>
|
||||
node.id === rootId
|
||||
? {
|
||||
...node,
|
||||
...geometry,
|
||||
metadata: {
|
||||
...node.metadata,
|
||||
content: child.metadata?.content,
|
||||
storageKey: child.metadata?.storageKey,
|
||||
mimeType: child.metadata?.mimeType,
|
||||
bytes: child.metadata?.bytes,
|
||||
naturalWidth: child.metadata?.naturalWidth,
|
||||
naturalHeight: child.metadata?.naturalHeight,
|
||||
assetId: child.metadata?.assetId,
|
||||
primaryImageId: targetId,
|
||||
status: NODE_STATUS_SUCCESS,
|
||||
},
|
||||
}
|
||||
: node,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
hasSuccess = true;
|
||||
if (isConfigNode) setNodes((current) => current.map((node) => (node.id === nodeId ? { ...node, metadata: { ...node.metadata, status: NODE_STATUS_SUCCESS, errorDetails: undefined } } : node)));
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user