From bfc2cec7d43eb8eaa46dd3f91084932381257059 Mon Sep 17 00:00:00 2001 From: kj_sh604 Date: Sun, 15 Mar 2026 16:19:35 -0400 Subject: refactor: excalidraw-app/ --- excalidraw-app/components/AI.tsx | 159 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 excalidraw-app/components/AI.tsx (limited to 'excalidraw-app/components/AI.tsx') diff --git a/excalidraw-app/components/AI.tsx b/excalidraw-app/components/AI.tsx new file mode 100644 index 0000000..ba13849 --- /dev/null +++ b/excalidraw-app/components/AI.tsx @@ -0,0 +1,159 @@ +import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types"; +import { + DiagramToCodePlugin, + exportToBlob, + getTextFromElements, + MIME_TYPES, + TTDDialog, +} from "@excalidraw/excalidraw"; +import { getDataURL } from "@excalidraw/excalidraw/data/blob"; +import { safelyParseJSON } from "@excalidraw/excalidraw/utils"; + +export const AIComponents = ({ + excalidrawAPI, +}: { + excalidrawAPI: ExcalidrawImperativeAPI; +}) => { + return ( + <> + { + const appState = excalidrawAPI.getAppState(); + + const blob = await exportToBlob({ + elements: children, + appState: { + ...appState, + exportBackground: true, + viewBackgroundColor: appState.viewBackgroundColor, + }, + exportingFrame: frame, + files: excalidrawAPI.getFiles(), + mimeType: MIME_TYPES.jpg, + }); + + const dataURL = await getDataURL(blob); + + const textFromFrameChildren = getTextFromElements(children); + + const response = await fetch( + `${ + import.meta.env.VITE_APP_AI_BACKEND + }/v1/ai/diagram-to-code/generate`, + { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + body: JSON.stringify({ + texts: textFromFrameChildren, + image: dataURL, + theme: appState.theme, + }), + }, + ); + + if (!response.ok) { + const text = await response.text(); + const errorJSON = safelyParseJSON(text); + + if (!errorJSON) { + throw new Error(text); + } + + if (errorJSON.statusCode === 429) { + return { + html: ` + +
+
Too many requests today,
please try again tomorrow!
+
+
+
You can also try kj-diagramming cloud to get more requests.
+
+ + `, + }; + } + + throw new Error(errorJSON.message || text); + } + + try { + const { html } = await response.json(); + + if (!html) { + throw new Error("Generation failed (invalid response)"); + } + return { + html, + }; + } catch (error: any) { + throw new Error("Generation failed (invalid response)"); + } + }} + /> + + { + try { + const response = await fetch( + `${ + import.meta.env.VITE_APP_AI_BACKEND + }/v1/ai/text-to-diagram/generate`, + { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + body: JSON.stringify({ prompt: input }), + }, + ); + + const rateLimit = response.headers.has("X-Ratelimit-Limit") + ? parseInt(response.headers.get("X-Ratelimit-Limit") || "0", 10) + : undefined; + + const rateLimitRemaining = response.headers.has( + "X-Ratelimit-Remaining", + ) + ? parseInt( + response.headers.get("X-Ratelimit-Remaining") || "0", + 10, + ) + : undefined; + + const json = await response.json(); + + if (!response.ok) { + if (response.status === 429) { + return { + rateLimit, + rateLimitRemaining, + error: new Error( + "Too many requests today, please try again tomorrow!", + ), + }; + } + + throw new Error(json.message || "Generation failed..."); + } + + const generatedResponse = json.generatedResponse; + if (!generatedResponse) { + throw new Error("Generation failed..."); + } + + return { generatedResponse, rateLimit, rateLimitRemaining }; + } catch (err: any) { + throw new Error("Request failed"); + } + }} + /> + + ); +}; -- cgit v1.2.3