From 8a797eb93a85ebce0106fc103c4f4c572786bad0 Mon Sep 17 00:00:00 2001 From: tsuf239 <39455181+tsuf239@users.noreply.github.com> Date: Tue, 20 Feb 2024 16:02:13 +0200 Subject: [PATCH 1/5] add ai --- apps/playground/src/AiInput.tsx | 69 +++++++++++++++++++++++++++++++++ apps/playground/src/Editor.tsx | 11 ++++-- 2 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 apps/playground/src/AiInput.tsx diff --git a/apps/playground/src/AiInput.tsx b/apps/playground/src/AiInput.tsx new file mode 100644 index 00000000..83ab920b --- /dev/null +++ b/apps/playground/src/AiInput.tsx @@ -0,0 +1,69 @@ +import { useState } from "react"; + +const Input = (props: { + value: string; + onChange: (e: React.ChangeEvent) => void; + placeholder: string; +}) => ( + +); + +const Button = (props: { + onClick: (e: React.MouseEvent) => void; + children: any; +}) => ( + +); + +export const AiInput = ({ + onAiAnswer, +}: { + onAiAnswer: (prompt: string) => void; +}) => { + const [prompt, setPrompt] = useState(""); + const [isLoading, setLoading] = useState(false); + + const askAi = async () => { + setLoading(true); + const res = await fetch( + "https://la2mf9ioh9.execute-api.us-east-1.amazonaws.com/prod/ai", + { + method: "POST", + body: prompt, + headers: { + "Access-Control-Allow-Origin": "http://localhost:5173", + "Access-Control-Allow-Credentials": "true", + }, + }, + ); + if (res.ok) { + const answer = await res.text(); + onAiAnswer(answer.replace(/```wing/g, "").replace(/```/g, "")); + } + setLoading(false); + setPrompt(""); + }; + + return ( +
+ ) => + setPrompt(e.target.value) + } + placeholder="What cloud infrastructure would you like to build today?" + /> + + {isLoading &&

Loading...

} +
+ ); +}; diff --git a/apps/playground/src/Editor.tsx b/apps/playground/src/Editor.tsx index 286ce5ca..32167a23 100644 --- a/apps/playground/src/Editor.tsx +++ b/apps/playground/src/Editor.tsx @@ -62,7 +62,8 @@ import { Header } from "./Header"; import { useTimeout } from "usehooks-ts"; import { TooSlowAlert } from "@wing-playground/shared/src/alerts/TooSlow"; import { ServerErrorAlert } from "@wing-playground/shared/src/alerts/ServerError"; -import {ServerDown} from "@wing-playground/shared/src/alerts/ServerDown"; +import { ServerDown } from "@wing-playground/shared/src/alerts/ServerDown"; +import { AiInput } from "./AiInput"; const wingPackageJson = await import( "@winglang/compiler/package.json?raw" @@ -222,6 +223,10 @@ export const ReactMonacoEditor: React.FC = ({}) => { } }, [languageContext]); + const setEditorValue = (code: string) => { + editorRef.current?.setValue(code); + }; + const simulatorTarget: TargetView = useMemo(() => { return { id: "simulator", @@ -264,7 +269,7 @@ export const ReactMonacoEditor: React.FC = ({}) => { const getAlert = () => { if (IS_SERVER_DOWN) { - return ServerDown; + return ServerDown; } if (tooSlow) { return TooSlowAlert; @@ -340,7 +345,7 @@ export const ReactMonacoEditor: React.FC = ({}) => { - + Date: Wed, 21 Feb 2024 17:45:56 +0200 Subject: [PATCH 2/5] adding conversations --- apps/playground/package.json | 1 + apps/playground/src/AiInput.tsx | 91 ++++++++++++++++++++++++++++----- package-lock.json | 15 ++++++ 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/apps/playground/package.json b/apps/playground/package.json index 22cf4e5b..fe5fabdd 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -39,6 +39,7 @@ "semantic-ui-css": "^2.5.0", "semantic-ui-react": "^2.1.4", "tar": "^6.1.13", + "uuidv4": "^6.2.13", "vite-plugin-externals": "^0.6.2", "vite-plugin-node-polyfills": "^0.7.0", "vscode-json-languageservice": "^5.3.2", diff --git a/apps/playground/src/AiInput.tsx b/apps/playground/src/AiInput.tsx index 83ab920b..78284f0b 100644 --- a/apps/playground/src/AiInput.tsx +++ b/apps/playground/src/AiInput.tsx @@ -1,4 +1,39 @@ -import { useState } from "react"; +import { uuid } from "uuidv4"; +import { useEffect, useState } from "react"; + +const AiIcon = ({ className = "" }: { className: string }) => ( + + + +); + +const FixIcon = ({ className = "" }: { className: string }) => ( + + + +); const Input = (props: { value: string; @@ -7,7 +42,7 @@ const Input = (props: { }) => ( ); @@ -18,7 +53,7 @@ const Button = (props: { @@ -32,6 +67,12 @@ export const AiInput = ({ const [prompt, setPrompt] = useState(""); const [isLoading, setLoading] = useState(false); + useEffect(() => { + if (sessionStorage.getItem("conversation-id") === null) { + sessionStorage.setItem("conversation-id", uuid()); + } + }, []); + const askAi = async () => { setLoading(true); const res = await fetch( @@ -40,6 +81,7 @@ export const AiInput = ({ method: "POST", body: prompt, headers: { + "conversation-id": sessionStorage.getItem("conversation-id")!, "Access-Control-Allow-Origin": "http://localhost:5173", "Access-Control-Allow-Credentials": "true", }, @@ -53,17 +95,40 @@ export const AiInput = ({ setPrompt(""); }; + const restart = () => { + sessionStorage.setItem("conversation-id", uuid()); + + setPrompt(""); + onAiAnswer( + "// Write something down to get started, or use the examples above...", + ); + }; + return ( -
- ) => - setPrompt(e.target.value) - } - placeholder="What cloud infrastructure would you like to build today?" - /> - - {isLoading &&

Loading...

} +
+
+

Use wingAi

+ +
+ +
+
+ +
+ + ) => + setPrompt(e.target.value) + } + placeholder="Or ask me to build something new..." + /> + + + {isLoading &&

Loading...

} +
); }; diff --git a/package-lock.json b/package-lock.json index 8a4f8234..026d293d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -87,6 +87,7 @@ "semantic-ui-css": "^2.5.0", "semantic-ui-react": "^2.1.4", "tar": "^6.1.13", + "uuidv4": "^6.2.13", "vite-plugin-externals": "^0.6.2", "vite-plugin-node-polyfills": "^0.7.0", "vscode-json-languageservice": "^5.3.2", @@ -6624,6 +6625,11 @@ "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==", "dev": true }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" + }, "node_modules/@types/yargs": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", @@ -29098,6 +29104,15 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/uuidv4": { + "version": "6.2.13", + "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.2.13.tgz", + "integrity": "sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ==", + "dependencies": { + "@types/uuid": "8.3.4", + "uuid": "8.3.2" + } + }, "node_modules/uvu": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", From 55732d78e70141379411ff46854df8922f0a4459 Mon Sep 17 00:00:00 2001 From: tsuf239 <39455181+tsuf239@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:52:52 +0200 Subject: [PATCH 3/5] add fix code --- apps/playground/src/AiInput.tsx | 134 ------------------------------- apps/playground/src/Editor.tsx | 7 +- apps/playground/src/ai/ctas.tsx | 23 ++++++ apps/playground/src/ai/icons.tsx | 33 ++++++++ apps/playground/src/ai/index.tsx | 112 ++++++++++++++++++++++++++ apps/playground/tsconfig.json | 2 +- 6 files changed, 174 insertions(+), 137 deletions(-) delete mode 100644 apps/playground/src/AiInput.tsx create mode 100644 apps/playground/src/ai/ctas.tsx create mode 100644 apps/playground/src/ai/icons.tsx create mode 100644 apps/playground/src/ai/index.tsx diff --git a/apps/playground/src/AiInput.tsx b/apps/playground/src/AiInput.tsx deleted file mode 100644 index 78284f0b..00000000 --- a/apps/playground/src/AiInput.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { uuid } from "uuidv4"; -import { useEffect, useState } from "react"; - -const AiIcon = ({ className = "" }: { className: string }) => ( - - - -); - -const FixIcon = ({ className = "" }: { className: string }) => ( - - - -); - -const Input = (props: { - value: string; - onChange: (e: React.ChangeEvent) => void; - placeholder: string; -}) => ( - -); - -const Button = (props: { - onClick: (e: React.MouseEvent) => void; - children: any; -}) => ( - -); - -export const AiInput = ({ - onAiAnswer, -}: { - onAiAnswer: (prompt: string) => void; -}) => { - const [prompt, setPrompt] = useState(""); - const [isLoading, setLoading] = useState(false); - - useEffect(() => { - if (sessionStorage.getItem("conversation-id") === null) { - sessionStorage.setItem("conversation-id", uuid()); - } - }, []); - - const askAi = async () => { - setLoading(true); - const res = await fetch( - "https://la2mf9ioh9.execute-api.us-east-1.amazonaws.com/prod/ai", - { - method: "POST", - body: prompt, - headers: { - "conversation-id": sessionStorage.getItem("conversation-id")!, - "Access-Control-Allow-Origin": "http://localhost:5173", - "Access-Control-Allow-Credentials": "true", - }, - }, - ); - if (res.ok) { - const answer = await res.text(); - onAiAnswer(answer.replace(/```wing/g, "").replace(/```/g, "")); - } - setLoading(false); - setPrompt(""); - }; - - const restart = () => { - sessionStorage.setItem("conversation-id", uuid()); - - setPrompt(""); - onAiAnswer( - "// Write something down to get started, or use the examples above...", - ); - }; - - return ( -
-
-

Use wingAi

- -
- -
-
- -
- - ) => - setPrompt(e.target.value) - } - placeholder="Or ask me to build something new..." - /> - - - {isLoading &&

Loading...

} -
-
- ); -}; diff --git a/apps/playground/src/Editor.tsx b/apps/playground/src/Editor.tsx index 32167a23..d8eee523 100644 --- a/apps/playground/src/Editor.tsx +++ b/apps/playground/src/Editor.tsx @@ -63,7 +63,7 @@ import { useTimeout } from "usehooks-ts"; import { TooSlowAlert } from "@wing-playground/shared/src/alerts/TooSlow"; import { ServerErrorAlert } from "@wing-playground/shared/src/alerts/ServerError"; import { ServerDown } from "@wing-playground/shared/src/alerts/ServerDown"; -import { AiInput } from "./AiInput"; +import { AiInput } from "./ai"; const wingPackageJson = await import( "@winglang/compiler/package.json?raw" @@ -345,7 +345,10 @@ export const ReactMonacoEditor: React.FC = ({}) => {
- + ) => void; + placeholder: string; +}) => ( + +); + +export const Button = (props: { + onClick: (e: React.MouseEvent) => void; + children: any; +}) => ( + +); diff --git a/apps/playground/src/ai/icons.tsx b/apps/playground/src/ai/icons.tsx new file mode 100644 index 00000000..9facb564 --- /dev/null +++ b/apps/playground/src/ai/icons.tsx @@ -0,0 +1,33 @@ +export const AiIcon = ({ className = "" }: { className?: string }) => ( + + + +); + +export const FixIcon = ({ className = "" }: { className?: string }) => ( + + + +); diff --git a/apps/playground/src/ai/index.tsx b/apps/playground/src/ai/index.tsx new file mode 100644 index 00000000..f4a16cdb --- /dev/null +++ b/apps/playground/src/ai/index.tsx @@ -0,0 +1,112 @@ +import { uuid } from "uuidv4"; +import { useEffect, useState } from "react"; +import { AiIcon, FixIcon } from "./icons"; +import { Button, Input } from "./ctas"; + +const formatCode = (code: string) => { + let isCode = false; + return code.split("\n").reduce((acc, line) => { + if (line.includes("```")) { + isCode = !isCode; + + const newLine = line.replace(/```wing/g, "").replace(/```/g, ""); + return acc ? [acc, newLine].join("\n") : newLine; + } + const nextLine = isCode ? line : `// ${line}`; + return acc ? [acc, nextLine].join("\n") : nextLine; + }, ""); +}; + +const AI_API_URL = + "https://t4iblpvvr4.execute-api.us-east-1.amazonaws.com/prod"; + +export const AiInput = ({ + onAiAnswer, + code = "", +}: { + onAiAnswer: (prompt: string) => void; + code?: string; +}) => { + const [prompt, setPrompt] = useState(""); + const [isLoading, setLoading] = useState(false); + + useEffect(() => { + if (sessionStorage.getItem("conversation-id") === null) { + sessionStorage.setItem("conversation-id", uuid()); + } + }, []); + + const askAi = async () => { + setLoading(true); + const res = await fetch(`${AI_API_URL}/ai`, { + method: "POST", + body: JSON.stringify({ prompt, code }), + headers: { + "conversation-id": sessionStorage.getItem("conversation-id")!, + "Access-Control-Allow-Origin": "http://localhost:5173", + "Access-Control-Allow-Credentials": "true", + }, + }); + if (res.ok) { + onAiAnswer(formatCode(await res.text())); + } + setLoading(false); + setPrompt(""); + }; + + const fixCode = async () => { + setLoading(true); + const res = await fetch(`${AI_API_URL}/fix-code`, { + method: "POST", + body: JSON.stringify({ code }), + headers: { + "conversation-id": sessionStorage.getItem("conversation-id")!, + "Access-Control-Allow-Origin": "http://localhost:5173", + "Access-Control-Allow-Credentials": "true", + }, + }); + if (res.ok) { + onAiAnswer(formatCode(await res.text())); + } + setLoading(false); + }; + + const restart = () => { + sessionStorage.setItem("conversation-id", uuid()); + + setPrompt(""); + onAiAnswer( + "// Write something down to get started, or use the examples above...", + ); + }; + + return ( +
+
+

+ Use wingAi +

+ +
+ +
+
+ +
+ + ) => + setPrompt(e.target.value) + } + placeholder="Or ask me to build something new..." + /> + + + {isLoading &&

Loading...

} +
+
+ ); +}; diff --git a/apps/playground/tsconfig.json b/apps/playground/tsconfig.json index 3d0a51a8..7b0e2287 100644 --- a/apps/playground/tsconfig.json +++ b/apps/playground/tsconfig.json @@ -16,6 +16,6 @@ "noEmit": true, "jsx": "react-jsx" }, - "include": ["src"], + "include": ["src/**/*.tsx"], "references": [{ "path": "./tsconfig.node.json" }] } From fbb82e4d197cd7d5dad5a21302f26e3d2ad6b9a1 Mon Sep 17 00:00:00 2001 From: tsuf239 <39455181+tsuf239@users.noreply.github.com> Date: Mon, 26 Feb 2024 16:23:32 +0200 Subject: [PATCH 4/5] add loading state and clean --- apps/playground/package.json | 1 + apps/playground/src/ai/ctas.tsx | 23 +++++++- apps/playground/src/ai/index.tsx | 90 ++++++++++++++++++++------------ package-lock.json | 21 ++++++++ 4 files changed, 102 insertions(+), 33 deletions(-) diff --git a/apps/playground/package.json b/apps/playground/package.json index fe5fabdd..0e687fb0 100644 --- a/apps/playground/package.json +++ b/apps/playground/package.json @@ -36,6 +36,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.8.0", + "react-toastify": "^10.0.4", "semantic-ui-css": "^2.5.0", "semantic-ui-react": "^2.1.4", "tar": "^6.1.13", diff --git a/apps/playground/src/ai/ctas.tsx b/apps/playground/src/ai/ctas.tsx index 5d4b2bdb..c7a442a6 100644 --- a/apps/playground/src/ai/ctas.tsx +++ b/apps/playground/src/ai/ctas.tsx @@ -11,13 +11,34 @@ export const Input = (props: { export const Button = (props: { onClick: (e: React.MouseEvent) => void; + isLoading?: boolean; children: any; }) => ( ); diff --git a/apps/playground/src/ai/index.tsx b/apps/playground/src/ai/index.tsx index f4a16cdb..bcfa07d6 100644 --- a/apps/playground/src/ai/index.tsx +++ b/apps/playground/src/ai/index.tsx @@ -2,6 +2,8 @@ import { uuid } from "uuidv4"; import { useEffect, useState } from "react"; import { AiIcon, FixIcon } from "./icons"; import { Button, Input } from "./ctas"; +import { ToastContainer, toast } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; const formatCode = (code: string) => { let isCode = false; @@ -18,7 +20,13 @@ const formatCode = (code: string) => { }; const AI_API_URL = - "https://t4iblpvvr4.execute-api.us-east-1.amazonaws.com/prod"; + "https://bxsblg1sf2.execute-api.us-east-1.amazonaws.com/prod"; + +const LOADING_STATES = { + GENERATE: "GENERATE", + FIX: "FIX", + NONE: "", +}; export const AiInput = ({ onAiAnswer, @@ -28,7 +36,7 @@ export const AiInput = ({ code?: string; }) => { const [prompt, setPrompt] = useState(""); - const [isLoading, setLoading] = useState(false); + const [isLoading, setIsLoading] = useState(LOADING_STATES.NONE); useEffect(() => { if (sessionStorage.getItem("conversation-id") === null) { @@ -37,38 +45,48 @@ export const AiInput = ({ }, []); const askAi = async () => { - setLoading(true); - const res = await fetch(`${AI_API_URL}/ai`, { - method: "POST", - body: JSON.stringify({ prompt, code }), - headers: { - "conversation-id": sessionStorage.getItem("conversation-id")!, - "Access-Control-Allow-Origin": "http://localhost:5173", - "Access-Control-Allow-Credentials": "true", - }, - }); - if (res.ok) { - onAiAnswer(formatCode(await res.text())); + setIsLoading(LOADING_STATES.GENERATE); + try { + const res = await fetch(`${AI_API_URL}/generate`, { + method: "POST", + body: JSON.stringify({ prompt, code }), + headers: { + "conversation-id": sessionStorage.getItem("conversation-id")!, + "Access-Control-Allow-Origin": "http://localhost:5173", + "Access-Control-Allow-Credentials": "true", + }, + }); + if (res.ok) { + onAiAnswer(formatCode(await res.text())); + } + setPrompt(""); + } catch (error) { + toast.error((error as Error).message); + } finally { + setIsLoading(LOADING_STATES.NONE); } - setLoading(false); - setPrompt(""); }; const fixCode = async () => { - setLoading(true); - const res = await fetch(`${AI_API_URL}/fix-code`, { - method: "POST", - body: JSON.stringify({ code }), - headers: { - "conversation-id": sessionStorage.getItem("conversation-id")!, - "Access-Control-Allow-Origin": "http://localhost:5173", - "Access-Control-Allow-Credentials": "true", - }, - }); - if (res.ok) { - onAiAnswer(formatCode(await res.text())); + try { + setIsLoading(LOADING_STATES.FIX); + const res = await fetch(`${AI_API_URL}/fix`, { + method: "POST", + body: JSON.stringify({ code }), + headers: { + "conversation-id": sessionStorage.getItem("conversation-id")!, + "Access-Control-Allow-Origin": "http://localhost:5173", + "Access-Control-Allow-Credentials": "true", + }, + }); + if (res.ok) { + onAiAnswer(formatCode(await res.text())); + } + } catch (error) { + toast.error((error as Error).message); + } finally { + setIsLoading(LOADING_STATES.NONE); } - setLoading(false); }; const restart = () => { @@ -91,7 +109,10 @@ export const AiInput = ({
-
@@ -103,9 +124,14 @@ export const AiInput = ({ } placeholder="Or ask me to build something new..." /> - + - {isLoading &&

Loading...

} +
); diff --git a/package-lock.json b/package-lock.json index 026d293d..a891b1cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,6 +84,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-icons": "^4.8.0", + "react-toastify": "^10.0.4", "semantic-ui-css": "^2.5.0", "semantic-ui-react": "^2.1.4", "tar": "^6.1.13", @@ -26620,6 +26621,26 @@ "react-dom": ">=16.8" } }, + "node_modules/react-toastify": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.4.tgz", + "integrity": "sha512-etR3RgueY8pe88SA67wLm8rJmL1h+CLqUGHuAoNsseW35oTGJEri6eBTyaXnFKNQ80v/eO10hBYLgz036XRGgA==", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, + "node_modules/react-toastify/node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", From 281197861eb8381bf4da5ccb02389d58ce8cd2b0 Mon Sep 17 00:00:00 2001 From: tsuf239 <39455181+tsuf239@users.noreply.github.com> Date: Mon, 26 Feb 2024 17:02:59 +0200 Subject: [PATCH 5/5] fix code to fix --- apps/playground/src/ai/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/playground/src/ai/index.tsx b/apps/playground/src/ai/index.tsx index bcfa07d6..c6dbd772 100644 --- a/apps/playground/src/ai/index.tsx +++ b/apps/playground/src/ai/index.tsx @@ -113,7 +113,7 @@ export const AiInput = ({ onClick={fixCode} isLoading={isLoading === LOADING_STATES.FIX} > - Fix code + Fix