File size: 4,504 Bytes
8214506
e9e1da2
a88e9cf
308bca9
82b1b1d
 
a88e9cf
 
 
 
 
c4d5641
 
8214506
82b1b1d
8214506
 
 
308bca9
 
82b1b1d
 
0970991
8214506
a54cb5b
bbae7a9
 
 
 
 
 
 
 
 
 
82b1b1d
 
0970991
a54cb5b
82b1b1d
 
 
8214506
 
e9e1da2
a54cb5b
 
 
 
 
 
 
1fe47b1
a54cb5b
 
 
1fe47b1
 
8214506
 
82b1b1d
0970991
 
 
 
 
 
8214506
82b1b1d
0970991
 
 
 
e9e1da2
0970991
e9e1da2
0970991
 
1fe47b1
e9e1da2
0970991
 
 
82b1b1d
 
8214506
 
 
82b1b1d
8214506
 
 
 
 
bbae7a9
8214506
 
 
 
 
 
 
82b1b1d
8214506
 
 
 
82b1b1d
8214506
 
82b1b1d
8214506
 
 
 
 
 
 
 
82b1b1d
 
8214506
 
 
 
bbae7a9
 
8214506
 
 
 
 
82b1b1d
8214506
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import React, { useState } from "react"
import { WordChip } from "./WordChip"
import { Spinner } from "./Spinner"
import { Word } from "../interfaces"

async function checkText(text: string): Promise<Word[]> {
  const encodedText = encodeURIComponent(text);
  const response = await fetch(`/check?text=${encodedText}`);
  const data = await response.json();
  console.log(data);
  return data.words;
}

export default function App() {
  const [threshold, setThreshold] = useState(-5.0)
  const [context, setContext] = useState("")
  const [wordlist, setWordlist] = useState("")
  const [showWholePrompt, setShowWholePrompt] = useState(false)
  // const [text, setText] = useState("I just drove to the store to but eggs, but they had some.")
  const [text, setText] = useState("I drove to the stove to but eggs")
  const [mode, setMode] = useState<"edit" | "check">("edit")
  const [words, setWords] = useState<Word[]>([])
  const [isLoading, setIsLoading] = useState(false)

  const check = async (text: string) => {
    setIsLoading(true)
    try {
      const checkedWords = await checkText(text)
      setWords(checkedWords)
    } finally {
      setIsLoading(false)
      setMode("check")
    }
  }

  const toggleMode = async () => {
    if (mode === "edit") {
      setIsLoading(true)
      await check(text)
    } else {
      setMode("edit")
    }
  }

  const handleReplace = async (index: number, newWord: string) => {
    console.log("handleReplace", index, newWord)
    const updatedWords = words.map((w, i) => {
      if (i === index) {
        return { text: newWord, logprob: 0, replacements: [] }
      }
      return w
    })
    setWords(updatedWords)
    const newText = updatedWords.map(w => w.text).join("")
    setText(newText)
    await check(newText)
  }

  let result

  if (mode === "edit") {
    result = (
      <div className="result-container">
        {isLoading && <Spinner />}
        <textarea value={text} onChange={e => setText(e.target.value)} />
      </div>
    )
  } else {
    result = (
      <div className="result-container">
        {isLoading && <Spinner />}
        <div className="result">
          {words.map((word, index) => (
            <WordChip
              key={index}
              word={word.text}
              logprob={word.logprob}
              threshold={threshold}
              replacements={word.replacements}
              onReplace={(newWord) => handleReplace(index, newWord)}
            />
          ))}
        </div>
      </div>
    )
  }

  return (
    <main>
      <h1>GPTed</h1>

      <details>
        <summary>Advanced settings</summary>
        <label>
          <strong>Threshold:</strong> <input type="number" step="1" value={threshold} onChange={e => setThreshold(Number(e.target.value))} />
          <small>
            The <a href="https://en.wikipedia.org/wiki/Log_probability" target="_blank" rel="noreferrer">logprob</a> threshold.
            Tokens with logprobs smaller than this will be marked red.
          </small>
        </label>
        <label>
          <strong>Context:</strong> <small>Context for the text, which can help GPT3 better rank certain words.</small>
          <textarea placeholder="A short essay about picnics" value={context} onChange={e => setContext(e.target.value)} />
        </label>
        <label>
          <strong>Dictionary:</strong>
          <small>Known words or phrases. Helpful for uncommon or invented words and names.</small>
          <textarea placeholder="jujubu eschaton Frodo Baggins" value={wordlist} onChange={e => setWordlist(e.target.value)} />
        </label>
        <label>
          <strong>Show whole prompt:</strong> <input type="checkbox" checked={showWholePrompt} onChange={e => setShowWholePrompt(e.target.checked)} />
          <small>
            Show the whole prompt in the token view, instead of just your text. Mostly useful for debugging or curiosity.
          </small>
        </label>
      </details>

      <section id="inner">
        {result}
        <button onClick={toggleMode}>
          {mode === "edit" ? "Check" : "Edit"}
        </button>

        <p>
          <small>
            Based on <a href="https://github.com/vgel/gpted">GPTed</a> by <a href="https://vgel.me">Theia Vogel</a>.
            Made with React, Transformers, LLama 3.2, and transitively, most of the web.
            <br />
            This software is provided with absolutely no warranty.
          </small>
        </p>
      </section>
    </main>
  )
}