Files
lemonspace_app/components/canvas/canvas-generation-failures.ts
Matthias Meister ed08b976f9 feat(canvas): add video-prompt node and enhance video generation support
- Introduced a new node type "video-prompt" for AI video generation, including its integration into the canvas command palette and node template picker.
- Updated connection validation to allow connections from text nodes to video-prompt and from video-prompt to ai-video nodes.
- Enhanced error handling and messaging for video generation failures, including specific cases for provider issues.
- Added tests to validate new video-prompt functionality and connection policies.
- Updated localization files to include new labels and prompts for video-prompt and ai-video nodes.
2026-04-07 08:50:59 +02:00

72 lines
2.1 KiB
TypeScript

import { useEffect, useRef } from "react";
import { useTranslations } from "next-intl";
import type { Doc } from "@/convex/_generated/dataModel";
import { toast } from "@/lib/toast";
import {
GENERATION_FAILURE_THRESHOLD,
GENERATION_FAILURE_WINDOW_MS,
} from "./canvas-helpers";
export function useGenerationFailureWarnings(
t: ReturnType<typeof useTranslations<'toasts'>>,
convexNodes: Doc<"nodes">[] | undefined,
): void {
const recentGenerationFailureTimestampsRef = useRef<number[]>([]);
const previousNodeStatusRef = useRef<Map<string, string | undefined>>(new Map());
const hasInitializedGenerationFailureTrackingRef = useRef(false);
useEffect(() => {
if (!convexNodes) return;
const nextNodeStatusMap = new Map<string, string | undefined>();
let detectedGenerationFailures = 0;
for (const node of convexNodes) {
nextNodeStatusMap.set(node._id, node.status);
if (node.type !== "ai-image" && node.type !== "ai-video") {
continue;
}
const previousStatus = previousNodeStatusRef.current.get(node._id);
if (
hasInitializedGenerationFailureTrackingRef.current &&
node.status === "error" &&
previousStatus !== "error"
) {
detectedGenerationFailures += 1;
}
}
previousNodeStatusRef.current = nextNodeStatusMap;
if (!hasInitializedGenerationFailureTrackingRef.current) {
hasInitializedGenerationFailureTrackingRef.current = true;
return;
}
if (detectedGenerationFailures === 0) {
return;
}
const now = Date.now();
const recentFailures = recentGenerationFailureTimestampsRef.current.filter(
(timestamp) => now - timestamp <= GENERATION_FAILURE_WINDOW_MS,
);
for (let index = 0; index < detectedGenerationFailures; index += 1) {
recentFailures.push(now);
}
if (recentFailures.length >= GENERATION_FAILURE_THRESHOLD) {
toast.warning(t('ai.providerIssuesTitle'), t('ai.providerIssuesDesc'));
recentGenerationFailureTimestampsRef.current = [];
return;
}
recentGenerationFailureTimestampsRef.current = recentFailures;
}, [t, convexNodes]);
}