Files
ttstd-infinite-canvas/web/src/pages/canvas/canvas-text-generation-executor.ts

91 lines
4.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { nanoid } from "nanoid";
import { NODE_DEFAULT_SIZE } from "@/constant/canvas";
import { getGenerationCount, runCanvasGenerationTaskToConsumer } from "@/lib/canvas/canvas-project-generation";
import { CanvasNodeType, type CanvasNodeData } from "@/types/canvas";
import type { CanvasGenerationExecution } from "./canvas-generation-executor-types";
const NODE_STATUS_LOADING = "loading" as const;
const NODE_STATUS_SUCCESS = "success" as const;
export async function executeTextGeneration({
nodeId,
sourceNode,
prompt,
effectivePrompt,
generationConfig,
generationContext,
controller,
editingTextNode,
projectId,
setNodes,
setConnections,
startGenerationRequest,
finishGenerationRequest,
bindGenerationTask,
applyGenerationTaskResult,
registerPendingNodeIds,
taskContext,
retryContext,
}: CanvasGenerationExecution) {
const isConfigNode = sourceNode?.type === CanvasNodeType.Config;
const isDirectTextTarget = sourceNode?.type === CanvasNodeType.Text && !sourceNode.metadata?.content?.trim() && !editingTextNode;
// 独立文本份数(textCount),默认 1,不再复用餐图片数量 count(对齐上游 v0.16 语义)
const textCount = getGenerationCount(String(sourceNode?.metadata?.textCount ?? 1));
const parentConfig = NODE_DEFAULT_SIZE[isConfigNode ? CanvasNodeType.Config : CanvasNodeType.Text];
const textConfig = NODE_DEFAULT_SIZE[CanvasNodeType.Text];
const parentPosition = sourceNode?.position || { x: 0, y: 0 };
const generateInPlace = !isConfigNode && !editingTextNode;
const childIds = Array.from({ length: generateInPlace ? Math.max(0, textCount - 1) : textCount }, () => nanoid());
registerPendingNodeIds(childIds);
if (childIds.length) {
const childNodes: CanvasNodeData[] = childIds.map((id, index) => ({
id,
type: CanvasNodeType.Text,
title: effectivePrompt.slice(0, 32) || "Generated Text",
position: {
x: parentPosition.x + parentConfig.width + 96,
y: parentPosition.y + parentConfig.height / 2 - textConfig.height / 2 + (index - (childIds.length - 1) / 2) * (textConfig.height + 36),
},
width: textConfig.width,
height: textConfig.height,
metadata: { prompt: effectivePrompt, status: NODE_STATUS_LOADING, fontSize: 14 },
}));
setNodes((current) => [...current.map((node) => (node.id === nodeId && isConfigNode ? { ...node, metadata: { ...node.metadata, prompt: effectivePrompt, status: NODE_STATUS_LOADING, errorDetails: undefined } } : node)), ...childNodes]);
setConnections((current) => [...current, ...childIds.map((childId) => ({ id: nanoid(), fromNodeId: nodeId, toNodeId: childId }))]);
}
const textTargetIds = generateInPlace ? [nodeId, ...childIds] : childIds;
textTargetIds.forEach((targetNodeId) => startGenerationRequest(targetNodeId, nodeId, nodeId, controller));
const answers = await Promise.all(
textTargetIds.map((targetNodeId) =>
runCanvasGenerationTaskToConsumer(
{
projectId,
nodeId: targetNodeId,
...retryContext,
mode: "text",
prompt: effectivePrompt,
config: generationConfig,
referenceImages: generationContext.referenceImages,
referenceVideos: generationContext.referenceVideos,
signal: controller.signal,
metadata: { sourceNodeId: nodeId, ...taskContext, resolvedCharacterVersions: generationContext.resolvedCharacterVersions },
},
{
bindTask: (task) => bindGenerationTask(targetNodeId, task),
consumeTask: (task) => applyGenerationTaskResult(targetNodeId, task),
},
)
.then(() => ({ nodeId: targetNodeId }))
.finally(() => finishGenerationRequest(targetNodeId, controller)),
),
);
if (controller.signal.aborted) return;
void answers;
if (isConfigNode) {
setNodes((current) => current.map((node) => (node.id === nodeId ? { ...node, metadata: { ...node.metadata, status: NODE_STATUS_SUCCESS, errorDetails: undefined, generationErrorCode: undefined, resourceReloadAvailable: undefined, failedPromptFingerprint: undefined } } : node)));
}
}