You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
4.8 KiB
TypeScript
160 lines
4.8 KiB
TypeScript
import type { ExcalidrawImperativeAPI } from "../../packages/excalidraw/types";
|
|
import {
|
|
DiagramToCodePlugin,
|
|
exportToBlob,
|
|
getTextFromElements,
|
|
MIME_TYPES,
|
|
TTDDialog,
|
|
} from "../../packages/excalidraw";
|
|
import { getDataURL } from "../../packages/excalidraw/data/blob";
|
|
import { safelyParseJSON } from "../../packages/excalidraw/utils";
|
|
|
|
export const AIComponents = ({
|
|
excalidrawAPI,
|
|
}: {
|
|
excalidrawAPI: ExcalidrawImperativeAPI;
|
|
}) => {
|
|
return (
|
|
<>
|
|
<DiagramToCodePlugin
|
|
generate={async ({ frame, children }) => {
|
|
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: `<html>
|
|
<body style="margin: 0; text-align: center">
|
|
<div style="display: flex; align-items: center; justify-content: center; flex-direction: column; height: 100vh; padding: 0 60px">
|
|
<div style="color:red">Too many requests today,</br>please try again tomorrow!</div>
|
|
</br>
|
|
</br>
|
|
<div>You can also try <a href="${
|
|
import.meta.env.VITE_APP_PLUS_LP
|
|
}/plus?utm_source=excalidraw&utm_medium=app&utm_content=d2c" target="_blank" rel="noreferrer noopener">Excalidraw+</a> to get more requests.</div>
|
|
</div>
|
|
</body>
|
|
</html>`,
|
|
};
|
|
}
|
|
|
|
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)");
|
|
}
|
|
}}
|
|
/>
|
|
|
|
<TTDDialog
|
|
onTextSubmit={async (input) => {
|
|
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");
|
|
}
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
};
|