mebubo commited on
Commit
82b1b1d
·
1 Parent(s): 8214506
frontend/esbuild.js CHANGED
@@ -1,18 +1,24 @@
1
  import * as esbuild from 'esbuild'
2
 
3
- esbuild
4
- .build({
5
- entryPoints: [
6
- "./src/index.tsx",
7
- ],
8
- bundle: true,
9
- minify: false,
10
- sourcemap: process.env.NODE_ENV !== "production",
11
- target: ["chrome120", "firefox110"],
12
- outdir: "public",
13
- outbase: "src",
14
- define: {
15
- "process.env.NODE_ENV": `"${process.env.NODE_ENV}"`
16
- }
17
- })
18
- .catch(() => process.exit(1))
 
 
 
 
 
 
 
1
  import * as esbuild from 'esbuild'
2
 
3
+ const ctx = await esbuild.context({
4
+ entryPoints: [
5
+ "./src/index.tsx",
6
+ ],
7
+ bundle: true,
8
+ minify: false,
9
+ sourcemap: process.env.NODE_ENV !== "production",
10
+ target: ["chrome120", "firefox110"],
11
+ outdir: "public",
12
+ outbase: "src",
13
+ define: {
14
+ "process.env.NODE_ENV": `"${process.env.NODE_ENV}"`
15
+ }
16
+ })
17
+
18
+ if (process.argv.includes('--watch')) {
19
+ await ctx.watch()
20
+ console.log('Watching...')
21
+ } else {
22
+ await ctx.rebuild()
23
+ await ctx.dispose()
24
+ }
frontend/package.json CHANGED
@@ -4,7 +4,8 @@
4
  "main": "index.js",
5
  "type": "module",
6
  "scripts": {
7
- "build": "node esbuild.js"
 
8
  },
9
  "author": "",
10
  "license": "ISC",
 
4
  "main": "index.js",
5
  "type": "module",
6
  "scripts": {
7
+ "build": "node esbuild.js",
8
+ "watch": "node esbuild.js --watch"
9
  },
10
  "author": "",
11
  "license": "ISC",
frontend/public/index.css CHANGED
@@ -1,3 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  main {
2
  display: flex;
3
  flex-direction: column;
@@ -51,3 +125,13 @@ details > summary {
51
  font-family: monospace;
52
  color: red;
53
  }
 
 
 
 
 
 
 
 
 
 
 
1
+ * {
2
+ box-sizing: border-box;
3
+ }
4
+
5
+ :root {
6
+ font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
7
+ font-size: 16px;
8
+ line-height: 24px;
9
+ font-weight: 400;
10
+
11
+ color: #213547;
12
+ background-color: #ffffff;
13
+
14
+ font-synthesis: none;
15
+ text-rendering: optimizeLegibility;
16
+ -webkit-font-smoothing: antialiased;
17
+ -moz-osx-font-smoothing: grayscale;
18
+ -webkit-text-size-adjust: 100%;
19
+ }
20
+
21
+ a {
22
+ font-weight: 500;
23
+ color: #646cff;
24
+ text-decoration: inherit;
25
+ }
26
+ a:hover {
27
+ color: #747bff;
28
+ }
29
+
30
+ body {
31
+ margin: 0;
32
+ display: flex;
33
+ place-items: center;
34
+ min-width: 320px;
35
+ min-height: 100vh;
36
+ }
37
+
38
+ h1 {
39
+ font-size: 3.2em;
40
+ line-height: 1.1;
41
+ }
42
+
43
+ .card {
44
+ padding: 2em;
45
+ }
46
+
47
+ #app {
48
+ width: min(900px, 100vw);
49
+ min-height: 100vh;
50
+ margin: 0 auto;
51
+ padding: 2rem;
52
+ text-align: center;
53
+ }
54
+
55
+ button {
56
+ border-radius: 4px;
57
+ border: 1px solid transparent;
58
+ padding: 0.6em 1.2em;
59
+ font-size: 1em;
60
+ font-weight: 500;
61
+ font-family: inherit;
62
+ background-color: #e5e5e5;
63
+ cursor: pointer;
64
+ transition: border-color 0.25s;
65
+ }
66
+ button:hover {
67
+ border-color: #646cff;
68
+ }
69
+ button:focus,
70
+ button:focus-visible {
71
+ outline: 4px auto -webkit-focus-ring-color;
72
+ }
73
+
74
+
75
  main {
76
  display: flex;
77
  flex-direction: column;
 
125
  font-family: monospace;
126
  color: red;
127
  }
128
+
129
+ span.token-chip {
130
+ background-color: #222222;
131
+ color: white;
132
+ padding: 2px;
133
+ }
134
+
135
+ span.token-chip.flagged {
136
+ background-color: #dd1111;
137
+ }
frontend/public/index.html CHANGED
@@ -5,7 +5,6 @@
5
  <link rel="stylesheet" href="index.css">
6
  </head>
7
  <body>
8
- <h1>GPTed with suggestions</h1>
9
  <div id="app"></div>
10
  <script src="index.js"></script>
11
  </body>
 
5
  <link rel="stylesheet" href="index.css">
6
  </head>
7
  <body>
 
8
  <div id="app"></div>
9
  <script src="index.js"></script>
10
  </body>
frontend/src/components/app.tsx CHANGED
@@ -1,35 +1,64 @@
1
  import React, { useState } from "react"
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  export default function App() {
4
- const [threshold, setThreshold] = useState(0.0)
5
  const [context, setContext] = useState("")
6
  const [wordlist, setWordlist] = useState("")
7
  const [showWholePrompt, setShowWholePrompt] = useState(false)
8
- const [checked, setChecked] = useState(false)
9
  const [text, setText] = useState("")
 
 
10
 
11
- const click = () => {
12
- setChecked(true)
 
 
 
 
 
 
13
  }
14
 
15
  let result
16
 
17
- if (checked === null) {
18
- result = <textarea value={text} />
19
  } else {
20
- result = <div className="result">
21
- {text}
22
- </div>
 
 
 
 
 
 
 
 
 
23
  }
24
 
25
  return (
26
- <>
27
  <h1>GPTed</h1>
28
 
29
  <details>
30
  <summary>Advanced settings</summary>
31
  <label>
32
- <strong>Threshold:</strong> <input type="number" step="0.1" value={threshold} />
33
  <small>
34
  The <a href="https://en.wikipedia.org/wiki/Log_probability" target="_blank" rel="noreferrer">logprob</a> threshold.
35
  Tokens with logprobs smaller than this will be marked red.
@@ -37,15 +66,15 @@ export default function App() {
37
  </label>
38
  <label>
39
  <strong>Context:</strong> <small>Context for the text, which can help GPT3 better rank certain words.</small>
40
- <textarea placeholder="A short essay about picnics" value={context} />
41
  </label>
42
  <label>
43
  <strong>Dictionary:</strong>
44
  <small>Known words or phrases. Helpful for uncommon or invented words and names.</small>
45
- <textarea placeholder="jujubu eschaton Frodo Baggins" value={wordlist} />
46
  </label>
47
  <label>
48
- <strong>Show whole prompt:</strong> <input type="checkbox" checked={showWholePrompt} />
49
  <small>
50
  Show the whole prompt in the token view, instead of just your text. Mostly useful for debugging or curiosity.
51
  </small>
@@ -54,8 +83,8 @@ export default function App() {
54
 
55
  <section id="inner">
56
  {result}
57
- <button onClick={click}>
58
- {checked ? "Check" : "Edit"}
59
  </button>
60
 
61
  <p>
@@ -67,6 +96,6 @@ export default function App() {
67
  </small>
68
  </p>
69
  </section>
70
- </>
71
  )
72
  }
 
1
  import React, { useState } from "react"
2
+ import { TokenChip } from "./TokenChip"
3
+
4
+ interface Word {
5
+ text: string
6
+ logprob: number
7
+ }
8
+
9
+ async function checkText(text: string): Promise<Word[]> {
10
+ await new Promise(resolve => setTimeout(resolve, 3000));
11
+
12
+ const words = text.split(/\b/)
13
+ return words.map(word => ({ text: word, logprob: -word.length }))
14
+ }
15
 
16
  export default function App() {
17
+ const [threshold, setThreshold] = useState(-5.0)
18
  const [context, setContext] = useState("")
19
  const [wordlist, setWordlist] = useState("")
20
  const [showWholePrompt, setShowWholePrompt] = useState(false)
 
21
  const [text, setText] = useState("")
22
+ const [mode, setMode] = useState<"edit" | "check">("edit")
23
+ const [words, setWords] = useState<Word[]>([])
24
 
25
+ const toggleMode = async () => {
26
+ if (mode === "edit") {
27
+ const checkedWords = await checkText(text)
28
+ setWords(checkedWords)
29
+ setMode("check")
30
+ } else {
31
+ setMode("edit")
32
+ }
33
  }
34
 
35
  let result
36
 
37
+ if (mode === "edit") {
38
+ result = <textarea value={text} onChange={e => setText(e.target.value)} />
39
  } else {
40
+ result = (
41
+ <div className="result">
42
+ {words.map((word, index) => (
43
+ <TokenChip
44
+ key={index}
45
+ token={word.text}
46
+ logprob={word.logprob}
47
+ threshold={threshold}
48
+ />
49
+ ))}
50
+ </div>
51
+ )
52
  }
53
 
54
  return (
55
+ <main>
56
  <h1>GPTed</h1>
57
 
58
  <details>
59
  <summary>Advanced settings</summary>
60
  <label>
61
+ <strong>Threshold:</strong> <input type="number" step="0.1" value={threshold} onChange={e => setThreshold(Number(e.target.value))} />
62
  <small>
63
  The <a href="https://en.wikipedia.org/wiki/Log_probability" target="_blank" rel="noreferrer">logprob</a> threshold.
64
  Tokens with logprobs smaller than this will be marked red.
 
66
  </label>
67
  <label>
68
  <strong>Context:</strong> <small>Context for the text, which can help GPT3 better rank certain words.</small>
69
+ <textarea placeholder="A short essay about picnics" value={context} onChange={e => setContext(e.target.value)} />
70
  </label>
71
  <label>
72
  <strong>Dictionary:</strong>
73
  <small>Known words or phrases. Helpful for uncommon or invented words and names.</small>
74
+ <textarea placeholder="jujubu eschaton Frodo Baggins" value={wordlist} onChange={e => setWordlist(e.target.value)} />
75
  </label>
76
  <label>
77
+ <strong>Show whole prompt:</strong> <input type="checkbox" checked={showWholePrompt} onChange={e => setShowWholePrompt(e.target.checked)} />
78
  <small>
79
  Show the whole prompt in the token view, instead of just your text. Mostly useful for debugging or curiosity.
80
  </small>
 
83
 
84
  <section id="inner">
85
  {result}
86
+ <button onClick={toggleMode}>
87
+ {mode === "edit" ? "Check" : "Edit"}
88
  </button>
89
 
90
  <p>
 
96
  </small>
97
  </p>
98
  </section>
99
+ </main>
100
  )
101
  }
frontend/src/index.tsx CHANGED
@@ -1,3 +1,4 @@
 
1
  import { createRoot } from "react-dom/client"
2
  import App from "./components/app"
3
 
@@ -5,4 +6,4 @@ const app = document.getElementById("app")
5
 
6
  const root = createRoot(app!)
7
 
8
- root.render(App())
 
1
+ import React from "react"
2
  import { createRoot } from "react-dom/client"
3
  import App from "./components/app"
4
 
 
6
 
7
  const root = createRoot(app!)
8
 
9
+ root.render(<App />)