feat: initial testing version

are/tte
are 1 year ago
parent 42d8c5a040
commit 0958241589
No known key found for this signature in database
GPG Key ID: 8367A69658056EE3

@ -397,6 +397,7 @@ import { COLOR_PALETTE } from "../colors";
import { ElementCanvasButton } from "./MagicButton";
import { MagicIcon, copyIcon, fullscreenIcon } from "./icons";
import { EditorLocalStorage } from "../data/EditorLocalStorage";
import { TextToExcalidraw } from "./TextToExcalidraw/TextToExcalidraw";
const AppContext = React.createContext<AppClassProperties>(null!);
const AppPropsContext = React.createContext<AppProps>(null!);

@ -0,0 +1,589 @@
import { useEffect, useRef, useState } from "react";
import { t } from "../../i18n";
import { useApp } from "../App";
import { Dialog } from "../Dialog";
import { TextField } from "../TextField";
import Trans from "../Trans";
import {
CloseIcon,
RedoIcon,
ZoomInIcon,
ZoomOutIcon,
playerPlayIcon,
playerStopFilledIcon,
} from "../icons";
import { NonDeletedExcalidrawElement } from "../../element/types";
import { convertToExcalidrawElements } from "../../data/transform";
import { exportToCanvas } from "../../packages/utils";
import { DEFAULT_EXPORT_PADDING } from "../../constants";
import { canvasToBlob } from "../../data/blob";
const testResponse = `{
"error": false,
"data": [
{
"type": "ellipse",
"x": 200,
"y": 200,
"width": 100,
"height": 100,
"strokeColor": "transparent",
"backgroundColor": "yellow",
"strokeWidth": 2
},
{
"type": "line",
"x": 300,
"y": 250,
"points": [
[
0,
0
],
[
70,
0
]
],
"width": -70,
"height": 0,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 293.30127018922195,
"y": 275,
"points": [
[
0,
0
],
[
60.62177826491069,
35
]
],
"width": -60.62177826491069,
"height": -35,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 275,
"y": 293.30127018922195,
"points": [
[
0,
0
],
[
35,
60.62177826491069
]
],
"width": -35,
"height": -60.62177826491069,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 250,
"y": 300,
"points": [
[
0,
0
],
[
0,
70
]
],
"width": 0,
"height": -70,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 225,
"y": 293.30127018922195,
"points": [
[
0,
0
],
[
-34.99999999999997,
60.62177826491069
]
],
"width": -34.99999999999997,
"height": -60.62177826491069,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 206.69872981077805,
"y": 275,
"points": [
[
0,
0
],
[
-60.62177826491069,
35
]
],
"width": -60.62177826491069,
"height": -35,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 200,
"y": 250,
"points": [
[
0,
0
],
[
-70,
2.842170943040401e-14
]
],
"width": -70,
"height": -2.842170943040401e-14,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 206.69872981077805,
"y": 225,
"points": [
[
0,
0
],
[
-60.62177826491069,
-34.99999999999997
]
],
"width": -60.62177826491069,
"height": -34.99999999999997,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 224.99999999999997,
"y": 206.69872981077808,
"points": [
[
0,
0
],
[
-35.00000000000003,
-60.62177826491069
]
],
"width": -35.00000000000003,
"height": -60.62177826491069,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 250,
"y": 200,
"points": [
[
0,
0
],
[
-2.842170943040401e-14,
-70
]
],
"width": -2.842170943040401e-14,
"height": -70,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 275,
"y": 206.69872981077808,
"points": [
[
0,
0
],
[
35,
-60.621778264910716
]
],
"width": -35,
"height": -60.621778264910716,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
},
{
"type": "line",
"x": 293.3012701892219,
"y": 224.99999999999997,
"points": [
[
0,
0
],
[
60.621778264910745,
-35.00000000000003
]
],
"width": -60.621778264910745,
"height": -35.00000000000003,
"strokeColor": "yellow",
"backgroundColor": "transparent",
"strokeWidth": 5
}
]
}`;
async function fetchData(
prompt: string,
): Promise<readonly NonDeletedExcalidrawElement[]> {
const response = await fetch(
`http://localhost:3015/v1/ai/text-to-excalidraw/generate`,
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify({ prompt }),
},
);
const result = await response.json();
if (result.error) {
alert("Oops!");
return [];
}
return convertToExcalidrawElements(result.data);
}
export const TextToExcalidraw = () => {
const app = useApp();
const [prompt, setPrompt] = useState("");
const [isPanelOpen, setPanelOpen] = useState(false);
const [isLoading, setLoading] = useState(false);
const [data, setData] = useState<
readonly NonDeletedExcalidrawElement[] | null
>(null);
const [previewCanvas, setPreviewCanvas] = useState<HTMLCanvasElement | null>(
null,
);
const containerRef = useRef<HTMLDivElement>(null);
const onClose = () => {
app.setOpenDialog(null);
};
const onSubmit = async () => {
setPanelOpen(true);
setLoading(true);
const elements = await fetchData(prompt);
setData(elements);
const canvas = await exportToCanvas({
elements,
files: {},
exportPadding: DEFAULT_EXPORT_PADDING,
});
await canvasToBlob(canvas);
setPreviewCanvas(canvas);
setLoading(false);
};
const onInsert = async () => {
if (data) {
app.addElementsFromPasteOrLibrary({
elements: data,
files: {},
position: "center",
fitToContent: true,
});
onClose();
}
};
useEffect(() => {
if (containerRef.current && previewCanvas) {
containerRef.current.replaceChildren(previewCanvas);
}
}, [previewCanvas]);
// exportToCanvas([], {}, {}, {});
// exportToSvg([], {exportBackground}, {}, {})
return (
<div
style={{
position: "absolute",
top: "6.5rem",
pointerEvents: "auto",
width: "100%",
display: "flex",
flexDirection: "column",
gap: "0.75rem",
}}
>
<div
className="Island"
style={{
width: "100%",
display: "flex",
flexDirection: "row",
boxSizing: "border-box",
gap: "0.75rem",
alignItems: "center",
height: 48,
padding: "0.5rem",
}}
>
<input
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
type="text"
style={{
flexGrow: 1,
height: "100%",
boxSizing: "border-box",
border: 0,
outline: "none",
}}
placeholder="How can I help you today?"
/>
<button
style={{
cursor: "pointer",
height: "100%",
border: "none",
background: "white",
aspectRatio: "1/1",
padding: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<div
style={{ width: "1.25rem", height: "1.25rem", color: "#1B1B1F" }}
>
{CloseIcon}
</div>
</button>
<div
style={{ background: "#D6D6D6", width: 1, height: "1.5rem" }}
></div>
<button
style={{
cursor: "pointer",
height: "100%",
border: "none",
aspectRatio: "1/1",
padding: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#6965DB",
borderRadius: "0.5rem",
}}
onClick={onSubmit}
>
<div style={{ width: "1.25rem", height: "1.25rem", color: "white" }}>
{isLoading ? playerStopFilledIcon : playerPlayIcon}
</div>
</button>
</div>
{isPanelOpen && (
<div
className="Island"
style={{
width: "100%",
display: "flex",
flexDirection: "row",
height: 400,
boxSizing: "border-box",
}}
>
{isLoading ? (
"loading"
) : (
<div
style={{
width: "100%",
height: "100%",
display: "flex",
flexDirection: "column",
}}
>
<div
ref={containerRef}
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "100%",
height: "100%",
}}
/>
<div
style={{
borderTop: "1px solid #F0EFFF",
padding: "0.75rem",
display: "flex",
flexDirection: "row",
gap: "0.75rem",
}}
>
<button
style={{
cursor: "pointer",
width: 32,
height: "100%",
border: "none",
aspectRatio: "1/1",
padding: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5F5F9",
borderRadius: "0.5rem",
}}
>
<div
style={{
width: "1.25rem",
height: "1.25rem",
color: "#1B1B1F",
}}
>
{RedoIcon}
</div>
</button>
<div style={{ width: 32, height: "100%", display: "flex" }}>
<button
style={{
cursor: "pointer",
width: 32,
height: "100%",
border: "none",
aspectRatio: "1/1",
padding: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5F5F9",
borderRadius: "0.5rem 0 0 0.5rem",
}}
>
<div
style={{
width: "1.25rem",
height: "1.25rem",
color: "#1B1B1F",
}}
>
{ZoomOutIcon}
</div>
</button>
<button
style={{
cursor: "pointer",
width: 32,
height: "100%",
border: "none",
aspectRatio: "1/1",
padding: 0,
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5F5F9",
borderRadius: "0 0.5rem 0.5rem 0",
}}
>
<div
style={{
width: "1.25rem",
height: "1.25rem",
color: "#1B1B1F",
}}
>
{ZoomInIcon}
</div>
</button>
</div>
<div style={{ flexGrow: 1 }}></div>
<button
style={{
cursor: "pointer",
height: "100%",
border: "none",
padding: "0.5rem 1rem",
display: "flex",
justifyContent: "center",
alignItems: "center",
backgroundColor: "#6965DB",
borderRadius: "0.5rem",
color: "white",
}}
onClick={onInsert}
>
Insert into scene &gt;
</button>
</div>
</div>
)}
</div>
)}
</div>
);
};

@ -251,7 +251,8 @@
"hand": "Hand (panning tool)",
"extraTools": "More tools",
"mermaidToExcalidraw": "Mermaid to Excalidraw",
"magicSettings": "AI settings"
"magicSettings": "AI settings",
"textToExcalidraw": "Text to Excalidraw"
},
"headings": {
"canvasActions": "Canvas actions",
@ -517,5 +518,10 @@
"description": "Currently only <flowchartLink>Flowcharts</flowchartLink> and <sequenceLink>Sequence Diagrams</sequenceLink> are supported. The other types will be rendered as image in Excalidraw.",
"syntax": "Mermaid Syntax",
"preview": "Preview"
},
"textToExcalidraw": {
"title": "Text to Excalidraw",
"description": "Test",
"button": "Insert"
}
}

Loading…
Cancel
Save