(null);
61 | React.useEffect(() => {
62 | if (open) {
63 | const { current: descriptionElement } = descriptionElementRef;
64 | if (descriptionElement !== null) {
65 | descriptionElement.focus();
66 | }
67 | }
68 | }, [open]);
69 |
70 | return (
71 |
72 |
73 |
117 |
118 | );
119 | }
--------------------------------------------------------------------------------
/src/components/SharePopup.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DialogTitle from "@material-ui/core/DialogTitle";
3 | import {
4 | Box,
5 | FormControlLabel,
6 | IconButton,
7 | Theme,
8 | Typography,
9 | FormGroup,
10 | Switch,
11 | Button, CircularProgress, TextField
12 | } from "@material-ui/core";
13 | import CloseIcon from "@material-ui/icons/Close";
14 | import DialogContent from "@material-ui/core/DialogContent";
15 | import Dialog from "@material-ui/core/Dialog";
16 | import {makeStyles} from "@material-ui/core/styles";
17 | import {
18 | selectCompletionParameters, selectExamples,
19 | } from "../slices/editorSlice";
20 | import SharedPrompt from '../resources/SharedPrompt';
21 | import {useSelector} from "react-redux";
22 | import {green} from "@material-ui/core/colors";
23 |
24 | const useStyles = makeStyles((theme: Theme) => ({
25 | closeButton: {
26 | position: 'absolute',
27 | right: theme.spacing(1),
28 | top: theme.spacing(1),
29 | color: theme.palette.grey[500],
30 | },
31 | buttonProgress: {
32 | color: green[500],
33 | position: 'absolute',
34 | top: '50%',
35 | left: '50%',
36 | marginTop: -12,
37 | marginLeft: -12,
38 | },
39 | }));
40 |
41 |
42 | export default function SharePopup() {
43 | const classes = useStyles();
44 |
45 | const [open, setOpen] = React.useState(true);
46 | const [loading, setLoading] = React.useState(false);
47 | const [link, setLink] = React.useState(undefined);
48 | const [includeExamples, setIncludeExamples] = React.useState(true);
49 |
50 | const completionParameters = useSelector(selectCompletionParameters);
51 | const examples = useSelector(selectExamples);
52 |
53 | const handleClose = () => {
54 | setLink(undefined);
55 | setOpen(false);
56 | };
57 |
58 | return ;
122 | }
--------------------------------------------------------------------------------
/src/migrations.ts:
--------------------------------------------------------------------------------
1 | import uniqid from "uniqid";
2 |
3 | export const migrations = {
4 | 0: (state: any) => {
5 | return {
6 | ...state,
7 | editor: {
8 | ...state.editor,
9 | maxCreativeCompletions: 10,
10 | creativeCompletions: []
11 | }
12 | };
13 | },
14 | 1: (state: any) => {
15 | return {
16 | ...state,
17 | editor: {
18 | ...state.editor,
19 | showPromptForCreativeCompletions: true,
20 | }
21 | };
22 | },
23 | 2: (state: any) => {
24 | return {
25 | ...state,
26 | editor: {
27 | ...state.editor,
28 | tabIndex: 0
29 | }
30 | };
31 | },
32 | 3: (state: any) => {
33 | return {
34 | ...state,
35 | editor: {
36 | ...state.editor,
37 | stopSymbols: []
38 | }
39 | };
40 | },
41 | 4: (state: any) => {
42 | return {
43 | ...state,
44 | editor: {
45 | ...state.editor,
46 | topP: 1,
47 | frequencyPenalty: 0,
48 | presencePenalty: 0,
49 | }
50 | };
51 | },
52 | 5: (state: any) => {
53 | return {
54 | ...state,
55 | editor: {
56 | ...state.editor,
57 | creativeCompletions: state.creativeCompletions.map((completion: any) => ({
58 | ...completion,
59 | topP: 1,
60 | frequencyPenalty: 0,
61 | presencePenalty: 0,
62 | }))
63 | }
64 | };
65 | },
66 | 6: (state: any) => {
67 | return {
68 | ...state,
69 | editor: {
70 | ...state.editor,
71 | showExamplePreviousOutputs: false
72 | }
73 | };
74 | },
75 | 7: (state: any) => {
76 | return {
77 | ...state,
78 | editor: {
79 | past: [],
80 | future: [],
81 | present: {...state.editor}
82 | }
83 | };
84 | },
85 | 8: (state: any) => {
86 | return {
87 | ...state,
88 | editor: {
89 | ...state.editor,
90 | present: {
91 | ...state.editor.present,
92 | modelName: 'davinci'
93 | }
94 | }
95 | }
96 | },
97 | 9: (state: any) => {
98 | return {
99 | ...state,
100 | editor: {
101 | ...state.editor,
102 | present: {
103 | ...state.editor.present,
104 | conversations: []
105 | }
106 | }
107 | }
108 | },
109 |
110 | 10: (state: any) => {
111 | return {
112 | ...state,
113 | editor: {
114 | ...state.editor,
115 | present: {
116 | ...state.editor.present,
117 | loadingVariations: state.editor.present.loadingCreativeCompletions,
118 | variations: state.editor.present.creativeCompletions,
119 | maxVariations: state.editor.present.maxCreativeCompletions,
120 | showPromptForVariations: state.editor.present.showPromptForCreativeCompletions
121 | }
122 | }
123 | }
124 | },
125 |
126 | 12: (state: any) => {
127 | return {
128 | ...state,
129 | editor: {
130 | ...state.editor,
131 | present: {
132 | ...state.editor.present,
133 | currentWorkspaceId: 'first_workspace',
134 | workspaces: [{
135 | id: 'first_workspace',
136 | prompt: "Click Explore Templates -> Song Generation for a fun example!",
137 | // prompt: "Input: Anna and Mike is going skiing.\n" +
138 | // "Output: Anna and Mike are going skiing.\n" +
139 | // "Input: Anna and Pat are married; he has been together for 20 years.\n" +
140 | // "Output: Anna and Pat are married; they have been together for 20 years.\n" +
141 | // "Input: I walk to the store and I bought milk.\n" +
142 | // "Output: I walked to the store and I bought milk.\n" +
143 | // "Input: {example}\n" +
144 | // "Output:",
145 | modelName: 'davinci',
146 | temperature: 0.8,
147 | topP: 1,
148 | frequencyPenalty: 0,
149 | presencePenalty: 0,
150 | // stopSymbols: ["\\n"],
151 | stopSymbols: [],
152 | maxTokens: 80,
153 | tabIndex: 0,
154 |
155 | showExamplePreviousOutputs: false,
156 | examples: [
157 | {id: uniqid("input_"), text: "We all eat the fish and then made dessert.", output: "We all ate the fish and then made dessert.", isLoading: false},
158 | {id: uniqid("input_"), text: "I like ski every day.", output: "I like skiing every day.", isLoading: false},
159 | ],
160 |
161 | loadingVariations: false,
162 | variations: [],
163 | maxVariations: 2,
164 | showPromptForVariations: true,
165 |
166 | conversations: [],
167 | }],
168 | }
169 | }
170 | }
171 | },
172 |
173 | 13: (state: any) => {
174 | return {
175 | ...state,
176 | editor: {
177 | ...state.editor,
178 | present: {
179 | ...state.editor.present,
180 | workspaces: state.editor.present.workspaces.map((workspace: any) => ({
181 | ...workspace,
182 | name: 'Draft #1'
183 | })),
184 | }
185 | }
186 | }
187 | },
188 |
189 | 14: (state: any) => {
190 | return {
191 | ...state,
192 | editor: {
193 | ...state.editor,
194 | present: {
195 | ...state.editor.present,
196 | workspaces: state.editor.present.workspaces.map((workspace: any) => ({
197 | ...workspace,
198 | basic: {
199 | output: '',
200 | loading: false,
201 | }
202 | })),
203 | }
204 | }
205 | }
206 | },
207 |
208 | 15: (state: any) => {
209 | return {
210 | ...state,
211 | editor: {
212 | ...state.editor,
213 | present: {
214 | ...state.editor.present,
215 | editableWorkspaceName: state.editor.present.workspaces.find((w: any) => w.id === state.editor.present.currentWorkspaceId).name
216 | }
217 | }
218 | }
219 | },
220 | };
221 |
222 | export const currentVersion = 15;
223 |
--------------------------------------------------------------------------------
/src/components/conversations/Conversation.tsx:
--------------------------------------------------------------------------------
1 | import React, {createRef, useEffect} from "react";
2 | import {Card, CardActions, CardContent, Typography, TextField, Grid, Box, Paper, AccordionDetails, AccordionSummary, Accordion, IconButton} from "@material-ui/core";
3 | import {makeStyles, Theme} from "@material-ui/core/styles";
4 | import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
5 | import { RootState } from "../../store";
6 | import {useDispatch, useSelector} from "react-redux";
7 | import {
8 | ConversationPartSource,
9 | selectPrompt,
10 | deleteConversation, selectCompletionParameters, updateConversationRestartSequence, updateConversationStartSequence,
11 | } from "../../slices/editorSlice";
12 | import {Delete} from "@material-ui/icons";
13 | import CompletionParameters from "./CompletionParameters";
14 | import Input from "./Input";
15 |
16 | interface Props {
17 | id: string;
18 | ind: number;
19 | }
20 |
21 | const useStyles = makeStyles((theme: Theme) => ({
22 | card: {
23 | backgroundColor: theme.palette.background.default,
24 | width: '100%',
25 | },
26 | settingField: {
27 | minWidth: '250px',
28 | },
29 | generatedText: {
30 | whiteSpace: 'pre-line',
31 | display: 'inline',
32 | fontWeight: 800,
33 | },
34 | promptedText: {
35 | whiteSpace: 'pre-line',
36 | display: 'inline',
37 | fontWeight: 400,
38 | },
39 | conversationBox: {
40 | minHeight: '400px',
41 | maxHeight: '400px',
42 | overflowY: 'scroll'
43 | },
44 | responseInput: {
45 | width: '100%'
46 | }
47 | }));
48 |
49 | export default function Conversation(props: Props) {
50 | const styles = useStyles();
51 | const dispatch = useDispatch();
52 | const prompt = useSelector(selectPrompt);
53 | const globalCompletionParameters = useSelector(selectCompletionParameters);
54 | const conversation = useSelector((state: RootState) => {
55 | const workspace = state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!;
56 | return workspace.conversations.find(c => c.id === props.id)!;
57 | });
58 |
59 | const hasStarted = conversation.parts.some(c => c.submitted);
60 |
61 | useEffect(() => {
62 | conversationBottom.current!.scrollTop = conversationBottom.current!.scrollHeight;
63 | });
64 |
65 | const conversationBottom = createRef();
66 |
67 | return
68 |
69 |
70 |
71 | {!hasStarted && (
72 | "New Conversation"
73 | )}
74 | {hasStarted && (
75 |
76 | Conversation #{props.ind}
77 | The prompt and parameters are locked.
78 |
79 | )}
80 |
81 |
82 | {hasStarted && (
83 | {
84 | dispatch(deleteConversation(props.id));
85 | }}>
86 |
87 |
88 | )}
89 |
90 |
91 |
92 |
93 |
94 | {hasStarted && (<>
95 | {conversation.initialPrompt}
96 | {conversation.parts.map(part => (<>
97 | {part.source === ConversationPartSource.gpt && {part.text}}
98 | {part.source === ConversationPartSource.user && {part.text}}
99 | >))}
100 | >)}
101 | {!hasStarted && (<>
102 | {prompt}
103 | {conversation.restartSequence}
104 | >)}
105 |
106 |
107 |
108 |
109 |
110 | {
111 | conversationBottom.current!.scrollTop = conversationBottom.current!.scrollHeight;
112 | }}/>
113 |
114 |
115 |
116 | }
118 | aria-controls="panel1a-content"
119 | id="panel1a-header"
120 | >
121 | Parameters
122 |
123 |
124 |
125 |
126 |
127 | ) => {
130 | dispatch(updateConversationRestartSequence({
131 | conversationId: props.id,
132 | restartSequence: event.currentTarget.value.split('\\n').join('\n')
133 | }));
134 | }}
135 | className={styles.settingField}
136 | label={'Before User Input'}
137 | variant={'outlined'}
138 | />
139 |
140 |
141 | ) => {
144 | dispatch(updateConversationStartSequence({
145 | conversationId: props.id,
146 | startSequence: event.currentTarget.value.split('\\n').join('\n')
147 | }));
148 | }}
149 | className={styles.settingField}
150 | label={'Before GPT-4 Completion'}
151 | variant={'outlined'}
152 | />
153 |
154 |
155 |
156 | {conversation.completionParams === undefined && (
157 |
158 | )}
159 | {conversation.completionParams !== undefined && (
160 |
161 | )}
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 | ;
172 | }
173 |
--------------------------------------------------------------------------------
/src/libs/codeGenerator.ts:
--------------------------------------------------------------------------------
1 | import {TabIndex, Example, CompletionParameters} from "../slices/editorSlice";
2 |
3 | //const HOST = `https://api.openai.com`;
4 | //const HOST = `http://localhost:9000`;
5 | //const HOST = `http://api.gpt4.org:9000`;
6 | const HOST = `https://api.gpt4.org`;
7 |
8 | interface CodeExample {
9 | id: string;
10 | name: string;
11 | text: string;
12 | language: string;
13 | }
14 |
15 | enum PythonOutputType {
16 | plain,
17 | stream,
18 | toxicity
19 | }
20 |
21 | export default function generateCodeExamples(completionParameters: CompletionParameters, tabIndex: TabIndex,
22 | examples: Array): Array {
23 | const exampleText = getFirstExampleOrPlaceholder(examples);
24 | return [
25 | {id: '1', name: "Python", language: "python", text: generatePythonExample(
26 | completionParameters, tabIndex, exampleText, PythonOutputType.plain
27 | )},
28 | {id: '2', name: "Python: Streaming", language: "python", text: generatePythonExample(
29 | completionParameters, tabIndex, exampleText, PythonOutputType.stream
30 | )},
31 | {id: '3', name: "Node.js: Axios", language: "javascript", text: generateNodeJsExample(
32 | completionParameters, tabIndex, exampleText
33 | )},
34 | {id: '4', name: "Typescript: Axios", language: "typescript", text: generateTypescriptExample(
35 | completionParameters, tabIndex, exampleText
36 | )},
37 | {id: '5', name: "Bash", language: "bash", text: generateShellExample(
38 | completionParameters, tabIndex, exampleText
39 | )},
40 |
41 |
42 | //{name: "Python: With Toxicity Check", text: generatePythonExample(
43 | // completionParameters, tabIndex, exampleText, PythonOutputType.toxicity
44 | // )},
45 |
46 | // {name: "Javascript", text: generatePythonExampleWithStream(completionParameters, tabIndex)},
47 | // {name: "Javascript: Client-side Streaming", text: generatePythonExampleWithStream(completionParameters, tabIndex)},
48 |
49 | // {name: "Javascript: With Toxicity Check", text: generatePythonExampleWithStream(completionParameters, tabIndex)},
50 | ];
51 | }
52 |
53 | function generateNodeJsExample(parameters: CompletionParameters, tabIndex: TabIndex, exampleText: string) {
54 | switch (tabIndex) {
55 | case TabIndex.multipleExamples: {
56 | return `var axios = require('axios');
57 |
58 | var example = ${formatJavascriptString(exampleText)};
59 | var config = {
60 | method: 'post',
61 | url: '${HOST}/v1/engines/${parameters.engine}/completions',
62 | headers: {
63 | 'Content-Type': 'application/json',
64 | 'Authorization': 'Bearer ${parameters.apiKey}'
65 | },
66 | data: {
67 | 'echo': true,
68 | 'prompt': ${formatJavascriptString(parameters.prompt)}.replace('{example}', example),
69 | 'max_tokens': ${parameters.maxTokens},
70 | 'temperature': ${parameters.temperature},
71 | 'top_p': ${parameters.topP},
72 | 'n': 1,
73 | 'stop': ${formatStopSymbolsJavascriptStringOrStringList(parameters.stop)},
74 | 'presence_penalty': ${parameters.presencePenalty},
75 | 'frequency_penalty': ${parameters.frequencyPenalty}}
76 | };
77 |
78 | axios(config)
79 | .then(function (response) {
80 | console.log(response.data);
81 | console.log(response.data['choices'][0]['text']);
82 | })
83 | .catch(function (error) {
84 | console.log(error);
85 | });
86 | `;
87 | }
88 | case TabIndex.basic:
89 | case TabIndex.conversations:
90 | case TabIndex.variations: {
91 | return `var axios = require('axios');
92 |
93 | var config = {
94 | method: 'post',
95 | url: '${HOST}/v1/engines/${parameters.engine}/completions',
96 | headers: {
97 | 'Content-Type': 'application/json',
98 | 'Authorization': 'Bearer ${parameters.apiKey}'
99 | },
100 | data: {
101 | 'echo': true,
102 | 'prompt': ${formatJavascriptString(parameters.prompt)},
103 | 'max_tokens': ${parameters.maxTokens},
104 | 'temperature': ${parameters.temperature},
105 | 'top_p': ${parameters.topP},
106 | 'n': 1,
107 | 'stop': ${formatStopSymbolsJavascriptStringOrStringList(parameters.stop)},
108 | 'presence_penalty': ${parameters.presencePenalty},
109 | 'frequency_penalty': ${parameters.frequencyPenalty}}
110 | };
111 |
112 | axios(config)
113 | .then(function (response) {
114 | console.log(response.data);
115 | console.log(response.data['choices'][0]['text']);
116 | })
117 | .catch(function (error) {
118 | console.log(error);
119 | });
120 | `;
121 | }
122 | }
123 |
124 | return '';
125 | }
126 |
127 | function generateTypescriptExample(parameters: CompletionParameters, tabIndex: TabIndex, exampleText: string) {
128 | switch (tabIndex) {
129 | case TabIndex.multipleExamples: {
130 | return `import axios from 'axios'
131 |
132 | const example = ${formatJavascriptString(exampleText)}
133 |
134 | axios({
135 | method: 'post',
136 | url: '${HOST}/v1/engines/${parameters.engine}/completions',
137 | headers: {
138 | 'Content-Type': 'application/json',
139 | 'Authorization': 'Bearer ${parameters.apiKey}'
140 | },
141 | data: {
142 | 'echo': true,
143 | 'prompt': ${formatJavascriptString(parameters.prompt)}.replace('{example}', example),
144 | 'max_tokens': ${parameters.maxTokens},
145 | 'temperature': ${parameters.temperature},
146 | 'top_p': ${parameters.topP},
147 | 'n': 1,
148 | 'stop': ${formatStopSymbolsJavascriptStringOrStringList(parameters.stop)},
149 | 'presence_penalty': ${parameters.presencePenalty},
150 | 'frequency_penalty': ${parameters.frequencyPenalty}}
151 | })
152 | .then(response => {
153 | console.log(response.data)
154 | console.log(response.data['choices'][0]['text'])
155 | })
156 | .catch(error => {
157 | console.log(error)
158 | });
159 | `;
160 | }
161 | case TabIndex.basic:
162 | case TabIndex.conversations:
163 | case TabIndex.variations: {
164 | return `import axios from 'axios'
165 |
166 | axios({
167 | method: 'post',
168 | url: '${HOST}/v1/engines/${parameters.engine}/completions',
169 | headers: {
170 | 'Content-Type': 'application/json',
171 | 'Authorization': 'Bearer ${parameters.apiKey}'
172 | },
173 | data: {
174 | 'echo': true,
175 | 'prompt': ${formatJavascriptString(parameters.prompt)},
176 | 'max_tokens': ${parameters.maxTokens},
177 | 'temperature': ${parameters.temperature},
178 | 'top_p': ${parameters.topP},
179 | 'n': 1,
180 | 'stop': ${formatStopSymbolsJavascriptStringOrStringList(parameters.stop)},
181 | 'presence_penalty': ${parameters.presencePenalty},
182 | 'frequency_penalty': ${parameters.frequencyPenalty}}
183 | })
184 | .then(function (response) {
185 | console.log(response.data)
186 | console.log(response.data['choices'][0]['text'])
187 | })
188 | .catch(function (error) {
189 | console.log(error)
190 | });
191 | `;
192 | }
193 | }
194 |
195 | return '';
196 | }
197 |
198 | function generateShellExample(parameters: CompletionParameters, tabIndex: TabIndex, exampleText: string) {
199 | switch (tabIndex) {
200 | case TabIndex.multipleExamples: {
201 | return `curl --location --request POST '${HOST}/v1/engines/davinci/completions' \\
202 | --header 'Content-Type: application/json' \\
203 | --header 'Authorization: Bearer ${parameters.apiKey}' \\
204 | --data-raw '${replaceAllOccurrences(JSON.stringify({
205 | 'echo': true,
206 | 'prompt': parameters.prompt.replace('{example}', exampleText),
207 | 'max_tokens': parameters.maxTokens,
208 | 'temperature': parameters.temperature,
209 | 'top_p': parameters.topP,
210 | 'n': 1,
211 | 'stop': formatStopSymbolsForShell(parameters.stop),
212 | 'presence_penalty': parameters.presencePenalty,
213 | 'frequency_penalty': parameters.frequencyPenalty
214 | }, null, 1), "'", "\\'")}'`;
215 | }
216 | case TabIndex.basic:
217 | case TabIndex.conversations:
218 | case TabIndex.variations: {
219 | return `curl --location --request POST '${HOST}/v1/engines/davinci/completions' \\
220 | --header 'Content-Type: application/json' \\
221 | --header 'Authorization: Bearer ${parameters.apiKey}' \\
222 | --data-raw '${replaceAllOccurrences(JSON.stringify({
223 | 'echo': true,
224 | 'prompt': parameters.prompt,
225 | 'max_tokens': parameters.maxTokens,
226 | 'temperature': parameters.temperature,
227 | 'top_p': parameters.topP,
228 | 'n': 1,
229 | 'stop': formatStopSymbolsForShell(parameters.stop),
230 | 'presence_penalty': parameters.presencePenalty,
231 | 'frequency_penalty': parameters.frequencyPenalty
232 | }, null, 1), "'", "\\'")}'`;
233 | }
234 | }
235 |
236 | return '';
237 | }
238 |
239 | function generatePythonExample(parameters: CompletionParameters, tabIndex: TabIndex, exampleText: string,
240 | outputType: PythonOutputType) {
241 | let completionVariableName, additionalArguments, outputCode;
242 | switch (outputType) {
243 | case PythonOutputType.plain: {
244 | completionVariableName = 'completion';
245 | additionalArguments = '';
246 | outputCode = `choice = completion["choices"][0]
247 | print("[choice object]", choice)
248 | print("[choice text]", choice["text"])`;
249 | break;
250 | }
251 | case PythonOutputType.stream: {
252 | completionVariableName = 'parts';
253 | additionalArguments = `
254 | stream=True`;
255 | outputCode = `for completion in parts:
256 | choice = completion["choices"][0]
257 | print("[choice object]", choice)
258 | print("[choice text]", choice["text"])`;
259 | break;
260 | }
261 | case PythonOutputType.toxicity: {
262 | completionVariableName = 'completion';
263 | additionalArguments = '';
264 | outputCode = `choice = completion["choices"][0]
265 | print("[choice object]", choice)
266 | print("[choice text]", choice["text"])
267 |
268 | filter_completion = openai.Completion.create(
269 | engine="davinci",
270 | max_tokens=1,
271 | prompt=f"<|endoftext|>{choice['text']}\\n--\\nLabel: ",
272 | temperature=0.0,
273 | top_p=0,
274 | )
275 | filter_result = completion["choices"][0]["text"]
276 | if filter_result == "0":
277 | print("[content status] safe")
278 | if filter_result == "1":
279 | print("[content status] non-toxic warning")
280 | if filter_result == "2":
281 | print("[content status] toxic")`;
282 | break;
283 | }
284 |
285 | }
286 | switch (tabIndex) {
287 | case TabIndex.multipleExamples: {
288 | return `import openai
289 | openai.api_key = "${parameters.apiKey}"
290 | prompt = ${formatPythonString(parameters.prompt)}
291 | example = ${formatPythonString(exampleText)}
292 | ${completionVariableName} = openai.Completion.create(
293 | engine="${parameters.engine}",
294 | n=1,
295 | max_tokens=${parameters.maxTokens},
296 | stop=${formatStopSymbolsPythonStringOrStringList(parameters.stop)},
297 | prompt=prompt.replace("{example}", example),
298 | temperature=${parameters.temperature},
299 | top_p=${parameters.topP},
300 | presence_penalty=${parameters.presencePenalty},
301 | frequency_penalty=${parameters.frequencyPenalty},${additionalArguments}
302 | )
303 | ${outputCode}
304 | `;
305 | }
306 | case TabIndex.basic:
307 | case TabIndex.conversations:
308 | case TabIndex.variations: {
309 | return `import openai
310 | openai.api_key = "${parameters.apiKey}"
311 | ${completionVariableName} = openai.Completion.create(
312 | engine="${parameters.engine}",
313 | n=1,
314 | max_tokens=${parameters.maxTokens},
315 | stop=${formatStopSymbolsPythonStringOrStringList(parameters.stop)},
316 | prompt=${formatPythonString(parameters.prompt)},
317 | temperature=${parameters.temperature},
318 | top_p=${parameters.topP},
319 | presence_penalty=${parameters.presencePenalty},
320 | frequency_penalty=${parameters.frequencyPenalty},
321 | echo=True,${additionalArguments}
322 | )
323 | ${outputCode}
324 | `;
325 | }
326 | }
327 |
328 | return '';
329 | }
330 |
331 | // Shell helpers
332 |
333 | function formatStopSymbolsForShell(value: Array | string) {
334 | if (value instanceof Array) {
335 | return value.map(formatStopSymbolStringForCode);
336 | } else {
337 | return formatStopSymbolStringForCode(value);
338 | }
339 | }
340 |
341 | // Javascript helpers
342 |
343 | function formatJavascriptString(value: string) {
344 | if (value.includes("\n")) {
345 | const formattedString = replaceAllOccurrences(value,'`', '\\`');
346 | return `\`${formattedString}\``;
347 | } else {
348 | const formattedString = replaceAllOccurrences(value, "'", "\\'");
349 | return `'${formattedString}'`;
350 | }
351 | }
352 |
353 | function formatStopSymbolsJavascriptStringOrStringList(value: Array | string) {
354 | if (value instanceof Array) {
355 | return formatJavascriptStringList(value.map(formatStopSymbolStringForCode));
356 | } else {
357 | return formatJavascriptString(formatStopSymbolStringForCode(value));
358 | }
359 | }
360 |
361 | function formatJavascriptStringList(value: Array) {
362 | return `[${value.map(value => `'${replaceAllOccurrences(value, "'", "\\'")}'`).join(', ')}]`;
363 | }
364 |
365 | // Python helpers
366 |
367 | function formatStopSymbolsPythonStringOrStringList(value: Array | string) {
368 | if (value instanceof Array) {
369 | return formatPythonStringList(value.map(formatStopSymbolStringForCode));
370 | } else {
371 | return formatPythonString(formatStopSymbolStringForCode(value));
372 | }
373 | }
374 |
375 | function formatPythonStringList(value: Array) {
376 | return `[${value.map(value => `"${value}"`).join(', ')}]`;
377 | }
378 |
379 | function formatPythonString(value: string) {
380 | if (value.includes("\n")) {
381 | const formattedString = replaceAllOccurrences(value, '"""', '\\"\\"\\"');
382 | return `"""${formattedString}"""`;
383 | } else {
384 | const formattedString = replaceAllOccurrences(value, '"', '\\"');
385 | return `"${formattedString}"`;
386 | }
387 | }
388 |
389 | // Common helpers
390 |
391 | function getFirstExampleOrPlaceholder(examples: Array): string {
392 | if (examples.length > 0 && examples[0].text.length > 0) {
393 | return examples[0].text;
394 | }
395 | return 'example';
396 | }
397 |
398 | function formatStopSymbolStringForCode(value: string) {
399 | return `${replaceAllOccurrences(value, '\n', '\\n')}`;
400 | }
401 |
402 | function replaceAllOccurrences(value: string, replace_from: string, replace_to: string) {
403 | return value.split(replace_from).join(replace_to);
404 | }
405 |
406 |
407 |
--------------------------------------------------------------------------------
/src/components/PromptEditor.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {useDispatch, useSelector} from "react-redux";
3 | import {
4 | Typography,
5 | Slider,
6 | TextField,
7 | Grid,
8 | Tooltip,
9 | Card,
10 | CardContent,
11 | Select,
12 | Box
13 | } from "@material-ui/core";
14 | import ChipInput from 'material-ui-chip-input'
15 | import {
16 | selectPrompt,
17 | editPrompt,
18 | selectTemperature,
19 | editTemperature,
20 | selectMaxTokens,
21 | editMaxTokens,
22 | selectStopSymbols,
23 | addStopSymbol,
24 | deleteStopSymbol,
25 | editTopP,
26 | editFrequencyPenalty,
27 | editPresencePenalty,
28 | selectTopP,
29 | selectFrequencyPenalty, selectPresencePenalty, selectModelName, editModelName
30 | } from "../slices/editorSlice";
31 | import {makeStyles} from "@material-ui/styles";
32 | import ModeTabs from "./ModeTabs";
33 | import WorkspaceForm from "./WorkspaceForm";
34 |
35 | const useStyles = makeStyles({
36 | fullWidth: {
37 | width: '100%',
38 | },
39 | });
40 |
41 | export function PromptEditor() {
42 | const dispatch = useDispatch();
43 | const styles = useStyles();
44 |
45 | const prompt = useSelector(selectPrompt);
46 | const temperature = useSelector(selectTemperature);
47 | const topP = useSelector(selectTopP);
48 | const frequencyPenalty = useSelector(selectFrequencyPenalty);
49 | const presencePenalty = useSelector(selectPresencePenalty);
50 | const maxTokens = useSelector(selectMaxTokens);
51 | const stopSymbols = useSelector(selectStopSymbols);
52 |
53 | const availableModelNames = ['davinci', 'davinci-instruct-beta',
54 | 'curie', 'curie-instruct-beta',
55 | 'babbage',
56 | 'ada'];
57 | const modelName = useSelector(selectModelName);
58 |
59 | const handlePromptChange = (event: React.FormEvent) => {
60 | dispatch(editPrompt(event.currentTarget.value));
61 | }
62 | const handleTemperatureChange = (event: React.ChangeEvent<{}>, value: number | number[]) => {
63 | dispatch(editTemperature(value as number));
64 | }
65 | const handleTopPChange = (event: React.ChangeEvent<{}>, value: number | number[]) => {
66 | dispatch(editTopP(value as number));
67 | }
68 | const handleFrequencyPenaltyChange = (event: React.ChangeEvent<{}>, value: number | number[]) => {
69 | dispatch(editFrequencyPenalty(value as number));
70 | }
71 | const handlePresencePenaltyChange = (event: React.ChangeEvent<{}>, value: number | number[]) => {
72 | dispatch(editPresencePenalty(value as number));
73 | }
74 | const handleMaxTokensChange = (event: React.ChangeEvent<{}>, value: number | number[]) => {
75 | dispatch(editMaxTokens(value as number));
76 | }
77 | const handleModelNameChange = (event: any) => {
78 | dispatch(editModelName(event.target.value));
79 | }
80 |
81 | return (
82 |
83 |
90 |
91 | {/*
92 |
93 |
94 |
95 |
96 |
101 |
102 |
108 |
109 |
110 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
124 | ) => {
130 | dispatch(editApiKey(event.currentTarget.value));
131 | }}
132 | inputProps={{
133 | autoComplete: 'new-password',
134 | form: {
135 | autoComplete: 'off',
136 | },
137 | }}
138 | className={styles.fullWidth}
139 | />
140 |
141 |
142 |
143 |
144 |
145 | */}
146 |
147 |
148 |
149 |
150 | Workspace
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 | Parameters
160 |
161 |
163 |
164 | Temperature: {temperature}
165 |
166 |
167 |
184 |
185 | Response length: {maxTokens}
186 |
187 |
204 |
205 |
206 |
207 | Stop sequences:
208 |
209 |
210 | dispatch(addStopSymbol(chip))}
213 | onDelete={(deletedChip) => dispatch(deleteStopSymbol(deletedChip))}
214 | onBeforeAdd={() => stopSymbols.length !== 4}
215 | newChipKeys={['Tab']}
216 | className={styles.fullWidth}
217 | />
218 |
219 |
220 |
221 |
222 | Advanced parameters
223 |
224 |
225 |
226 | Top P: {topP}
227 |
228 |
229 |
246 |
247 |
248 | Frequency Penalty: {frequencyPenalty}
249 |
250 |
251 |
268 |
269 |
270 | Presence Penalty: {presencePenalty}
271 |
272 |
273 |
290 |
291 | Model name:
292 |
293 |
298 |
299 |
300 |
301 |
302 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 | );
321 | }
--------------------------------------------------------------------------------
/src/libs/templatesLibrary.ts:
--------------------------------------------------------------------------------
1 | import {uniqueId} from "lodash";
2 | import {LoadTemplateActionPayload, TabIndex} from '../slices/editorSlice';
3 |
4 | export interface Template {
5 | id: string;
6 | name: string;
7 | actionPayload: LoadTemplateActionPayload;
8 | }
9 |
10 | interface TemplateGroup {
11 | name: string;
12 | templates: Array;
13 | }
14 |
15 | const templateGroups = [
16 | {name: 'Simple', templates: [
17 | {
18 | id: uniqueId('template_'),
19 | name: 'Top 10 Women',
20 | actionPayload: {
21 | prompt: 'Top 10 most important women in human history, and their greatest achievements:\n' +
22 | '\n' +
23 | '1.',
24 | stopSymbols: ['11.'],
25 | tabIndex: TabIndex.basic,
26 | examples: []
27 | }
28 | },
29 | {
30 | id: uniqueId('template_'),
31 | name: 'Email Generation',
32 | actionPayload: {
33 | prompt: 'The following email explains two things:\n' +
34 | '1) The writer, Andy, is going to miss work.\n' +
35 | '2) The receiver, Betty, is Andy\'s boss and can email if anything needs to be done.\n' +
36 | '\n' +
37 | 'From: ',
38 | stopSymbols: [],
39 | tabIndex: TabIndex.basic,
40 | examples: []
41 | },
42 | },
43 | {
44 | id: uniqueId('template_'),
45 | name: 'Federalist Paper (Memory)',
46 | actionPayload: {
47 | prompt: 'FEDERALIST No. 79. The Judiciary Continued\n' +
48 | '\n' +
49 | 'HAMILTON\n' +
50 | '\n' +
51 | 'To the People of the State of New York.\n' +
52 | '\n' +
53 | 'IN THE course of the preceding papers,',
54 | stopSymbols: [],
55 | tabIndex: TabIndex.basic,
56 | examples: []
57 | },
58 | },
59 | {
60 | id: uniqueId('template_'),
61 | name: 'Simple Math',
62 | actionPayload: {
63 | prompt: '2 * 4 =',
64 | stopSymbols: ['\\n'],
65 | tabIndex: TabIndex.basic,
66 | examples: []
67 | },
68 | }
69 | ]},
70 | {name: 'Examples', templates: [
71 | {id: uniqueId('template_'), name: 'Company Classification', actionPayload: {
72 | prompt: 'The following is a list of companies and the categories they fall into\n' +
73 | '\n' +
74 | 'Facebook: Social media, Technology\n' +
75 | 'Uber: Transportation, Technology, Marketplace\n' +
76 | 'Mcdonalds: Food, Fast Food, Logistics, Restaurants\n' +
77 | '{example}:',
78 | tabIndex: TabIndex.multipleExamples,
79 | stopSymbols: ['\\n'],
80 | examples: [{text: 'Unilever', output: 'Consumer Goods, Food, Personal Care, Retail'}, {text: 'LinkedIn', output: 'Social Media, Technology, Business'}, {text: 'FedEx', output: 'Logistics, Transportation'}]
81 | }},
82 | {id: uniqueId('template_'), name: 'Alliteration Generator', actionPayload: {
83 | prompt: 'Find synonyms for words that can create alliterations.\n' +
84 | '\n' +
85 | 'Sentence: The dog went to the store.\n' +
86 | 'Alliteration: The dog drove to the department.\n' +
87 | '\n' +
88 | 'Sentence: David wears a hat everyday.\n' +
89 | 'Alliteration: David dons a derby daily.\n' +
90 | '\n' +
91 | 'Sentence: The soap dries over night.\n' +
92 | 'Alliteration: The soap shrivels succeeding sunset.\n' +
93 | '\n' +
94 | 'Sentence: {example}\n' +
95 | 'Alliteration:',
96 | examples: [{text: 'A person was running to the church.', output: ''},
97 | {text: 'A person cooked a great meal.', output: ''}],
98 | tabIndex: 0,
99 | stopSymbols: ['\\n'],
100 | }},
101 | {id: uniqueId('template_'), name: 'Song Generation', actionPayload: {
102 | // stopSymbols: ["\\n\\n"],
103 | prompt: 'VERSE:\n' +
104 | 'Alas my love,\n' +
105 | 'You do me wrong,\n' +
106 | 'To cast me off discourteously,\n' +
107 | 'for i have loved you so long,\n' +
108 | 'delighting in your company.\n' +
109 | '\n' +
110 | 'CHORDS:\n' +
111 | 'Alas[Am] my[C] love,\n' +
112 | 'you [G]do [Em]me wrong,\n' +
113 | 'to [Am]cast me off dis[E]courteously,\n' +
114 | 'for [Am]i have[C] loved[G] you [Em]so long,\n' +
115 | 'de[Am]lighting in[E7] your [Am]company.\n' +
116 | '\n' +
117 | 'VERSE:\n' +
118 | '{example}\n' +
119 | '\n' +
120 | 'CHORDS:',
121 | examples: [
122 | {text: 'My pangolin heart\n' +
123 | 'has scales of bone\n' +
124 | 'black and streaked with red\n' +
125 | 'hidden like a forgotten gem\n' +
126 | 'in the dusk', output: ''},
127 | {text: 'Country roads, take me home\n' +
128 | 'To the place I belong\n' +
129 | 'West Virginia, mountain mama\n' +
130 | 'Take me home, country roads',
131 | output: ''}
132 | ],
133 | tabIndex: TabIndex.multipleExamples,
134 | }},
135 | {id: uniqueId('template_'), name: 'Sentence => Email', actionPayload: {
136 | prompt: '```\n' +
137 | 'Thank John for the book. \n' +
138 | '\n' +
139 | '````\n' +
140 | '\n' +
141 | 'Dear John,\n' +
142 | '\n' +
143 | 'Thank you so much for the book. I really appreciate it. \n' +
144 | '\n' +
145 | 'I hope to hang out soon. \n' +
146 | '\n' +
147 | 'Your friend, \n' +
148 | '\n' +
149 | 'Sarah\n' +
150 | '\n' +
151 | '###\n' +
152 | '\n' +
153 | 'Tell TechCorp I appreciate the great service.\n' +
154 | '\n' +
155 | '````\n' +
156 | '\n' +
157 | 'To Whom it May Concern, \n' +
158 | '\n' +
159 | 'I want you to know that I appreciate the great service at TechCorp.\n' +
160 | '\n' +
161 | 'The staff is outstanding and I enjoy every visit. \n' +
162 | '\n' +
163 | 'Sincerely, \n' +
164 | '\n' +
165 | 'Bill Johnson\n' +
166 | '\n' +
167 | '###\n' +
168 | '\n' +
169 | 'Invoice Kelly Watkins $500 for design consultation.\n' +
170 | '\n' +
171 | '````\n' +
172 | '\n' +
173 | 'Dear Ms. Watkins, \n' +
174 | '\n' +
175 | 'This is my invoice for $500 for design consultation. \n' +
176 | '\n' +
177 | 'It was a pleasure to work with you. \n' +
178 | '\n' +
179 | 'Sincerely, \n' +
180 | '\n' +
181 | 'Emily Fields\n' +
182 | '\n' +
183 | '###\n' +
184 | '\n' +
185 | 'Invite Amanda and Paul to the company event Friday night. \n' +
186 | '\n' +
187 | '```\n' +
188 | 'Dear Amanda and Paul,\n' +
189 | '\n' +
190 | 'I hope this finds you doing well. \n' +
191 | '\n' +
192 | 'I want to invite you to our company event on Friday night. \n' +
193 | '\n' +
194 | 'It will be a great opportunity for networking and there will be food and drinks. \n' +
195 | '\n' +
196 | 'Should be fun. \n' +
197 | '\n' +
198 | 'Best, \n' +
199 | '\n' +
200 | 'Ryan\n' +
201 | '\n' +
202 | '###\n' +
203 | '\n' +
204 | '{example}\n' +
205 | '\n' +
206 | '```\n',
207 | stopSymbols: ['###'],
208 | examples: [
209 | {'text': 'Ask RAM Co. if they have new storage units in stock.', 'output': ''}
210 | ],
211 | tabIndex: TabIndex.multipleExamples
212 | }},
213 | {id: uniqueId('template_'), name: 'Book Review', actionPayload: {
214 | prompt: 'Title: Lovely War\n' +
215 | 'Rating: 3/5\n' +
216 | 'Quotes:\n' +
217 | '- "It was time for James and Hazel to get properly acquainted. Time to see if the magic of music and moonlight and graceful movement were all that they had shared, or if a grimy gray London dawn and a cheap cup of coffee could make them feel the same way."\n' +
218 | '- "Annihilation has its own je ne sais quoi. We’re all guilty of it. So spare me the sermons."\n' +
219 | '- "His mother’s letters are full of urgent warning. She grew up in Mississippi. \n' +
220 | 'She knows about lynching. Aubrey wonders if he’ll die in his country before he \n' +
221 | 'ever gets the chance to die for his country. Either way, he’d rather not."\n' +
222 | '- "Whatever boost sixty captured miles might have brought to German morale was \n' +
223 | 'erased by the chocolate in the BEF’s packs. War is morale. War is supply. War is \n' +
224 | 'chocolate."\n' +
225 | 'Thoughts:\n' +
226 | '- Pacing felt awkward\n' +
227 | '- WW1 history felt accurate\n' +
228 | '- Didn\'t care too much for the story of the Gods\n' +
229 | 'Review: A good book with well rounded characters, but the pacing felt super \n' +
230 | 'awkward. The titles of the chapters showed which Greek God was speaking, but I was more interested in the WW1 tales than their relationships.\n' +
231 | '\n' +
232 | '\'\'\'\n' +
233 | '{example}\n' +
234 | 'Review:',
235 | examples: [
236 | {text: 'Title: Goodbye, Things\n' +
237 | 'Rating: 4/5\n' +
238 | 'Thoughts:\n' +
239 | '- very cleanly written\n' +
240 | '- read easily\n' +
241 | '- author did good research', output: ''},
242 | {text: 'Title: Deep Work: Rules for Focused Success in a Distracted World\n' +
243 | 'Rating: 5/5\n' +
244 | 'Thoughts:\n' +
245 | '- Great read, got me to refocus my goals around my schedule.\n' +
246 | '- Got me to delete a social media I used too much\n' +
247 | '- I like that Cal Newport is a computer scientist as well', output: ''}
248 | ],
249 | tabIndex: TabIndex.multipleExamples,
250 | stopSymbols: ['\\n\\n']
251 | }},
252 | {id: uniqueId('template_'), name: 'Headline Generation', actionPayload: {
253 | prompt: 'Topic: Britain, coronavirus, beaches\n' +
254 | 'Headline: Videos show crowded beaches in Britain\n' +
255 | '\n' +
256 | 'Topic: Apple, Big Sur, software\n' +
257 | 'Headline: Apple promises faster software update installation with macOS Big Sur\n' +
258 | '\n' +
259 | 'Topic: Artic, climate change, satellite\n' +
260 | 'Headline: A Satellite Lets Scientists See Antarctica’s Melting Like Never Before\n' +
261 | '\n' +
262 | 'Topic: {example}\n' +
263 | 'Headline:',
264 | examples: [
265 | {text: 'Chicago, restaurants, summer', output: ''}
266 | ],
267 | tabIndex: TabIndex.multipleExamples,
268 | stopSymbols: ['\\n']
269 | }},
270 | {id: uniqueId('template_'), name: 'Product Name Generator', actionPayload: {
271 | prompt: 'This is a product name generator. It takes a product\'s description and seed words, then outputs a list of potential product names.\n' +
272 | '\n' +
273 | 'Product description: A complete home gym that can fit in any apartment.\n' +
274 | 'Seed words: intelligent, aspirational, luxury, futuristic\n' +
275 | 'Product names: InfinityHome, Quantum, FlexFit, Flight, FutureFit\n' +
276 | '\n' +
277 | 'Product description: An affordable electric bike.\n' +
278 | 'Seed words: Easy, eco-friendly, practical, dependable\n' +
279 | 'Product names: Pegasus, Swifty, SunRunner, Wave, Amp\n' +
280 | '\n' +
281 | '{example}\n' +
282 | 'Product names:',
283 | examples: [
284 | {text: 'Product description: A zero carbohydrate cereal that tastes great.\n' +
285 | 'Seed words: fitness, healthy, keto, clean, tasty', output: ''}
286 | ],
287 | tabIndex: TabIndex.multipleExamples,
288 | stopSymbols: ['\\n']
289 | }},
290 | {id: uniqueId('template_'), name: 'Rhyming', actionPayload: {
291 | prompt: 'A homophone is defined as a word that is pronounced the same as another word but \n' +
292 | 'differs in meaning.\n' +
293 | '\n' +
294 | 'Here is a list of homophones:\n' +
295 | '1. Accept/Except\n' +
296 | '2. Affect/Effect\n' +
297 | '3. Allude/Elude\n' +
298 | '4. Alter/Altar\n' +
299 | '5. A lot/Allot\n' +
300 | '\n' +
301 | 'Here\'s a list of homophones starting with the letter "{example}":\n',
302 | examples: [
303 | {text: "b", output: ""}
304 | ],
305 | stopSymbols: [],
306 | tabIndex: TabIndex.multipleExamples
307 | }},
308 | {id: uniqueId('template_'), name: 'Q&A', actionPayload: {
309 | prompt: "Q: What is the definition of a linearly independent list?\n" +
310 | "A: A linearly independent list is a list of vectors that cannot be\n" +
311 | " expressed as a linear combination of other vectors in the list.\n" +
312 | " \n" +
313 | "Q: What is a basis of a vector space?\n" +
314 | "A: A basis of a vector space is a linearly independent list of vectors\n" +
315 | " that spans the vector space.\n" +
316 | "\n" +
317 | "Q: What is a spanning list of vectors in a vector space?\n" +
318 | "A: A spanning list of vectors in a vector space is list of vectors in\n" +
319 | " the vector space such that every vector in the vector space can be\n" +
320 | " written as a linear combination of the vectors in the spanning list.\n" +
321 | " \n" +
322 | "Q: {example}\n" +
323 | "A:",
324 | examples: [
325 | {text: "What is an eigenvector of a linear transformation f?", output: ""},
326 | {text: "What is the definition of a linear transformation?", output: ""},
327 | {text: "Is the vector space of univariate polynomials over a finite field a finite-dimensional vector space?",
328 | output: ""},
329 | {text: "What is the maximum number of eigenvalues of an operator on a 5-dimensional vector space?", output: ""},
330 | {text: "Can the length of a spanning list for a vector space be longer than any linearly independent list of vectors in that space?",
331 | output: ""},
332 |
333 | ],
334 | stopSymbols: ["\\n"],
335 | tabIndex: TabIndex.multipleExamples
336 | }},
337 | {id: uniqueId('template_'), name: 'Summarization', actionPayload: {
338 | prompt: '```\n' +
339 | 'My second grader asked me what this passage means:\n' +
340 | '\n' +
341 | '"""\n' +
342 | '\n' +
343 | '{example}\n' +
344 | '\n' +
345 | '"""\n' +
346 | '\n' +
347 | 'I rephrased it for him, in plain language a second grader can understand:\n' +
348 | '\n' +
349 | '"""\n',
350 | examples: [
351 | {text: "Overnight trading for the NYSE Index futures was a bit volatile, " +
352 | "dropping by about 3% to the downside before moving sharply back to the upside. " +
353 | "Gold futures were unchanged and the E-mini NASDAQ 100 futures remained near " +
354 | "unchanged. The yield on the 10-year Treasury bond finished unchanged from its " +
355 | "close of 2.45% earlier today.",
356 | output: ""},
357 | {text: "This Nondisclosure Agreement (the \"Agreement\") is entered into by and between _______________ with its principal offices at _______________, (\"Disclosing Party\") and _______________, located at _______________ (\"Receiving Party\") for the purpose of preventing the unauthorized disclosure of Confidential Information as defined below. The parties agree to enter into a confidential relationship concerning the disclosure of certain proprietary and confidential information (\"Confidential Information\"). 1. Definition of Confidential Information. For purposes of this Agreement, \"Confidential Information\" shall include all information or material that has or could have commercial value or other utility in the business in which Disclosing Party is engaged. If Confidential Information is in written form, the Disclosing Party shall label or stamp the materials with the word \"Confidential\" or some similar warning. If Confidential Information is transmitted orally, the Disclosing Party shall promptly provide writing indicating that such oral communication constituted Confidential Information. 2. Exclusions from Confidential Information. Receiving Party's obligations under this Agreement do not extend to information that is: (a) publicly known at the time of disclosure or subsequently becomes publicly known through no fault of the Receiving Party; (b) discovered or created by the Receiving Party before disclosure by Disclosing Party; (c) learned by the Receiving Party through legitimate means other than from the Disclosing Party or Disclosing Party's representatives; or (d) is disclosed by Receiving Party with Disclosing Party's prior written approval.",
358 | output: ""},
359 | ],
360 | stopSymbols: ['"""'],
361 | tabIndex: TabIndex.multipleExamples
362 | }},
363 | {id: uniqueId('template_'), name: 'Code Translation', actionPayload: {
364 | prompt: 'Python:\n' +
365 | 'list[::-1]\n' +
366 | 'Ruby:\n' +
367 | 'list.reverse\n' +
368 | '\n' +
369 | 'Python:\n' +
370 | 'list[1:4]\n' +
371 | 'Ruby:\n' +
372 | 'list[1..4]\n' +
373 | '\n' +
374 | 'Python:\n' +
375 | 'print("Hello World")\n' +
376 | 'Ruby:\n' +
377 | 'puts "Hello World"\n' +
378 | '\n' +
379 | 'Python:\n' +
380 | 'fruits = ["apple","banana","cherry"]\n' +
381 | 'for x in fruits:\n' +
382 | 'print(x)\n' +
383 | 'Ruby:\n' +
384 | 'fruit = ["apple", "banana", "cherry"]\n' +
385 | 'each {|x| print x } \n' +
386 | '\n' +
387 | 'Python:\n' +
388 | '{example}\n' +
389 | 'Ruby:\n',
390 | examples: [
391 | {text: 'fruits = ["apple","banana","cherry"]\n' +
392 | 'a = list(fruits)\n' +
393 | 'print(a)\n' +
394 | 'a.reverse()\n' +
395 | 'print(a)', output: ""}
396 | ],
397 | stopSymbols: ["Python:"],
398 | tabIndex: TabIndex.multipleExamples
399 | }},
400 | {id: uniqueId('template_'), name: 'Translation', actionPayload: {
401 | prompt: 'English: I do not speak French.\n' +
402 | 'French: Je ne parle pas français.\n' +
403 | '\n' +
404 | 'English: See you later!\n' +
405 | 'French: À tout à l\'heure!\n' +
406 | '\n' +
407 | 'English: Where is a good restaurant?\n' +
408 | 'French: Où est un bon restaurant?\n' +
409 | '\n' +
410 | 'English: {example}\n' +
411 | 'French:',
412 | examples: [
413 | {text: "What rooms do you have available?", output: ""}
414 | ],
415 | stopSymbols: ['\\n'],
416 | tabIndex: TabIndex.multipleExamples
417 | }},
418 | {id: uniqueId('template_'), name: 'Estimation', actionPayload: {
419 | prompt: 'Lower and upper bound for each quantity:\n' +
420 | '\tNumber of cars in New York: 1500000 to 2500000\n' +
421 | '\tNumber of cars in San Francicso: 300000 to 600000\n' +
422 | '\tHeight of Empire State building: 1400 to 1500 feet\n' +
423 | '\tLength of average car: 4 to 4.5 meters\n' +
424 | '\tPopulation of Germany: 80 to 85 million\n' +
425 | '\t{example}:',
426 | examples: [
427 | {text: "How much does the iPhone XI cost?", output: ""}
428 | ],
429 | stopSymbols: ['\\n'],
430 | tabIndex: TabIndex.multipleExamples
431 | }},
432 | ]
433 | },
434 | {name: 'Variations', templates: [
435 | {id: uniqueId('template_'), name: 'React Components', actionPayload: {
436 | prompt: 'import React from \'react\';\n' +
437 | '\n' +
438 | 'const ThreeButtonComponent=()=>(',
439 | examples: [], tabIndex: TabIndex.variations
440 | }},
441 | {id: uniqueId('template_'), name: 'Analogies Generator', actionPayload: {
442 | prompt: 'Neural networks are like',
443 | stopSymbols: ['.'],
444 | examples: [], tabIndex: TabIndex.variations
445 | }},
446 | {id: uniqueId('template_'), name: 'Idea Generator', actionPayload: {
447 | prompt: 'Here is a list of 100 interesting ideas for new movie plots. Each plot is ' +
448 | 'described with a title and a summary paragraph:\n' +
449 | '\n' +
450 | '1. The Bird. \n' +
451 | 'A woman realizes that her pet bird is actually highly intelligent and able to communicate. The bird turns out to be a secret agent working for the CIA. The woman has to keep the bird\'s secret.\n' +
452 | '\n' +
453 | '2.',
454 | stopSymbols: ['3'],
455 | examples: [], tabIndex: TabIndex.variations
456 | }},
457 | {id: uniqueId('template_'), name: 'Tweet Generation', actionPayload: {
458 | prompt: 'My favorite programming tweets:\n' +
459 | '-------\n' +
460 | 'I asked @ilyasut how to set neural network init. He accidentally replied with a poem:\n' +
461 | 'You want to be on the edge of chaos\n' +
462 | 'Too small, and the init will be too stable, with vanishing gradients\n' +
463 | 'Too large, and you\'ll be unstable, due to exploding gradients\n' +
464 | 'You want to be on the edge\n' +
465 | '-------\n' +
466 | 'I\'ve been programming for 10 years now. Still feels like magic out of a fantasy: say the words exactly right, and watch your intent get carried out; say the words slightly wrong, and things go haywire. Feeling of wonder and joy hasn\'t faded one bit.\n' +
467 | '-------\n' +
468 | 'Web programming is the science of coming up with increasingly complicated ways of concatenating strings.\n' +
469 | '-------\n' +
470 | 'If you ever feel alone in this world, read your firewall logs. Problem solved :)\n' +
471 | '-------\n' +
472 | 'Always wanted to travel back in time to try fighting a younger version of yourself? Software development is the career for you!\n' +
473 | '-------\n' +
474 | 'After 17 years as a professional developer, it seems that the answer to every programming question is "it depends"\n' +
475 | '-------\n',
476 | stopSymbols: ['\\n-'], examples: [], tabIndex: TabIndex.variations
477 | }},
478 | {id: uniqueId('template_'), name: 'Poem Generator', actionPayload: {
479 | prompt: 'Who trusted God was love indeed\n' +
480 | 'And love Creation’s final law\n' +
481 | 'Tho’ Nature, red in tooth and claw\n' +
482 | 'With ravine, shriek’d against his creed.\n' +
483 | 'The hills are shadows, and they flow\n' +
484 | 'From form to form, and nothing stands;T\n' +
485 | 'hey melt like mist, the solid lands,\n' +
486 | 'Like clouds they shape themselves and go.\n' +
487 | '----\n',
488 | stopSymbols: ['--'], examples: [], tabIndex: TabIndex.variations
489 | }},
490 | ]},
491 | {
492 | name: 'Conversations',
493 | templates: [
494 | {id: uniqueId('template_'), name: 'Mark Zuckerberg', actionPayload: {
495 | prompt: 'The following is a transcript of a conversation between Steve, a computer science student, ' +
496 | 'and Mark Zuckerberg. Mark Zuckerberg is an American media magnate, internet entrepreneur, and philanthropist. ' +
497 | 'He is known for co-founding Facebook, Inc. and serves as its chairman, chief executive officer,' +
498 | ' and controlling shareholder.\n',
499 | stopSymbols: ['\\n'],
500 | examples: [],
501 | tabIndex: TabIndex.conversations,
502 | startSequence: '\nMark:',
503 | restartSequence: '\nSteve: ',
504 | }},
505 | {id: uniqueId('template_'), name: 'AI Assistant', actionPayload: {
506 | prompt: 'The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, and very friendly.\n',
507 | stopSymbols: ['\\n'],
508 | examples: [],
509 | tabIndex: TabIndex.conversations,
510 | startSequence: '\nAI:',
511 | restartSequence: '\nHuman: ',
512 | }}
513 | ]
514 | }
515 | ];
516 |
517 | export default function getTemplateGroups() : Array {
518 | return templateGroups;
519 | }
520 |
521 | export function getFlattenedTemplates() {
522 | return ([] as Template[]).concat(...getTemplateGroups().map((templateGroup) => templateGroup.templates));
523 | }
524 |
--------------------------------------------------------------------------------
/src/slices/editorSlice.ts:
--------------------------------------------------------------------------------
1 | import { createSlice, PayloadAction } from '@reduxjs/toolkit';
2 | import uniqid from "uniqid";
3 | import {AppThunk, RootState} from "../store";
4 | import GptAPI, {ChoiceResult} from "../services/GptAPI";
5 |
6 | // TODO: This file grew too fast. It needs to be split into separate slices for different modes.
7 |
8 | // State
9 |
10 | interface Example {
11 | id: string;
12 | text: string;
13 | isLoading: boolean;
14 | output?: string;
15 | previousOutput?: string;
16 | }
17 |
18 | interface CompletionParameters {
19 | apiKey: string;
20 | engine: string;
21 | maxTokens: number;
22 | stop: string | Array;
23 | prompt: string;
24 | temperature: number;
25 | topP: number;
26 | presencePenalty: number;
27 | frequencyPenalty: number;
28 | }
29 |
30 | enum TabIndex {
31 | basic = 0,
32 | multipleExamples,
33 | variations,
34 | conversations
35 | }
36 |
37 | interface Variation {
38 | id: string;
39 | prompt: string;
40 | output: string;
41 | temperature: number;
42 | maxTokens: number;
43 | topP: number;
44 | frequencyPenalty: number;
45 | presencePenalty: number;
46 | modelName: string;
47 | }
48 |
49 | interface Basic {
50 | output: string;
51 | loading: boolean;
52 | }
53 |
54 | enum ConversationPartSource {
55 | user = 'user',
56 | gpt = 'gpt'
57 | }
58 |
59 | interface ConversationPart {
60 | source: ConversationPartSource;
61 | text: string;
62 | submitted: boolean;
63 | }
64 |
65 | interface ConversationCompletionParameters {
66 | engine: string;
67 | maxTokens: number;
68 | stop: string | Array;
69 | prompt: string;
70 | temperature: number;
71 | topP: number;
72 | presencePenalty: number;
73 | frequencyPenalty: number;
74 | }
75 |
76 | interface Conversation {
77 | id: string;
78 | initialPrompt?: string;
79 | inputValue: string;
80 | isLoading: boolean;
81 | startSequence: string;
82 | restartSequence: string;
83 | parts: Array;
84 | completionParams?: ConversationCompletionParameters;
85 | }
86 |
87 | interface Workspace {
88 | id: string;
89 | name: string;
90 |
91 | prompt: string;
92 | modelName: string;
93 | temperature: number;
94 | topP: number;
95 | frequencyPenalty: number;
96 | presencePenalty: number;
97 | stopSymbols: Array;
98 | maxTokens: number;
99 | tabIndex: TabIndex;
100 |
101 | showExamplePreviousOutputs: boolean;
102 | examples: Array;
103 |
104 | loadingVariations: boolean;
105 | variations: Array;
106 | maxVariations: number;
107 | showPromptForVariations: boolean;
108 |
109 | basic: Basic;
110 |
111 | conversations: Array;
112 | }
113 |
114 | interface EditorState {
115 | apiKey?: string;
116 | currentWorkspaceId: string;
117 | editableWorkspaceName: string;
118 | workspaces: Array;
119 |
120 | showApiKeyDialog: boolean;
121 | showTemplateDialog: boolean;
122 | }
123 |
124 | const initialState: EditorState = {
125 | apiKey: undefined,
126 | currentWorkspaceId: 'first_workspace',
127 | editableWorkspaceName: 'Draft #1',
128 | workspaces: [{
129 | id: 'first_workspace',
130 | name: 'Draft #1',
131 | prompt: "Click Explore Templates -> Song Generation for a fun example!",
132 | // prompt: "Input: Anna and Mike is going skiing.\n" +
133 | // "Output: Anna and Mike are going skiing.\n" +
134 | // "Input: Anna and Pat are married; he has been together for 20 years.\n" +
135 | // "Output: Anna and Pat are married; they have been together for 20 years.\n" +
136 | // "Input: I walk to the store and I bought milk.\n" +
137 | // "Output: I walked to the store and I bought milk.\n" +
138 | // "Input: {example}\n" +
139 | // "Output:",
140 | modelName: 'davinci',
141 | temperature: 0.8,
142 | topP: 1,
143 | frequencyPenalty: 0,
144 | presencePenalty: 0,
145 | // stopSymbols: ["\\n"],
146 | stopSymbols: [],
147 | maxTokens: 80,
148 | tabIndex: 0,
149 |
150 | showExamplePreviousOutputs: false,
151 | examples: [
152 | {id: uniqid("input_"), text: "We all eat the fish and then made dessert.", output: "We all ate the fish and then made dessert.", isLoading: false},
153 | {id: uniqid("input_"), text: "I like ski every day.", output: "I like skiing every day.", isLoading: false},
154 | ],
155 |
156 | loadingVariations: false,
157 | variations: [],
158 | maxVariations: 2,
159 | showPromptForVariations: true,
160 |
161 | conversations: [],
162 |
163 | basic: {
164 | output: '',
165 | loading: false,
166 | },
167 | }],
168 | showApiKeyDialog: false,
169 | showTemplateDialog: false,
170 | };
171 |
172 | // Action Payloads: Examples
173 |
174 | interface EditExampleActionPayload {
175 | id: string;
176 | text: string;
177 | }
178 |
179 | interface LoadExampleOutputActionPayload {
180 | id: string;
181 | output: string;
182 | }
183 |
184 | // Action Payloads: Variations
185 |
186 | interface AddVariationActionPayload {
187 | output: string;
188 | prompt: string;
189 | temperature: number;
190 | maxTokens: number;
191 | topP: number;
192 | frequencyPenalty: number;
193 | presencePenalty: number;
194 | modelName: string;
195 | }
196 |
197 | // Action Payloads: Conversations
198 |
199 | interface SetConversationCompletionParametersActionPayload {
200 | conversationId: string;
201 | parameters: ConversationCompletionParameters;
202 | }
203 |
204 | interface SetConversationInitialPromptActionPayload {
205 | conversationId: string;
206 | initialPrompt: string;
207 | }
208 |
209 | interface UpdateConversationLoadingStatusActionPayload {
210 | conversationId: string;
211 | status: boolean;
212 | }
213 |
214 | interface UpdateConversationInputValueActionPayload {
215 | conversationId: string;
216 | inputValue: string;
217 | }
218 |
219 | interface UpdateConversationStartSequenceActionPayload {
220 | conversationId: string;
221 | startSequence: string;
222 | }
223 |
224 | interface UpdateConversationRestartSequenceActionPayload {
225 | conversationId: string;
226 | restartSequence: string;
227 | }
228 |
229 |
230 | interface AddMessageToConversationFromUserActionPayload {
231 | conversationId: string;
232 | source: ConversationPartSource.user;
233 | }
234 |
235 | interface AddMessageToConversationFromGptActionPayload {
236 | conversationId: string;
237 | text: string;
238 | source: ConversationPartSource.gpt;
239 | }
240 |
241 | // Action Payloads: Templates
242 |
243 | interface LoadTemplateFromFileDataActionPayload {
244 | prompt: string;
245 | temperature: number;
246 | topP: number;
247 | frequencyPenalty: number;
248 | presencePenalty: number;
249 | maxTokens: number;
250 | stopSymbols: Array;
251 | modelName: string;
252 | }
253 |
254 | interface LoadTemplateActionExample {
255 | text: string;
256 | output: string;
257 | }
258 |
259 | interface LoadTemplateActionPayload {
260 | prompt: string;
261 | examples: Array;
262 | stopSymbols?: Array;
263 | tabIndex: number;
264 | startSequence?: string;
265 | restartSequence?: string;
266 | }
267 |
268 | const editorSlice = createSlice({
269 | name: 'editor',
270 | initialState,
271 | reducers: {
272 | editExample: (state, action: PayloadAction) => {
273 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
274 | workspace.examples = workspace.examples.map(value => {
275 | if (value.id === action.payload.id) {
276 | value.text = action.payload.text;
277 | }
278 | return value;
279 | });
280 | },
281 | cleanExampleList: (state) => {
282 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
283 | // Always add an empty example for user to fill out
284 | if (workspace.examples.length < 1 || workspace.examples[workspace.examples.length - 1].text.length) {
285 | workspace.examples.push({id: uniqid("input_"), text: "", output: undefined, isLoading: false});
286 | }
287 | // Delete all empty inputs except for the last one
288 | workspace.examples = workspace.examples.filter((value, index) => {
289 | if (index === workspace.examples.length - 1) {
290 | return true;
291 | }
292 | return value.text.length > 0;
293 | })
294 | },
295 | markExampleAsLoading: (state, action: PayloadAction) => {
296 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
297 | workspace.examples = workspace.examples.map(value => {
298 | if (value.id === action.payload) {
299 | value.isLoading = true;
300 | }
301 | return value;
302 | });
303 | },
304 | markAllExamplesAsNotLoading: (state) => {
305 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
306 | workspace.examples = workspace.examples.map(value => {
307 | value.isLoading = false;
308 | return value;
309 | });
310 | },
311 | loadOutputForExample: (state, action: PayloadAction) => {
312 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
313 | workspace.examples = workspace.examples.map(value => {
314 | if (value.id === action.payload.id) {
315 | value.previousOutput = value.output;
316 | value.output = action.payload.output;
317 | value.isLoading = false;
318 | }
319 | return value;
320 | });
321 | },
322 | deleteExample: (state, action: PayloadAction) => {
323 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
324 | workspace.examples = workspace.examples.filter(example => example.id !== action.payload);
325 | },
326 | updateExamplePreviousOutputsStatus: (state, action: PayloadAction) => {
327 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
328 | workspace.showExamplePreviousOutputs = action.payload;
329 | },
330 | loadBasicOutput: (state, action: PayloadAction) => {
331 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
332 | workspace.basic.output = action.payload;
333 | },
334 | setBasicLoading: (state, action: PayloadAction) => {
335 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
336 | workspace.basic.loading = action.payload;
337 | },
338 |
339 | updateVariationsLoadingStatus: (state, action: PayloadAction) => {
340 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
341 | workspace.loadingVariations = action.payload;
342 | },
343 | addVariation: (state, action: PayloadAction) => {
344 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
345 | workspace.variations.push({
346 | id: uniqid('variation_'),
347 | output: action.payload.output,
348 | prompt: action.payload.prompt,
349 | temperature: action.payload.temperature,
350 | maxTokens: action.payload.maxTokens,
351 | topP: action.payload.topP,
352 | frequencyPenalty: action.payload.frequencyPenalty,
353 | presencePenalty: action.payload.presencePenalty,
354 | modelName: action.payload.modelName,
355 | });
356 | },
357 | editMaxVariations: (state, action: PayloadAction) => {
358 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
359 | workspace.maxVariations = action.payload;
360 | },
361 | cleanVariations: (state) => {
362 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
363 | workspace.variations = [];
364 | },
365 | updateShowPromptForVariations: (state, action: PayloadAction) => {
366 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
367 | workspace.showPromptForVariations = action.payload;
368 | },
369 |
370 | normalizeConversations: (state) => {
371 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
372 | // Always add an empty conversation for user to start
373 | if (workspace.conversations.length < 1 || workspace.conversations[0].parts.length > 1) {
374 | let startSequence = "\nAI:";
375 | let restartSequence = "\nUser: ";
376 | if (workspace.conversations.length >= 1) {
377 | startSequence = workspace.conversations[0].startSequence;
378 | restartSequence = workspace.conversations[0].restartSequence;
379 | }
380 | workspace.conversations.unshift({
381 | id: uniqid("conversation_"), parts: [
382 | {text: convertConversationPartToText(
383 | '', ConversationPartSource.user,
384 | startSequence, restartSequence),
385 | source: ConversationPartSource.user,
386 | submitted: false}
387 | ], completionParams: undefined, inputValue: '',
388 | isLoading: false, initialPrompt: undefined, startSequence: startSequence, restartSequence: restartSequence
389 | });
390 | }
391 | },
392 | setConversationCompletionParams: (state,
393 | action: PayloadAction) => {
394 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
395 | workspace.conversations = workspace.conversations.map(conversation => {
396 | if (conversation.id === action.payload.conversationId) {
397 | conversation.completionParams = action.payload.parameters;
398 | }
399 | return conversation;
400 | });
401 | },
402 | setConversationInitialPrompt: (state, action: PayloadAction) => {
403 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
404 | workspace.conversations = workspace.conversations.map(conversation => {
405 | if (conversation.id === action.payload.conversationId) {
406 | conversation.initialPrompt = action.payload.initialPrompt;
407 | }
408 | return conversation;
409 | });
410 | },
411 | updateConversationLoadingStatus: (state, action: PayloadAction) => {
412 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
413 | workspace.conversations = workspace.conversations.map(conversation => {
414 | if (conversation.id === action.payload.conversationId) {
415 | conversation.isLoading = action.payload.status;
416 | }
417 | return conversation;
418 | });
419 | },
420 | updateConversationInputValue: (state, action: PayloadAction) => {
421 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
422 | workspace.conversations = workspace.conversations.map(conversation => {
423 | if (conversation.id === action.payload.conversationId) {
424 | conversation.inputValue = action.payload.inputValue;
425 | }
426 | return conversation;
427 | });
428 | },
429 | updateConversationStartSequence: (state, action: PayloadAction) => {
430 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
431 | workspace.conversations = workspace.conversations.map(conversation => {
432 | if (conversation.id === action.payload.conversationId) {
433 | conversation.startSequence = action.payload.startSequence;
434 | }
435 | return conversation;
436 | });
437 | },
438 | updateConversationRestartSequence: (state, action: PayloadAction) => {
439 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
440 | workspace.conversations = workspace.conversations.map(conversation => {
441 | if (conversation.id === action.payload.conversationId) {
442 | conversation.restartSequence = action.payload.restartSequence;
443 | }
444 | return conversation;
445 | });
446 | },
447 | addMessageInConversation: (state, action: PayloadAction) => {
448 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
449 | workspace.conversations = workspace.conversations.map(conversation => {
450 | if (conversation.id !== action.payload.conversationId) {
451 | return conversation;
452 | }
453 |
454 | let inputText: string;
455 | if (action.payload.source === ConversationPartSource.user) {
456 | inputText = conversation.inputValue;
457 | conversation.inputValue = '';
458 | } else {
459 | inputText = action.payload.text;
460 | }
461 |
462 | const lastPartInd = conversation.parts.length - 1;
463 | const lastPart = conversation.parts[lastPartInd];
464 |
465 | // It shouldn't happen.
466 | if (lastPart.source !== action.payload.source) {
467 | console.log('[lastPart.source !== action.payload.source]');
468 | return conversation;
469 | }
470 |
471 | lastPart.text = convertConversationPartToText(
472 | inputText, lastPart.source,
473 | conversation.startSequence, conversation.restartSequence)
474 | lastPart.submitted = true;
475 | conversation.parts[lastPartInd] = lastPart;
476 |
477 | const nextSource = (
478 | lastPart.source === ConversationPartSource.gpt
479 | ? ConversationPartSource.user
480 | : ConversationPartSource.gpt
481 | );
482 | conversation.parts.push({
483 | source: nextSource,
484 | text: convertConversationPartToText(
485 | '', nextSource,
486 | conversation.startSequence, conversation.restartSequence),
487 | submitted: false
488 | });
489 |
490 | return conversation;
491 | });
492 | },
493 | deleteConversation: (state, action: PayloadAction) => {
494 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
495 | workspace.conversations = workspace.conversations.filter(c => c.id !== action.payload);
496 | },
497 |
498 | loadTemplate: (state, action: PayloadAction) => {
499 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
500 | workspace.prompt = action.payload.prompt;
501 | workspace.examples = action.payload.examples.map((example) => {
502 | return {id: uniqid('example_'), text: example.text, output: example.output, isLoading: false}
503 | });
504 |
505 | if (action.payload.stopSymbols !== undefined) {
506 | workspace.stopSymbols = action.payload.stopSymbols;
507 | }
508 | if (action.payload.startSequence !== undefined) {
509 | workspace.conversations[0]!.startSequence = action.payload.startSequence;
510 | }
511 | if (action.payload.restartSequence !== undefined) {
512 | workspace.conversations[0]!.restartSequence = action.payload.restartSequence;
513 | }
514 | workspace.tabIndex = action.payload.tabIndex;
515 | },
516 | loadTemplateFromFileData: (state, action: PayloadAction) => {
517 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
518 | workspace.prompt = action.payload.prompt;
519 | workspace.temperature = action.payload.temperature;
520 | workspace.topP = action.payload.topP;
521 | workspace.frequencyPenalty = action.payload.frequencyPenalty;
522 | workspace.presencePenalty = action.payload.presencePenalty;
523 | workspace.maxTokens = action.payload.maxTokens;
524 | workspace.stopSymbols = action.payload.stopSymbols;
525 | workspace.modelName = action.payload.modelName;
526 | },
527 | editPrompt: (state, action: PayloadAction) => {
528 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
529 | workspace.prompt = action.payload;
530 | },
531 | editApiKey: (state, action: PayloadAction) => {
532 | state.apiKey = action.payload;
533 | },
534 | editModelName: (state, action: PayloadAction) => {
535 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
536 | workspace.modelName = action.payload;
537 | },
538 | editTemperature: (state, action: PayloadAction) => {
539 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
540 | workspace.temperature = action.payload;
541 | },
542 | editTopP: (state, action: PayloadAction) => {
543 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
544 | workspace.topP = action.payload;
545 | },
546 | editFrequencyPenalty: (state, action: PayloadAction) => {
547 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
548 | workspace.frequencyPenalty = action.payload;
549 | },
550 | editPresencePenalty: (state, action: PayloadAction) => {
551 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
552 | workspace.presencePenalty = action.payload;
553 | },
554 | addStopSymbol: (state, action: PayloadAction) => {
555 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
556 | workspace.stopSymbols.push(action.payload);
557 | },
558 | deleteStopSymbol: (state, action: PayloadAction) => {
559 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
560 | workspace.stopSymbols = workspace.stopSymbols.filter((symbol) => symbol !== action.payload);
561 | },
562 | editMaxTokens: (state, action: PayloadAction) => {
563 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
564 | workspace.maxTokens = action.payload;
565 | },
566 | updateTabIndex: (state, action: PayloadAction) => {
567 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
568 | workspace.tabIndex = action.payload;
569 | },
570 |
571 | updateWorkspaceId: (state, action: PayloadAction) => {
572 | const newWorkspace = state.workspaces.find(w => w.id === action.payload);
573 | if (newWorkspace === undefined) {
574 | return;
575 | }
576 | state.currentWorkspaceId = action.payload;
577 | state.editableWorkspaceName = newWorkspace.name;
578 | },
579 | createWorkspace: (state) => {
580 | let currentWorkspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
581 | const newWorkspace = {
582 | ...currentWorkspace,
583 | id: uniqid('workspace_'),
584 | name: `Draft #${state.workspaces.length + 1}`
585 | };
586 | state.workspaces.push(newWorkspace);
587 | state.currentWorkspaceId = newWorkspace.id;
588 | state.editableWorkspaceName = newWorkspace.name;
589 | },
590 | updateCurrentWorkspaceName: (state) => {
591 | let workspace = state.workspaces.find(w => w.id === state.currentWorkspaceId)!
592 | workspace.name = state.editableWorkspaceName;
593 | },
594 | updateEditableWorkspaceName: (state, action: PayloadAction) => {
595 | state.editableWorkspaceName = action.payload;
596 | },
597 | deleteCurrentWorkspace: (state) => {
598 | if (state.workspaces.length < 2) {
599 | return;
600 | }
601 | state.workspaces = state.workspaces.filter(w => w.id !== state.currentWorkspaceId);
602 | const newWorkspace = state.workspaces[state.workspaces.length - 1];
603 | state.currentWorkspaceId = newWorkspace.id;
604 | state.editableWorkspaceName = newWorkspace.name;
605 | },
606 |
607 | toggleApiKeyDialog: (state, action: PayloadAction) => {
608 | state.showApiKeyDialog = action.payload;
609 | },
610 | toggleTemplateDialog: (state, action: PayloadAction) => {
611 | state.showTemplateDialog = action.payload;
612 | },
613 | },
614 | });
615 |
616 | const fetchForCurrentTab = (): AppThunk => (dispatch, getState) => {
617 | const state = getState();
618 | let workspace = state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!
619 | switch (workspace.tabIndex) {
620 | case TabIndex.basic: {
621 | dispatch(fetchBasicOutputAsync());
622 | break;
623 | }
624 | case TabIndex.multipleExamples: {
625 | dispatch(fetchExamplesOutputsAsync());
626 | break;
627 | }
628 | case TabIndex.variations: {
629 | dispatch(fetchVariationsAsync());
630 | break;
631 | }
632 | }
633 | }
634 |
635 | const fetchBasicOutputAsync = (): AppThunk => (dispatch, getState) => {
636 | const state = getState();
637 | let workspace = state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!
638 | if (state.editor.present.apiKey === undefined) {
639 | alert('Enter an API key before running requests.');
640 | return;
641 | }
642 | if (workspace.prompt.length === 0) {
643 | alert("The prompt can't be empty");
644 | return;
645 | }
646 |
647 | const completionParams = selectCompletionParameters(state);
648 | dispatch(setBasicLoading(true));
649 | GptAPI.generateCompletions(completionParams.prompt, completionParams, 1, true).then(response => {
650 | console.log(response.data);
651 | return { ...response.data };
652 | }).then(response => {
653 | const choiceResult = response.choices[0] as ChoiceResult;
654 | dispatch(loadBasicOutput(choiceResult.text));
655 | }).catch(error => {
656 | alert('API returned an error. Refer to the console to inspect it.')
657 | console.log(error.response);
658 | dispatch(markAllExamplesAsNotLoading());
659 | }).finally(() => {
660 | dispatch(setBasicLoading(false));
661 | });
662 | };
663 |
664 | const fetchExamplesOutputsAsync = (): AppThunk => (dispatch, getState) => {
665 | const state = getState();
666 | let workspace = state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!
667 | if (state.editor.present.apiKey === undefined) {
668 | alert('Enter an API key before running requests.');
669 | return;
670 | }
671 | if (workspace.prompt.length === 0) {
672 | alert("The prompt can't be empty");
673 | return;
674 | }
675 | if (workspace.prompt.indexOf('{example}') === -1) {
676 | alert('Use "{example}" in your prompt to use the Multiple Examples mode');
677 | return;
678 | }
679 |
680 | const examples = workspace.examples.filter(example => example.text.length > 0);
681 | if (examples.length === 0) {
682 | alert('Enter at least one example');
683 | return;
684 | }
685 |
686 | const completionParams = selectCompletionParameters(state);
687 | const examplePrompts = examples.map(example => completionParams.prompt.replace('{example}', example.text));
688 | const exampleIds = examples.map(example => example.id);
689 | exampleIds.map((exampleId) => dispatch(markExampleAsLoading(exampleId)));
690 |
691 | GptAPI.generateCompletions(examplePrompts, completionParams).then(response => {
692 | console.log(response.data);
693 | return { ...response.data };
694 | }).then(response => {
695 | response.choices.map((exampleResult: ChoiceResult, ind: number) => {
696 | const exampleId = exampleIds[ind];
697 | dispatch(loadOutputForExample({id: exampleId, output: exampleResult.text}));
698 | return undefined;
699 | });
700 | }).catch(error => {
701 | alert('API returned an error. Refer to the console to inspect it.')
702 | console.log(error.response);
703 | dispatch(markAllExamplesAsNotLoading());
704 | });
705 | };
706 |
707 | const fetchVariationsAsync = (): AppThunk => (dispatch, getState) => {
708 | const state = getState();
709 | let workspace = state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!;
710 | if (state.editor.present.apiKey === undefined) {
711 | alert('Enter an API key before running requests.');
712 | return;
713 | }
714 | if (workspace.prompt.length === 0) {
715 | alert("The prompt can't be empty");
716 | return;
717 | }
718 |
719 | dispatch(updateVariationsLoadingStatus(true));
720 |
721 | const completionParams = selectCompletionParameters(state);
722 |
723 | GptAPI.generateCompletions(completionParams.prompt, completionParams, workspace.maxVariations).then(response => {
724 | console.log(response.data);
725 | return { ...response.data };
726 | }).then(response => {
727 | dispatch(updateVariationsLoadingStatus(false));
728 | response.choices.map((variationResult: ChoiceResult) => (
729 | dispatch(addVariation({
730 | output: variationResult.text,
731 | prompt: completionParams.prompt,
732 | temperature: completionParams.temperature,
733 | maxTokens: completionParams.maxTokens,
734 | topP: completionParams.topP,
735 | presencePenalty: completionParams.presencePenalty,
736 | frequencyPenalty: completionParams.frequencyPenalty,
737 | modelName: completionParams.engine
738 | }))
739 | ));
740 | }).catch(error => {
741 | alert('API returned an error. Refer to the console to inspect it.')
742 | console.log(error.response);
743 | dispatch(updateVariationsLoadingStatus(false));
744 | });
745 | }
746 |
747 | const sendMessageInConversationAsync = (conversationId: string): AppThunk => (dispatch, getState) => {
748 | const state = getState();
749 | let workspace = state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!;
750 | if (state.editor.present.apiKey === undefined) {
751 | alert('Enter an API key before running requests.');
752 | return;
753 | }
754 | const conversation = workspace.conversations.find(conversation => conversation.id === conversationId);
755 | if (conversation === undefined) {
756 | return;
757 | }
758 |
759 | // If it is a first message in the conversation, lock current completion parameters and prompt for whole conversation
760 | if (conversation.parts.length === 1) {
761 | dispatch(setConversationInitialPrompt({
762 | conversationId: conversationId, initialPrompt: selectPrompt(state)
763 | }));
764 | dispatch(setConversationCompletionParams({
765 | conversationId: conversationId, parameters: selectCompletionParameters(state)
766 | }));
767 | }
768 |
769 | dispatch(addMessageInConversation({conversationId: conversationId, source: ConversationPartSource.user}))
770 | dispatch(updateConversationLoadingStatus({conversationId: conversationId, status: true}));
771 |
772 | const updatedState = getState();
773 | let updatedWorkspace = updatedState.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!;
774 | const updatedConversation = updatedWorkspace.conversations.find(conversation => conversation.id === conversationId);
775 | if (updatedConversation === undefined) {
776 | return;
777 | }
778 | const completionParams = {apiKey: state.editor.present.apiKey, ...updatedConversation.completionParams!};
779 | const prompt = updatedConversation.initialPrompt + updatedConversation.parts.map(p => p.text).join('');
780 | GptAPI.generateCompletions(prompt, completionParams, 1).then(response => {
781 | console.log(response.data);
782 | return { ...response.data };
783 | }).then(response => {
784 | dispatch(updateConversationLoadingStatus({conversationId: conversationId, status: false}));
785 | dispatch(addMessageInConversation({conversationId: conversationId, source: ConversationPartSource.gpt,
786 | text: response['choices'][0]['text']}))
787 | });
788 |
789 | }
790 |
791 | const selectApiKey = (state: RootState) => state.editor.present.apiKey;
792 | const selectApiKeyDialogVisible = (state: RootState) => state.editor.present.showApiKeyDialog;
793 | const selectTemplateDialogVisible = (state: RootState) => state.editor.present.showTemplateDialog;
794 | const selectCurrentWorkspaceId = (state: RootState) => state.editor.present.currentWorkspaceId;
795 | const selectEditableWorkspaceName = (state: RootState) => state.editor.present.editableWorkspaceName;
796 | const selectCurrentWorkspaceName = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.name;
797 | const selectWorkspacesList = (state: RootState) => state.editor.present.workspaces.map(w => ({id: w.id, name: w.name}));
798 |
799 | const selectTabIndex = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.tabIndex;
800 | const selectPrompt = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.prompt;
801 | const selectStopSymbols = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.stopSymbols;
802 |
803 | const selectModelName = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.modelName;
804 | const selectTemperature = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.temperature;
805 | const selectTopP = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.topP;
806 | const selectFrequencyPenalty = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.frequencyPenalty;
807 | const selectPresencePenalty = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.presencePenalty;
808 | const selectMaxTokens = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.maxTokens;
809 | const selectCompletionParameters = (state: RootState) => {
810 | const workspace = state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!;
811 | return {
812 | apiKey: state.editor.present.apiKey === undefined ? '' : state.editor.present.apiKey,
813 | engine: workspace.modelName,
814 | maxTokens: workspace.maxTokens,
815 | stop: (() => {
816 | if (workspace.stopSymbols.length > 0) {
817 | return workspace.stopSymbols.map(symbol => {
818 | return symbol.split('\\n').join('\n');
819 | });
820 | } else {
821 | return '';
822 | }
823 | })(),
824 | prompt: workspace.prompt,
825 | temperature: workspace.temperature,
826 | topP: workspace.topP,
827 | presencePenalty: workspace.presencePenalty,
828 | frequencyPenalty: workspace.frequencyPenalty,
829 | };
830 | };
831 |
832 | const selectExamples = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.examples;
833 | const selectExamplePreviousOutputsStatus = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.showExamplePreviousOutputs;
834 |
835 | const selectBasicOutput = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.basic.output;
836 | const selectBasicLoading = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.basic.loading;
837 |
838 | const selectVariationsLoadingStatus = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.loadingVariations;
839 | const selectVariations = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.variations;
840 | const selectMaxVariations = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.maxVariations;
841 | const selectShowPromptForVariations = (state: RootState) => state.editor.present.workspaces.find(w => w.id === state.editor.present.currentWorkspaceId)!.showPromptForVariations;
842 |
843 | // Helpers
844 |
845 | function convertConversationPartToText(text: string, source: ConversationPartSource,
846 | startSequence: string, restartSequence: string): string {
847 | if (source === ConversationPartSource.user) {
848 | return restartSequence + text;
849 | } else { // source === ConversationPartSource.gpt
850 | return startSequence + text;
851 | }
852 | }
853 |
854 | // Exports
855 |
856 | export default editorSlice.reducer;
857 | export {editorSlice};
858 |
859 | // State Enums
860 |
861 | export {TabIndex, ConversationPartSource};
862 |
863 | // State Parts
864 |
865 | export type {
866 | CompletionParameters, Example, // for code generator
867 | ConversationCompletionParameters, // for conversation's completion parameters props
868 | };
869 |
870 | // Action payloads
871 |
872 | export type {
873 | LoadTemplateFromFileDataActionPayload, LoadTemplateActionPayload, // for templates library
874 | };
875 |
876 | // Selectors
877 |
878 | export {
879 | // Common
880 | selectTabIndex, selectPrompt, selectStopSymbols, selectApiKey, selectModelName,
881 | selectTemperature, selectTopP, selectFrequencyPenalty, selectPresencePenalty,
882 | selectMaxTokens, selectApiKeyDialogVisible, selectTemplateDialogVisible,
883 | selectCompletionParameters, selectCurrentWorkspaceId, selectEditableWorkspaceName, selectCurrentWorkspaceName,
884 | selectWorkspacesList,
885 |
886 | // Modes
887 | selectExamples, selectExamplePreviousOutputsStatus,
888 | selectVariationsLoadingStatus, selectVariations, selectMaxVariations,
889 | selectShowPromptForVariations, selectBasicOutput, selectBasicLoading,
890 | };
891 |
892 | // Async Actions
893 |
894 | export {
895 | fetchForCurrentTab, fetchExamplesOutputsAsync, fetchBasicOutputAsync,
896 | fetchVariationsAsync, sendMessageInConversationAsync
897 | };
898 |
899 | // Actions
900 | export const {
901 | updateWorkspaceId, createWorkspace, deleteCurrentWorkspace, updateCurrentWorkspaceName, updateEditableWorkspaceName,
902 | editExample, loadOutputForExample, deleteExample, cleanExampleList, markExampleAsLoading, updateExamplePreviousOutputsStatus, loadBasicOutput, setBasicLoading,
903 | markAllExamplesAsNotLoading,
904 | addVariation, editMaxVariations, cleanVariations, updateShowPromptForVariations, updateVariationsLoadingStatus,
905 | setConversationCompletionParams, normalizeConversations, updateConversationLoadingStatus, updateConversationInputValue,
906 | updateConversationStartSequence, updateConversationRestartSequence, addMessageInConversation,
907 | setConversationInitialPrompt, deleteConversation,
908 | addStopSymbol, deleteStopSymbol,
909 | editTopP, editFrequencyPenalty, editPresencePenalty,
910 | loadTemplate, loadTemplateFromFileData,
911 | editPrompt, editApiKey, editModelName, editTemperature, editMaxTokens, updateTabIndex, toggleApiKeyDialog, toggleTemplateDialog } = editorSlice.actions;
912 |
913 | // Action Payloads
914 |
--------------------------------------------------------------------------------