Spaces:
Runtime error
Runtime error
feat: renamed a few components, added cancel, changed the default button
Browse files- public/js/utils.js +1 -1
- src/components/Examples.tsx +29 -2
- src/components/GameCreator.tsx +135 -106
- src/components/{Workflow.tsx → HowToUse.tsx} +27 -3
- src/components/Introduction.tsx +37 -27
- src/components/Troubleshooting.tsx +43 -0
- src/components/{Instructions.tsx → UnderTheHood.tsx} +1 -36
- src/components/base/boxes.tsx +16 -1
- src/components/title.tsx +1 -1
- src/lib/theme.ts +12 -0
- src/pages/index.tsx +7 -4
- src/services/api/index.ts +11 -6
- src/services/api/openai.ts +6 -1
public/js/utils.js
CHANGED
@@ -49,7 +49,7 @@ function answer(window_, channel, targetOrigin = "*") {
|
|
49 |
}
|
50 |
|
51 |
function handleTemplate(template) {
|
52 |
-
Function("Template", `${template}
|
53 |
}
|
54 |
|
55 |
subscribe("2DGameGPT", event => {
|
|
|
49 |
}
|
50 |
|
51 |
function handleTemplate(template) {
|
52 |
+
Function("Template", `${template}`)();
|
53 |
}
|
54 |
|
55 |
subscribe("2DGameGPT", event => {
|
src/components/Examples.tsx
CHANGED
@@ -17,6 +17,7 @@ import {
|
|
17 |
} from "@mui/material";
|
18 |
import { DividerBox, SectionBox } from "./base/boxes";
|
19 |
import { DynamicFeed, PrecisionManufacturing } from "@mui/icons-material";
|
|
|
20 |
|
21 |
export default function Examples() {
|
22 |
return (
|
@@ -27,12 +28,38 @@ export default function Examples() {
|
|
27 |
<Typography component="h3" variant="h2">
|
28 |
Example Games
|
29 |
</Typography>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
</SectionBox>
|
31 |
|
32 |
<Grid container>
|
33 |
<Grid item sm={4}>
|
34 |
<Card>
|
35 |
-
<CardHeader
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
<CardMedia
|
37 |
component="img"
|
38 |
image="img/space_invaders_extreme.jpg"
|
@@ -50,7 +77,7 @@ export default function Examples() {
|
|
50 |
target="_blank"
|
51 |
rel="noopener"
|
52 |
>
|
53 |
-
|
54 |
</Link>
|
55 |
</TableCell>
|
56 |
</TableRow>
|
|
|
17 |
} from "@mui/material";
|
18 |
import { DividerBox, SectionBox } from "./base/boxes";
|
19 |
import { DynamicFeed, PrecisionManufacturing } from "@mui/icons-material";
|
20 |
+
import theme from "@/lib/theme";
|
21 |
|
22 |
export default function Examples() {
|
23 |
return (
|
|
|
28 |
<Typography component="h3" variant="h2">
|
29 |
Example Games
|
30 |
</Typography>
|
31 |
+
<Typography variant="body1">
|
32 |
+
We re-created some of our favorite games! You want to share your game with the
|
33 |
+
community? Then head over to our{" "}
|
34 |
+
<Link
|
35 |
+
href="https://discord.com/invite/m3TBB9XEkb"
|
36 |
+
target="_blank"
|
37 |
+
rel="noopener"
|
38 |
+
sx={{ verticalAlign: "bottom" }}
|
39 |
+
>
|
40 |
+
<img
|
41 |
+
style={{ verticalAlign: "bottom" }}
|
42 |
+
src="https://img.shields.io/discord/1091306623819059300?color=7289da&label=Discord&logo=discord&logoColor=fff&style=for-the-badge"
|
43 |
+
/>
|
44 |
+
</Link>
|
45 |
+
, post it in #showcase and we might add it to this section as well!
|
46 |
+
</Typography>
|
47 |
</SectionBox>
|
48 |
|
49 |
<Grid container>
|
50 |
<Grid item sm={4}>
|
51 |
<Card>
|
52 |
+
<CardHeader
|
53 |
+
title="Space Invaders Extreme"
|
54 |
+
subheader={
|
55 |
+
<>
|
56 |
+
by{" "}
|
57 |
+
<Link href="https://nerddis.co" target="_blank" rel="noopener">
|
58 |
+
NERDDISCO
|
59 |
+
</Link>
|
60 |
+
</>
|
61 |
+
}
|
62 |
+
></CardHeader>
|
63 |
<CardMedia
|
64 |
component="img"
|
65 |
image="img/space_invaders_extreme.jpg"
|
|
|
77 |
target="_blank"
|
78 |
rel="noopener"
|
79 |
>
|
80 |
+
on CodeSandbox
|
81 |
</Link>
|
82 |
</TableCell>
|
83 |
</TableRow>
|
src/components/GameCreator.tsx
CHANGED
@@ -1,15 +1,12 @@
|
|
1 |
-
import {
|
2 |
|
3 |
-
import
|
4 |
-
import KeyIcon from "@mui/icons-material/Key";
|
5 |
-
import SmartButtonIcon from "@mui/icons-material/SmartButton";
|
6 |
import AcUnitIcon from "@mui/icons-material/AcUnit";
|
7 |
import LocalFireDepartmentIcon from "@mui/icons-material/LocalFireDepartment";
|
8 |
import CheckIcon from "@mui/icons-material/Check";
|
9 |
import ClearIcon from "@mui/icons-material/Clear";
|
10 |
import CodeIcon from "@mui/icons-material/Code";
|
11 |
import CodeOffIcon from "@mui/icons-material/CodeOff";
|
12 |
-
import EditIcon from "@mui/icons-material/Edit";
|
13 |
import VisibilityIcon from "@mui/icons-material/Visibility";
|
14 |
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
|
15 |
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
@@ -36,7 +33,6 @@ import ListItemButton from "@mui/material/ListItemButton";
|
|
36 |
import ListItemText from "@mui/material/ListItemText";
|
37 |
import { useHost } from "esdeka/react";
|
38 |
import CircularProgress from "@mui/material/CircularProgress";
|
39 |
-
import CssBaseline from "@mui/material/CssBaseline";
|
40 |
import Slider from "@mui/material/Slider";
|
41 |
import { useAtom } from "jotai";
|
42 |
import Button from "@mui/material/Button";
|
@@ -61,23 +57,14 @@ import {
|
|
61 |
COMMAND_REMOVE_FEATURE,
|
62 |
} from "@/constants";
|
63 |
import { baseGame } from "@/constants/baseGame";
|
64 |
-
import {
|
65 |
-
import theme, { fontMono } from "@/lib/theme";
|
66 |
import { Codesandbox } from "@/components/Codesandbox";
|
67 |
-
import { Codepen } from "@/components/Codepen";
|
68 |
-
import { InfoMenu } from "@/components/InfoMenu";
|
69 |
-
import SimpleSnackbar from "@/components/SimpleSnackbar";
|
70 |
import ExampleButton from "@/components/base/ExampleButton";
|
71 |
-
import {
|
72 |
import Secret from "@/components/base/secret";
|
73 |
-
import Footer from "@/components/footer";
|
74 |
-
import Title from "@/components/title";
|
75 |
-
import { RunCircle } from "@mui/icons-material";
|
76 |
-
import Introduction from "@/components/Introduction";
|
77 |
-
import Instructions from "@/components/Instructions";
|
78 |
-
import Examples from "@/components/Examples";
|
79 |
import { toOpenAI } from "@/services/api";
|
80 |
import { createClient } from "@/services/api/openai";
|
|
|
81 |
const MonacoEditor = dynamic(import("@monaco-editor/react"), { ssr: false });
|
82 |
|
83 |
export interface ShareProps {
|
@@ -87,6 +74,8 @@ export interface ShareProps {
|
|
87 |
|
88 |
export default function GameCreator() {
|
89 |
const ref = useRef<HTMLIFrameElement>(null);
|
|
|
|
|
90 |
const [prompt, setPrompt] = useState("");
|
91 |
const [template, setTemplate] = useState(prettify(baseGame.default));
|
92 |
const [runningId, setRunningId] = useState("1");
|
@@ -96,7 +85,6 @@ export default function GameCreator() {
|
|
96 |
const [showCode, setShowCode] = useAtom(showCodeAtom);
|
97 |
const [loading, setLoading] = useState(false);
|
98 |
const [loadingLive, setLoadingLive] = useState(true);
|
99 |
-
const [showError, setShowError] = useState(false);
|
100 |
const [errorMessage, setErrorMessage] = useState("");
|
101 |
|
102 |
const { mode, systemMode } = useColorScheme();
|
@@ -150,6 +138,14 @@ export default function GameCreator() {
|
|
150 |
};
|
151 |
}, [subscribe, loadingLive]);
|
152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
153 |
const sortedAnswers = useMemo(() => {
|
154 |
return [...answers].sort((a, b) => {
|
155 |
if (a.id === "1") return -1;
|
@@ -160,14 +156,6 @@ export default function GameCreator() {
|
|
160 |
|
161 |
const current = answers.find(({ id }) => id === activeId);
|
162 |
|
163 |
-
const handleSnackbarClose = (event: SyntheticEvent | Event, reason?: string) => {
|
164 |
-
if (reason === "clickaway") {
|
165 |
-
return;
|
166 |
-
}
|
167 |
-
|
168 |
-
setShowError(false);
|
169 |
-
};
|
170 |
-
|
171 |
function reload() {
|
172 |
connection.current = false;
|
173 |
if (ref.current) {
|
@@ -186,7 +174,7 @@ export default function GameCreator() {
|
|
186 |
inset: 0,
|
187 |
overflow: "hidden",
|
188 |
flexDirection: { md: "row" },
|
189 |
-
height: "
|
190 |
}}
|
191 |
>
|
192 |
<Stack
|
@@ -199,10 +187,14 @@ export default function GameCreator() {
|
|
199 |
>
|
200 |
<AppBar position="static" elevation={0} color="default">
|
201 |
<Toolbar>
|
202 |
-
<Typography variant="h5" component="h2" sx={{
|
203 |
2D GameCreator-GPT
|
204 |
</Typography>
|
205 |
|
|
|
|
|
|
|
|
|
206 |
<IconButton
|
207 |
color="inherit"
|
208 |
aria-label={showCode ? "Hide Code" : "Show Code"}
|
@@ -212,19 +204,6 @@ export default function GameCreator() {
|
|
212 |
>
|
213 |
{showCode ? <CodeOffIcon /> : <CodeIcon />}
|
214 |
</IconButton>
|
215 |
-
{/* <IconButton
|
216 |
-
edge="end"
|
217 |
-
color="inherit"
|
218 |
-
aria-label="Clear Prompt"
|
219 |
-
onClick={async () => {
|
220 |
-
setActiveId("1");
|
221 |
-
setRunningId("1");
|
222 |
-
setTemplate(prettify(baseGame.default));
|
223 |
-
reload();
|
224 |
-
}}
|
225 |
-
>
|
226 |
-
<ClearIcon />
|
227 |
-
</IconButton> */}
|
228 |
</Toolbar>
|
229 |
</AppBar>
|
230 |
{showCode && (
|
@@ -279,6 +258,8 @@ export default function GameCreator() {
|
|
279 |
try {
|
280 |
setLoading(true);
|
281 |
|
|
|
|
|
282 |
const {
|
283 |
command,
|
284 |
prompt,
|
@@ -299,17 +280,22 @@ export default function GameCreator() {
|
|
299 |
model: model as string,
|
300 |
maxTokens: maxTokens as string,
|
301 |
client,
|
|
|
302 |
});
|
303 |
|
304 |
setAnswers(previousAnswers => [answer, ...previousAnswers]);
|
305 |
setRunningId(answer.id);
|
306 |
setActiveId(answer.id);
|
307 |
setTemplate(prettify(answer.content));
|
|
|
308 |
reload();
|
309 |
} catch (error) {
|
310 |
-
|
311 |
-
|
312 |
-
|
|
|
|
|
|
|
313 |
} finally {
|
314 |
setLoading(false);
|
315 |
}
|
@@ -322,13 +308,14 @@ export default function GameCreator() {
|
|
322 |
<TextField
|
323 |
multiline
|
324 |
fullWidth
|
|
|
325 |
required
|
326 |
id="prompt"
|
327 |
name="prompt"
|
328 |
label="Prompt"
|
329 |
value={prompt}
|
330 |
onChange={e => setPrompt(e.target.value)}
|
331 |
-
minRows={
|
332 |
InputProps={{
|
333 |
style: fontMono.style,
|
334 |
}}
|
@@ -364,36 +351,49 @@ export default function GameCreator() {
|
|
364 |
</Select>
|
365 |
</FormControl>
|
366 |
|
367 |
-
<
|
368 |
-
form="gpt-form"
|
369 |
-
type="submit"
|
370 |
variant="contained"
|
371 |
fullWidth
|
372 |
-
|
373 |
-
aria-disabled={loading}
|
374 |
-
disabled={loading}
|
375 |
-
startIcon={
|
376 |
-
loading ? (
|
377 |
-
<CircularProgress size={20} />
|
378 |
-
) : (
|
379 |
-
<PlayArrowIcon />
|
380 |
-
)
|
381 |
-
}
|
382 |
-
sx={{
|
383 |
-
pl: 5,
|
384 |
-
pr: 5,
|
385 |
-
flexGrow: 1,
|
386 |
-
overflow: "auto",
|
387 |
-
}}
|
388 |
>
|
389 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
390 |
Run
|
391 |
-
</
|
392 |
-
|
393 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
394 |
</Stack>
|
395 |
</Stack>
|
396 |
|
|
|
|
|
397 |
<Stack direction="row" spacing={1} alignItems="center">
|
398 |
<Typography>Examples</Typography>
|
399 |
|
@@ -585,38 +585,73 @@ export default function GameCreator() {
|
|
585 |
}
|
586 |
disablePadding
|
587 |
>
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
>
|
600 |
-
<ListItemIcon>
|
601 |
-
{runningId === answer.id ? (
|
602 |
-
<CheckIcon />
|
603 |
-
) : (
|
604 |
-
<VisibilityIcon />
|
605 |
-
)}
|
606 |
-
</ListItemIcon>
|
607 |
-
|
608 |
-
<ListItemText
|
609 |
-
primary={answer.task}
|
610 |
-
primaryTypographyProps={{
|
611 |
-
sx: {
|
612 |
-
overflow: "hidden",
|
613 |
-
textOverflow: "ellipsis",
|
614 |
-
whiteSpace: "nowrap",
|
615 |
-
fontSize: 16,
|
616 |
-
},
|
617 |
}}
|
618 |
-
|
619 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
620 |
</ListItem>
|
621 |
);
|
622 |
})}
|
@@ -697,12 +732,6 @@ export default function GameCreator() {
|
|
697 |
</Stack>
|
698 |
</Stack>
|
699 |
</Paper>
|
700 |
-
|
701 |
-
<SimpleSnackbar
|
702 |
-
handleClose={handleSnackbarClose}
|
703 |
-
showError={showError}
|
704 |
-
message={errorMessage}
|
705 |
-
/>
|
706 |
</>
|
707 |
);
|
708 |
}
|
|
|
1 |
+
import { useEffect, useMemo, useRef, useState } from "react";
|
2 |
|
3 |
+
import { AxiosError } from "axios";
|
|
|
|
|
4 |
import AcUnitIcon from "@mui/icons-material/AcUnit";
|
5 |
import LocalFireDepartmentIcon from "@mui/icons-material/LocalFireDepartment";
|
6 |
import CheckIcon from "@mui/icons-material/Check";
|
7 |
import ClearIcon from "@mui/icons-material/Clear";
|
8 |
import CodeIcon from "@mui/icons-material/Code";
|
9 |
import CodeOffIcon from "@mui/icons-material/CodeOff";
|
|
|
10 |
import VisibilityIcon from "@mui/icons-material/Visibility";
|
11 |
import DeleteForeverIcon from "@mui/icons-material/DeleteForever";
|
12 |
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
|
33 |
import ListItemText from "@mui/material/ListItemText";
|
34 |
import { useHost } from "esdeka/react";
|
35 |
import CircularProgress from "@mui/material/CircularProgress";
|
|
|
36 |
import Slider from "@mui/material/Slider";
|
37 |
import { useAtom } from "jotai";
|
38 |
import Button from "@mui/material/Button";
|
|
|
57 |
COMMAND_REMOVE_FEATURE,
|
58 |
} from "@/constants";
|
59 |
import { baseGame } from "@/constants/baseGame";
|
60 |
+
import { fontMono } from "@/lib/theme";
|
|
|
61 |
import { Codesandbox } from "@/components/Codesandbox";
|
|
|
|
|
|
|
62 |
import ExampleButton from "@/components/base/ExampleButton";
|
63 |
+
import { Alert, ButtonGroup, ListSubheader } from "@mui/material";
|
64 |
import Secret from "@/components/base/secret";
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
import { toOpenAI } from "@/services/api";
|
66 |
import { createClient } from "@/services/api/openai";
|
67 |
+
import { RainbowListItemButton } from "./base/boxes";
|
68 |
const MonacoEditor = dynamic(import("@monaco-editor/react"), { ssr: false });
|
69 |
|
70 |
export interface ShareProps {
|
|
|
74 |
|
75 |
export default function GameCreator() {
|
76 |
const ref = useRef<HTMLIFrameElement>(null);
|
77 |
+
const abortController = useRef<AbortController | null>(null);
|
78 |
+
|
79 |
const [prompt, setPrompt] = useState("");
|
80 |
const [template, setTemplate] = useState(prettify(baseGame.default));
|
81 |
const [runningId, setRunningId] = useState("1");
|
|
|
85 |
const [showCode, setShowCode] = useAtom(showCodeAtom);
|
86 |
const [loading, setLoading] = useState(false);
|
87 |
const [loadingLive, setLoadingLive] = useState(true);
|
|
|
88 |
const [errorMessage, setErrorMessage] = useState("");
|
89 |
|
90 |
const { mode, systemMode } = useColorScheme();
|
|
|
138 |
};
|
139 |
}, [subscribe, loadingLive]);
|
140 |
|
141 |
+
const handleCancel = async () => {
|
142 |
+
if (abortController.current) {
|
143 |
+
abortController.current.abort();
|
144 |
+
}
|
145 |
+
setLoading(false);
|
146 |
+
reload();
|
147 |
+
};
|
148 |
+
|
149 |
const sortedAnswers = useMemo(() => {
|
150 |
return [...answers].sort((a, b) => {
|
151 |
if (a.id === "1") return -1;
|
|
|
156 |
|
157 |
const current = answers.find(({ id }) => id === activeId);
|
158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
function reload() {
|
160 |
connection.current = false;
|
161 |
if (ref.current) {
|
|
|
174 |
inset: 0,
|
175 |
overflow: "hidden",
|
176 |
flexDirection: { md: "row" },
|
177 |
+
height: "90vh",
|
178 |
}}
|
179 |
>
|
180 |
<Stack
|
|
|
187 |
>
|
188 |
<AppBar position="static" elevation={0} color="default">
|
189 |
<Toolbar>
|
190 |
+
<Typography variant="h5" component="h2" sx={{ m: 0 }}>
|
191 |
2D GameCreator-GPT
|
192 |
</Typography>
|
193 |
|
194 |
+
<Typography variant="body2" sx={{ ml: 1, flex: 1 }}>
|
195 |
+
v0.0.1
|
196 |
+
</Typography>
|
197 |
+
|
198 |
<IconButton
|
199 |
color="inherit"
|
200 |
aria-label={showCode ? "Hide Code" : "Show Code"}
|
|
|
204 |
>
|
205 |
{showCode ? <CodeOffIcon /> : <CodeIcon />}
|
206 |
</IconButton>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
</Toolbar>
|
208 |
</AppBar>
|
209 |
{showCode && (
|
|
|
258 |
try {
|
259 |
setLoading(true);
|
260 |
|
261 |
+
abortController.current = new AbortController();
|
262 |
+
|
263 |
const {
|
264 |
command,
|
265 |
prompt,
|
|
|
280 |
model: model as string,
|
281 |
maxTokens: maxTokens as string,
|
282 |
client,
|
283 |
+
signal: abortController.current.signal,
|
284 |
});
|
285 |
|
286 |
setAnswers(previousAnswers => [answer, ...previousAnswers]);
|
287 |
setRunningId(answer.id);
|
288 |
setActiveId(answer.id);
|
289 |
setTemplate(prettify(answer.content));
|
290 |
+
setErrorMessage("");
|
291 |
reload();
|
292 |
} catch (error) {
|
293 |
+
if (
|
294 |
+
(error as { message?: string }).message !== "canceled"
|
295 |
+
) {
|
296 |
+
setErrorMessage((error as AxiosError).message);
|
297 |
+
console.error(error);
|
298 |
+
}
|
299 |
} finally {
|
300 |
setLoading(false);
|
301 |
}
|
|
|
308 |
<TextField
|
309 |
multiline
|
310 |
fullWidth
|
311 |
+
variant="outlined"
|
312 |
required
|
313 |
id="prompt"
|
314 |
name="prompt"
|
315 |
label="Prompt"
|
316 |
value={prompt}
|
317 |
onChange={e => setPrompt(e.target.value)}
|
318 |
+
minRows={3}
|
319 |
InputProps={{
|
320 |
style: fontMono.style,
|
321 |
}}
|
|
|
351 |
</Select>
|
352 |
</FormControl>
|
353 |
|
354 |
+
<ButtonGroup
|
|
|
|
|
355 |
variant="contained"
|
356 |
fullWidth
|
357 |
+
sx={{ flexGrow: 1, maxHeight: "96px" }}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
>
|
359 |
+
<Button
|
360 |
+
form="gpt-form"
|
361 |
+
type="submit"
|
362 |
+
aria-label={loading ? "Loading" : "Run"}
|
363 |
+
aria-disabled={loading}
|
364 |
+
disabled={loading}
|
365 |
+
startIcon={
|
366 |
+
loading ? (
|
367 |
+
<CircularProgress size={20} />
|
368 |
+
) : (
|
369 |
+
<PlayArrowIcon />
|
370 |
+
)
|
371 |
+
}
|
372 |
+
sx={{
|
373 |
+
pl: 5,
|
374 |
+
pr: 5,
|
375 |
+
}}
|
376 |
+
>
|
377 |
Run
|
378 |
+
</Button>
|
379 |
+
<Button
|
380 |
+
aria-label="Cancel"
|
381 |
+
aria-disabled={!loading}
|
382 |
+
disabled={!loading}
|
383 |
+
onClick={handleCancel}
|
384 |
+
startIcon={<ClearIcon />}
|
385 |
+
color="error"
|
386 |
+
sx={{
|
387 |
+
pl: 0,
|
388 |
+
pr: 0,
|
389 |
+
}}
|
390 |
+
></Button>
|
391 |
+
</ButtonGroup>
|
392 |
</Stack>
|
393 |
</Stack>
|
394 |
|
395 |
+
{errorMessage && <Alert severity="error">{errorMessage}</Alert>}
|
396 |
+
|
397 |
<Stack direction="row" spacing={1} alignItems="center">
|
398 |
<Typography>Examples</Typography>
|
399 |
|
|
|
585 |
}
|
586 |
disablePadding
|
587 |
>
|
588 |
+
{activeId === answer.id ? (
|
589 |
+
<RainbowListItemButton
|
590 |
+
dense
|
591 |
+
selected={activeId === answer.id}
|
592 |
+
// disabled={activeId === answer.id}
|
593 |
+
role={undefined}
|
594 |
+
onClick={() => {
|
595 |
+
setActiveId(answer.id);
|
596 |
+
setRunningId(answer.id);
|
597 |
+
setTemplate(prettify(answer.content));
|
598 |
+
reload();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
599 |
}}
|
600 |
+
>
|
601 |
+
<ListItemIcon>
|
602 |
+
{runningId === answer.id ? (
|
603 |
+
<CheckIcon />
|
604 |
+
) : (
|
605 |
+
<VisibilityIcon />
|
606 |
+
)}
|
607 |
+
</ListItemIcon>
|
608 |
+
|
609 |
+
<ListItemText
|
610 |
+
primary={answer.task}
|
611 |
+
primaryTypographyProps={{
|
612 |
+
sx: {
|
613 |
+
overflow: "hidden",
|
614 |
+
textOverflow: "ellipsis",
|
615 |
+
whiteSpace: "nowrap",
|
616 |
+
fontSize: 16,
|
617 |
+
},
|
618 |
+
}}
|
619 |
+
/>
|
620 |
+
</RainbowListItemButton>
|
621 |
+
) : (
|
622 |
+
<ListItemButton
|
623 |
+
dense
|
624 |
+
selected={activeId === answer.id}
|
625 |
+
// disabled={activeId === answer.id}
|
626 |
+
role={undefined}
|
627 |
+
onClick={() => {
|
628 |
+
setActiveId(answer.id);
|
629 |
+
setRunningId(answer.id);
|
630 |
+
setTemplate(prettify(answer.content));
|
631 |
+
reload();
|
632 |
+
}}
|
633 |
+
>
|
634 |
+
<ListItemIcon>
|
635 |
+
{runningId === answer.id ? (
|
636 |
+
<CheckIcon />
|
637 |
+
) : (
|
638 |
+
<VisibilityIcon />
|
639 |
+
)}
|
640 |
+
</ListItemIcon>
|
641 |
+
|
642 |
+
<ListItemText
|
643 |
+
primary={answer.task}
|
644 |
+
primaryTypographyProps={{
|
645 |
+
sx: {
|
646 |
+
overflow: "hidden",
|
647 |
+
textOverflow: "ellipsis",
|
648 |
+
whiteSpace: "nowrap",
|
649 |
+
fontSize: 16,
|
650 |
+
},
|
651 |
+
}}
|
652 |
+
/>
|
653 |
+
</ListItemButton>
|
654 |
+
)}
|
655 |
</ListItem>
|
656 |
);
|
657 |
})}
|
|
|
732 |
</Stack>
|
733 |
</Stack>
|
734 |
</Paper>
|
|
|
|
|
|
|
|
|
|
|
|
|
735 |
</>
|
736 |
);
|
737 |
}
|
src/components/{Workflow.tsx → HowToUse.tsx}
RENAMED
@@ -1,4 +1,4 @@
|
|
1 |
-
import { PlayArrow, Code, Replay, CropSquare } from "@mui/icons-material";
|
2 |
import {
|
3 |
Button,
|
4 |
Grid,
|
@@ -7,12 +7,24 @@ import {
|
|
7 |
ListItem,
|
8 |
ListSubheader,
|
9 |
Paper,
|
|
|
10 |
Typography,
|
11 |
} from "@mui/material";
|
12 |
import { OutlinedBox, SectionBox, RainbowBox } from "@/components/base/boxes";
|
13 |
import { Key } from "react";
|
14 |
|
15 |
const workflowSteps = [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
{
|
17 |
title: "Create a New Game",
|
18 |
steps: [
|
@@ -94,7 +106,7 @@ const workflowSteps = [
|
|
94 |
"Open the Options by clicking on them",
|
95 |
"Switch the model between gpt-4 and gpt-3.5-turbo (default)",
|
96 |
"Update the max_tokens to 4096 (gpt-4), default is 2048 (gpt-3.5-turbo)",
|
97 |
-
"Make changes to the temperature if you want more random results, default is 0.2",
|
98 |
],
|
99 |
},
|
100 |
];
|
@@ -130,6 +142,18 @@ function parseString(string: string) {
|
|
130 |
|
131 |
</>
|
132 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
"source code button": (item: string, index: Key | null | undefined) => (
|
134 |
<>
|
135 |
|
@@ -205,7 +229,7 @@ function parseString(string: string) {
|
|
205 |
});
|
206 |
}
|
207 |
|
208 |
-
export default function
|
209 |
return (
|
210 |
<>
|
211 |
<SectionBox>
|
|
|
1 |
+
import { PlayArrow, Code, Replay, CropSquare, Clear } from "@mui/icons-material";
|
2 |
import {
|
3 |
Button,
|
4 |
Grid,
|
|
|
7 |
ListItem,
|
8 |
ListSubheader,
|
9 |
Paper,
|
10 |
+
Stack,
|
11 |
Typography,
|
12 |
} from "@mui/material";
|
13 |
import { OutlinedBox, SectionBox, RainbowBox } from "@/components/base/boxes";
|
14 |
import { Key } from "react";
|
15 |
|
16 |
const workflowSteps = [
|
17 |
+
{
|
18 |
+
title: "Editor Usage Tips",
|
19 |
+
steps: [
|
20 |
+
"We are limited by the context-size of the selected model, the scope of the game shouldn't be super huge (for example 'asteroids' is a game with small scope while 'fortnite' is way too big)",
|
21 |
+
"It's good to start with simple features, main mechanics first using the base game + the create game command.",
|
22 |
+
'Iterate on this. For example "Flappy Bird. Intro screen, start the game by pressing space key."',
|
23 |
+
"See if the generated result is what you expect. Continue there, add more features. Either by using the add feature command or by extending the prompt itself and start from scratch (select the base game + create game command).",
|
24 |
+
"Make always sure to check the selected game in the games list, as this is used as the foundation for the next iteration.",
|
25 |
+
"Cancel generating the game at any time by pressing the cancel button button next to run button.",
|
26 |
+
],
|
27 |
+
},
|
28 |
{
|
29 |
title: "Create a New Game",
|
30 |
steps: [
|
|
|
106 |
"Open the Options by clicking on them",
|
107 |
"Switch the model between gpt-4 and gpt-3.5-turbo (default)",
|
108 |
"Update the max_tokens to 4096 (gpt-4), default is 2048 (gpt-3.5-turbo)",
|
109 |
+
"Make changes to the temperature if you want more random (value closer to 1.0) results, default is 0.2 (not very random)",
|
110 |
],
|
111 |
},
|
112 |
];
|
|
|
142 |
|
143 |
</>
|
144 |
),
|
145 |
+
"cancel button": (item: string, index: Key | null | undefined) => (
|
146 |
+
<>
|
147 |
+
|
148 |
+
<Button
|
149 |
+
variant="contained"
|
150 |
+
color="error"
|
151 |
+
startIcon={<Clear />}
|
152 |
+
key={index}
|
153 |
+
></Button>
|
154 |
+
|
155 |
+
</>
|
156 |
+
),
|
157 |
"source code button": (item: string, index: Key | null | undefined) => (
|
158 |
<>
|
159 |
|
|
|
229 |
});
|
230 |
}
|
231 |
|
232 |
+
export default function HowToUse() {
|
233 |
return (
|
234 |
<>
|
235 |
<SectionBox>
|
src/components/Introduction.tsx
CHANGED
@@ -9,42 +9,48 @@ import {
|
|
9 |
ListItemIcon,
|
10 |
ListItemText,
|
11 |
Link,
|
|
|
12 |
} from "@mui/material";
|
13 |
import KeyIcon from "@mui/icons-material/Key";
|
14 |
import SmartButtonIcon from "@mui/icons-material/SmartButton";
|
15 |
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
|
|
16 |
|
17 |
export default function Introduction() {
|
18 |
return (
|
19 |
<Stack direction="row" spacing={2}>
|
20 |
<Grid container gap={2} sx={{ justifyContent: "center" }}>
|
21 |
<Grid item md={4}>
|
22 |
-
<
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
27 |
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
<
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
|
|
|
|
|
|
48 |
</Grid>
|
49 |
<Grid item md={4}>
|
50 |
<Paper>
|
@@ -71,7 +77,7 @@ export default function Introduction() {
|
|
71 |
<SmartButtonIcon />
|
72 |
</ListItemIcon>
|
73 |
<ListItemText>
|
74 |
-
Select one of the <b>
|
75 |
</ListItemText>
|
76 |
</ListItem>
|
77 |
<ListItem>
|
@@ -79,7 +85,11 @@ export default function Introduction() {
|
|
79 |
<PlayArrowIcon />
|
80 |
</ListItemIcon>
|
81 |
<ListItemText>
|
82 |
-
Click on
|
|
|
|
|
|
|
|
|
83 |
</ListItemText>
|
84 |
</ListItem>
|
85 |
</List>
|
|
|
9 |
ListItemIcon,
|
10 |
ListItemText,
|
11 |
Link,
|
12 |
+
Button,
|
13 |
} from "@mui/material";
|
14 |
import KeyIcon from "@mui/icons-material/Key";
|
15 |
import SmartButtonIcon from "@mui/icons-material/SmartButton";
|
16 |
import PlayArrowIcon from "@mui/icons-material/PlayArrow";
|
17 |
+
import { PlayArrow } from "@mui/icons-material";
|
18 |
|
19 |
export default function Introduction() {
|
20 |
return (
|
21 |
<Stack direction="row" spacing={2}>
|
22 |
<Grid container gap={2} sx={{ justifyContent: "center" }}>
|
23 |
<Grid item md={4}>
|
24 |
+
<Stack spacing={2}>
|
25 |
+
<Typography>
|
26 |
+
You provide a prompt that describes the game you want, so that your
|
27 |
+
skilled 2D Game Developer can built it for you. The game runs directly
|
28 |
+
in your browser (thanks to JavaScript on Canvas2D).
|
29 |
+
</Typography>
|
30 |
|
31 |
+
<Typography>
|
32 |
+
You are stuck?{" "}
|
33 |
+
<Link
|
34 |
+
href="https://huggingface.co/spaces/failfast/2D-GameCreator-GPT/discussions"
|
35 |
+
target="_blank"
|
36 |
+
rel="noopener"
|
37 |
+
>
|
38 |
+
We are here to help!
|
39 |
+
</Link>
|
40 |
+
</Typography>
|
41 |
+
|
42 |
+
<Typography>
|
43 |
+
We are looking into integrating open-source models (for example{" "}
|
44 |
+
<Link
|
45 |
+
href="https://huggingface.co/HuggingFaceH4/starchat-alpha"
|
46 |
+
target="_blank"
|
47 |
+
rel="noopener"
|
48 |
+
>
|
49 |
+
starchat-alpha
|
50 |
+
</Link>
|
51 |
+
) next, so stay tuned!
|
52 |
+
</Typography>
|
53 |
+
</Stack>
|
54 |
</Grid>
|
55 |
<Grid item md={4}>
|
56 |
<Paper>
|
|
|
77 |
<SmartButtonIcon />
|
78 |
</ListItemIcon>
|
79 |
<ListItemText>
|
80 |
+
Select one of the <b>Examples</b>
|
81 |
</ListItemText>
|
82 |
</ListItem>
|
83 |
<ListItem>
|
|
|
85 |
<PlayArrowIcon />
|
86 |
</ListItemIcon>
|
87 |
<ListItemText>
|
88 |
+
Click on
|
89 |
+
<Button variant="contained" startIcon={<PlayArrow />}>
|
90 |
+
<Typography sx={{ fontWeight: "500" }}>Run</Typography>
|
91 |
+
</Button>
|
92 |
+
|
93 |
</ListItemText>
|
94 |
</ListItem>
|
95 |
</List>
|
src/components/Troubleshooting.tsx
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { Typography, Paper, Alert, Link } from "@mui/material";
|
2 |
+
import { SectionBox, DividerBox } from "./base/boxes";
|
3 |
+
|
4 |
+
export default function Troubleshooting() {
|
5 |
+
return (
|
6 |
+
<>
|
7 |
+
<SectionBox>
|
8 |
+
<Typography component="h3" variant="h2">
|
9 |
+
Troubleshooting
|
10 |
+
</Typography>
|
11 |
+
</SectionBox>
|
12 |
+
|
13 |
+
<Paper sx={{ p: 1 }}>
|
14 |
+
<Alert severity="error" sx={{ fontSize: "1.25rem", mb: 1 }}>
|
15 |
+
Unhandled Runtime Error: SyntaxError: Unexpected identifier
|
16 |
+
</Alert>
|
17 |
+
|
18 |
+
<Typography variant="body1">
|
19 |
+
The generated output was interrupted, as it was too long and the OpenAI API
|
20 |
+
delivered not everything. If you can, switch to GPT-4 as it allows a bigger
|
21 |
+
context size (change it in the options and also increase the max_tokens). If you
|
22 |
+
can't do this, then please help us extend the GameCreator so that it can
|
23 |
+
also resume when the output is interrupted.
|
24 |
+
</Typography>
|
25 |
+
</Paper>
|
26 |
+
|
27 |
+
<DividerBox />
|
28 |
+
|
29 |
+
<Paper sx={{ p: 1 }}>
|
30 |
+
<Typography>
|
31 |
+
You need help? Something is not working?{" "}
|
32 |
+
<Link
|
33 |
+
href="https://huggingface.co/spaces/failfast/2D-GameCreator-GPT/discussions"
|
34 |
+
target="_blank"
|
35 |
+
rel="noopener"
|
36 |
+
>
|
37 |
+
Please let us know!
|
38 |
+
</Link>
|
39 |
+
</Typography>
|
40 |
+
</Paper>
|
41 |
+
</>
|
42 |
+
);
|
43 |
+
}
|
src/components/{Instructions.tsx → UnderTheHood.tsx}
RENAMED
@@ -2,7 +2,7 @@ import { Alert, Link, List, ListItem, ListItemText, Paper, Typography } from "@m
|
|
2 |
import { DividerBox, SectionBox, OutlinedBox } from "@/components/base/boxes";
|
3 |
import { systemMessage } from "@/constants";
|
4 |
|
5 |
-
export default function
|
6 |
return (
|
7 |
<>
|
8 |
<DividerBox />
|
@@ -83,41 +83,6 @@ TEMPLATE:`}
|
|
83 |
</ListItem>
|
84 |
</List>
|
85 |
</Paper>
|
86 |
-
|
87 |
-
<SectionBox>
|
88 |
-
<Typography component="h3" variant="h2">
|
89 |
-
Troubleshooting
|
90 |
-
</Typography>
|
91 |
-
</SectionBox>
|
92 |
-
|
93 |
-
<Paper sx={{ p: 1 }}>
|
94 |
-
<Alert severity="error" sx={{ fontSize: "1.25rem", mb: 1 }}>
|
95 |
-
Unhandled Runtime Error: SyntaxError: Unexpected identifier
|
96 |
-
</Alert>
|
97 |
-
|
98 |
-
<Typography variant="body1">
|
99 |
-
The generated output was interrupted, as it was too long and the OpenAI API
|
100 |
-
delivered not everything. If you can, switch to GPT-4 as it allows a bigger
|
101 |
-
context size (change it in the options and also increase the max_tokens). If you
|
102 |
-
can't do this, then please help us extend the GameCreator so that it can
|
103 |
-
also resume when the output is interrupted.
|
104 |
-
</Typography>
|
105 |
-
</Paper>
|
106 |
-
|
107 |
-
<DividerBox />
|
108 |
-
|
109 |
-
<Paper sx={{ p: 1 }}>
|
110 |
-
<Typography>
|
111 |
-
You need help? Something is not working?{" "}
|
112 |
-
<Link
|
113 |
-
href="https://huggingface.co/spaces/failfast/2D-GameCreator-GPT/discussions"
|
114 |
-
target="_blank"
|
115 |
-
rel="noopener"
|
116 |
-
>
|
117 |
-
Please let us know!
|
118 |
-
</Link>
|
119 |
-
</Typography>
|
120 |
-
</Paper>
|
121 |
</>
|
122 |
);
|
123 |
}
|
|
|
2 |
import { DividerBox, SectionBox, OutlinedBox } from "@/components/base/boxes";
|
3 |
import { systemMessage } from "@/constants";
|
4 |
|
5 |
+
export default function UnderTheHood() {
|
6 |
return (
|
7 |
<>
|
8 |
<DividerBox />
|
|
|
83 |
</ListItem>
|
84 |
</List>
|
85 |
</Paper>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
</>
|
87 |
);
|
88 |
}
|
src/components/base/boxes.tsx
CHANGED
@@ -1,8 +1,17 @@
|
|
1 |
-
import {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
import { styled } from "@mui/material/styles";
|
3 |
|
4 |
export const SectionBox = styled(Paper)<PaperProps>(({ theme }) => ({
|
5 |
display: "flex",
|
|
|
|
|
6 |
padding: 15,
|
7 |
paddingTop: 30,
|
8 |
paddingBottom: 30,
|
@@ -26,6 +35,12 @@ export const RainbowBox = styled("div")(({ theme }) => ({
|
|
26 |
borderImageSlice: 1,
|
27 |
}));
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
export const DividerBox = styled(Divider)<DividerProps>(({ theme }) => ({
|
30 |
marginTop: 20,
|
31 |
marginBottom: 20,
|
|
|
1 |
+
import {
|
2 |
+
Divider,
|
3 |
+
DividerProps,
|
4 |
+
ListItemButton,
|
5 |
+
ListItemButtonProps,
|
6 |
+
Paper,
|
7 |
+
PaperProps,
|
8 |
+
} from "@mui/material";
|
9 |
import { styled } from "@mui/material/styles";
|
10 |
|
11 |
export const SectionBox = styled(Paper)<PaperProps>(({ theme }) => ({
|
12 |
display: "flex",
|
13 |
+
flexDirection: "column",
|
14 |
+
gap: 10,
|
15 |
padding: 15,
|
16 |
paddingTop: 30,
|
17 |
paddingBottom: 30,
|
|
|
35 |
borderImageSlice: 1,
|
36 |
}));
|
37 |
|
38 |
+
export const RainbowListItemButton = styled(ListItemButton)<ListItemButtonProps>(({ theme }) => ({
|
39 |
+
border: `1px solid transparent`,
|
40 |
+
borderImage: `linear-gradient(to bottom right, #b827fc 0%, #2c90fc 25%, #b8fd33 50%, #fec837 75%, #fd1892 100%)`,
|
41 |
+
borderImageSlice: 1,
|
42 |
+
}));
|
43 |
+
|
44 |
export const DividerBox = styled(Divider)<DividerProps>(({ theme }) => ({
|
45 |
marginTop: 20,
|
46 |
marginBottom: 20,
|
src/components/title.tsx
CHANGED
@@ -13,7 +13,7 @@ export default function Title() {
|
|
13 |
p: 4,
|
14 |
}}
|
15 |
>
|
16 |
-
<Typography variant="h1" component="h1">
|
17 |
2D GameCreator-GPT
|
18 |
</Typography>
|
19 |
|
|
|
13 |
p: 4,
|
14 |
}}
|
15 |
>
|
16 |
+
<Typography variant="h1" component="h1" sx={{ fontSize: { xs: "2em", md: "5em" } }}>
|
17 |
2D GameCreator-GPT
|
18 |
</Typography>
|
19 |
|
src/lib/theme.ts
CHANGED
@@ -58,6 +58,18 @@ const theme = extendTheme({
|
|
58 |
},
|
59 |
},
|
60 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
},
|
62 |
});
|
63 |
|
|
|
58 |
},
|
59 |
},
|
60 |
},
|
61 |
+
MuiButton: {
|
62 |
+
styleOverrides: {
|
63 |
+
startIcon: ({ ownerState }) => ({
|
64 |
+
...(ownerState.children
|
65 |
+
? {}
|
66 |
+
: {
|
67 |
+
// if no button label, center icon (e.g mobile)
|
68 |
+
marginRight: 0,
|
69 |
+
}),
|
70 |
+
}),
|
71 |
+
},
|
72 |
+
},
|
73 |
},
|
74 |
});
|
75 |
|
src/pages/index.tsx
CHANGED
@@ -4,10 +4,11 @@ import { Container } from "@mui/material";
|
|
4 |
import Footer from "@/components/footer";
|
5 |
import Title from "@/components/title";
|
6 |
import Introduction from "@/components/Introduction";
|
7 |
-
import
|
8 |
import Examples from "@/components/Examples";
|
9 |
import GameCreator from "@/components/GameCreator";
|
10 |
-
import
|
|
|
11 |
|
12 |
export default function Home() {
|
13 |
return (
|
@@ -24,9 +25,11 @@ export default function Home() {
|
|
24 |
|
25 |
<Examples />
|
26 |
|
27 |
-
<
|
28 |
|
29 |
-
<
|
|
|
|
|
30 |
|
31 |
<Footer />
|
32 |
</Container>
|
|
|
4 |
import Footer from "@/components/footer";
|
5 |
import Title from "@/components/title";
|
6 |
import Introduction from "@/components/Introduction";
|
7 |
+
import UnderTheHood from "@/components/UnderTheHood";
|
8 |
import Examples from "@/components/Examples";
|
9 |
import GameCreator from "@/components/GameCreator";
|
10 |
+
import HowToUse from "@/components/HowToUse";
|
11 |
+
import Troubleshooting from "@/components/Troubleshooting";
|
12 |
|
13 |
export default function Home() {
|
14 |
return (
|
|
|
25 |
|
26 |
<Examples />
|
27 |
|
28 |
+
<HowToUse />
|
29 |
|
30 |
+
<UnderTheHood />
|
31 |
+
|
32 |
+
<Troubleshooting />
|
33 |
|
34 |
<Footer />
|
35 |
</Container>
|
src/services/api/index.ts
CHANGED
@@ -11,6 +11,7 @@ interface ToOpenAIProps {
|
|
11 |
model: string;
|
12 |
maxTokens: string;
|
13 |
client: OpenAIApi | null;
|
|
|
14 |
}
|
15 |
|
16 |
export async function toOpenAI({
|
@@ -21,6 +22,7 @@ export async function toOpenAI({
|
|
21 |
model = "gpt-3.5-turbo",
|
22 |
maxTokens = "2048",
|
23 |
client = null,
|
|
|
24 |
}: ToOpenAIProps) {
|
25 |
if (client === null) {
|
26 |
throw new Error("OpenAI client is not defined");
|
@@ -50,12 +52,15 @@ export async function toOpenAI({
|
|
50 |
];
|
51 |
|
52 |
try {
|
53 |
-
const response = await client.createChatCompletion(
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
59 |
|
60 |
const { message } = response.data.choices[0];
|
61 |
|
|
|
11 |
model: string;
|
12 |
maxTokens: string;
|
13 |
client: OpenAIApi | null;
|
14 |
+
signal?: AbortSignal;
|
15 |
}
|
16 |
|
17 |
export async function toOpenAI({
|
|
|
22 |
model = "gpt-3.5-turbo",
|
23 |
maxTokens = "2048",
|
24 |
client = null,
|
25 |
+
signal,
|
26 |
}: ToOpenAIProps) {
|
27 |
if (client === null) {
|
28 |
throw new Error("OpenAI client is not defined");
|
|
|
52 |
];
|
53 |
|
54 |
try {
|
55 |
+
const response = await client.createChatCompletion(
|
56 |
+
{
|
57 |
+
model,
|
58 |
+
messages,
|
59 |
+
max_tokens: Number.parseInt(maxTokens),
|
60 |
+
temperature: Number.parseFloat(temperature),
|
61 |
+
},
|
62 |
+
{ signal }
|
63 |
+
);
|
64 |
|
65 |
const { message } = response.data.choices[0];
|
66 |
|
src/services/api/openai.ts
CHANGED
@@ -1,5 +1,10 @@
|
|
1 |
import { Configuration, OpenAIApi } from "openai";
|
2 |
|
3 |
export const createClient = (apiKey: string): OpenAIApi => {
|
4 |
-
|
|
|
|
|
|
|
|
|
|
|
5 |
};
|
|
|
1 |
import { Configuration, OpenAIApi } from "openai";
|
2 |
|
3 |
export const createClient = (apiKey: string): OpenAIApi => {
|
4 |
+
const configuration = new Configuration({ apiKey });
|
5 |
+
|
6 |
+
// See https://github.com/openai/openai-node/issues/6#issuecomment-1492814621
|
7 |
+
delete configuration.baseOptions.headers["User-Agent"];
|
8 |
+
|
9 |
+
return new OpenAIApi(configuration);
|
10 |
};
|