Files
ttstd-infinite-canvas/web/src/lib/canvas/canvas-image-batch-retry.ts

88 lines
4.2 KiB
TypeScript

import { CanvasNodeType, type CanvasNodeData, type CanvasNodeMetadata } from "@/types/canvas";
export function failedImageBatchChildren(root: CanvasNodeData, nodes: CanvasNodeData[]) {
if (root.type !== CanvasNodeType.Image || !root.metadata?.isBatchRoot) return [];
const nodeById = new Map(nodes.map((node) => [node.id, node]));
return (root.metadata.batchChildIds || [])
.map((id) => nodeById.get(id))
.filter((node): node is CanvasNodeData => Boolean(node && node.type === CanvasNodeType.Image && node.metadata?.batchRootId === root.id && node.metadata.status === "error"));
}
export function markImageBatchRetrying(rootId: string, childIds: string[], nodes: CanvasNodeData[]): CanvasNodeData[] {
const retryingIds = new Set(childIds);
return nodes.map((node) => {
if (node.id !== rootId && !retryingIds.has(node.id)) return node;
return {
...node,
metadata: {
...node.metadata,
status: "loading",
...(node.id === rootId ? { batchFailedCount: childIds.length } : {}),
errorDetails: undefined,
generationErrorCode: undefined,
resourceReloadAvailable: undefined,
failedPromptFingerprint: undefined,
},
};
});
}
export function restoreUnsubmittedImageBatchChild(current: CanvasNodeData, original: CanvasNodeData): CanvasNodeData {
if (current.metadata?.status !== "loading") return current;
return {
...current,
metadata: {
...current.metadata,
status: "error",
errorDetails: original.metadata?.errorDetails || "重试请求未提交",
generationErrorCode: original.metadata?.generationErrorCode,
resourceReloadAvailable: original.metadata?.resourceReloadAvailable,
failedPromptFingerprint: original.metadata?.failedPromptFingerprint,
},
};
}
export function reconcileImageBatchRoot(root: CanvasNodeData, nodes: CanvasNodeData[]) {
if (root.type !== CanvasNodeType.Image || !root.metadata?.isBatchRoot) return root;
const nodeById = new Map(nodes.map((node) => [node.id, node]));
const children = (root.metadata.batchChildIds || [])
.map((id) => nodeById.get(id))
.filter((node): node is CanvasNodeData => Boolean(node && node.type === CanvasNodeType.Image && node.metadata?.batchRootId === root.id));
if (!children.length) return root;
const primary = children.find((node) => node.id === root.metadata?.primaryImageId && node.metadata?.content) || children.find((node) => node.metadata?.content);
const loading = children.some((node) => node.metadata?.status === "loading");
const failed = children.find((node) => node.metadata?.status === "error");
const metadata: CanvasNodeMetadata = { ...root.metadata };
metadata.batchFailedCount = children.filter((node) => node.metadata?.status === "error").length;
if (primary) {
metadata.content = primary.metadata?.content;
metadata.storageKey = primary.metadata?.storageKey;
metadata.mimeType = primary.metadata?.mimeType;
metadata.bytes = primary.metadata?.bytes;
metadata.naturalWidth = primary.metadata?.naturalWidth;
metadata.naturalHeight = primary.metadata?.naturalHeight;
metadata.primaryImageId = primary.id;
metadata.status = "success";
delete metadata.errorDetails;
delete metadata.generationErrorCode;
delete metadata.failedPromptFingerprint;
} else {
delete metadata.content;
delete metadata.storageKey;
delete metadata.mimeType;
delete metadata.bytes;
delete metadata.naturalWidth;
delete metadata.naturalHeight;
delete metadata.primaryImageId;
metadata.status = loading ? "loading" : failed ? "error" : "idle";
metadata.errorDetails = failed?.metadata?.errorDetails;
metadata.generationErrorCode = failed?.metadata?.generationErrorCode;
metadata.resourceReloadAvailable = failed?.metadata?.resourceReloadAvailable;
metadata.failedPromptFingerprint = failed?.metadata?.failedPromptFingerprint;
}
return { ...root, metadata };
}