mebubo commited on
Commit
0970991
·
1 Parent(s): 82b1b1d
frontend/.gitignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ /node_modules/
2
+ /public/*.js*
frontend/public/index.css CHANGED
@@ -91,15 +91,10 @@ label.missing > input {
91
  border: 1px solid red;
92
  }
93
 
94
- label > textarea {
95
  flex-basis: 100%;
96
  }
97
 
98
- #api-token > button {
99
- width: 5rem;
100
- padding: 0.2rem;
101
- }
102
-
103
  details > summary {
104
  text-align: left;
105
  }
@@ -135,3 +130,42 @@ span.token-chip {
135
  span.token-chip.flagged {
136
  background-color: #dd1111;
137
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  border: 1px solid red;
92
  }
93
 
94
+ textarea {
95
  flex-basis: 100%;
96
  }
97
 
 
 
 
 
 
98
  details > summary {
99
  text-align: left;
100
  }
 
130
  span.token-chip.flagged {
131
  background-color: #dd1111;
132
  }
133
+
134
+ .result-container {
135
+ position: relative;
136
+ }
137
+
138
+ .result-container textarea {
139
+ position: absolute;
140
+ top: 0;
141
+ left: 0;
142
+ right: 0;
143
+ bottom: 0;
144
+ }
145
+
146
+ .spinner-overlay {
147
+ position: absolute;
148
+ top: 0;
149
+ left: 0;
150
+ right: 0;
151
+ bottom: 0;
152
+ background-color: rgba(255, 255, 255, 0.7);
153
+ display: flex;
154
+ justify-content: center;
155
+ align-items: center;
156
+ z-index: 10;
157
+ }
158
+
159
+ .spinner {
160
+ border: 4px solid #f3f3f3;
161
+ border-top: 4px solid #3498db;
162
+ border-radius: 50%;
163
+ width: 40px;
164
+ height: 40px;
165
+ animation: spin 1s linear infinite;
166
+ }
167
+
168
+ @keyframes spin {
169
+ 0% { transform: rotate(0deg); }
170
+ 100% { transform: rotate(360deg); }
171
+ }
frontend/src/components/TokenChip.tsx ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ import React from "react"
2
+
3
+ export const TokenChip = ({ token, logprob, threshold }: { token: string, logprob: number, threshold: number }) => {
4
+ return <span
5
+ title={logprob.toFixed(2)}
6
+ className={`token-chip ${logprob < threshold ? "flagged" : ""}`}
7
+ >
8
+ {token}
9
+ </span>
10
+ }
frontend/src/components/app.tsx CHANGED
@@ -4,15 +4,23 @@ import { TokenChip } from "./TokenChip"
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("")
@@ -21,12 +29,18 @@ export default function App() {
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
  }
@@ -35,18 +49,26 @@ export default function App() {
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
  }
 
4
  interface Word {
5
  text: string
6
  logprob: number
7
+ replacements: string[]
8
  }
9
 
10
  async function checkText(text: string): Promise<Word[]> {
11
  await new Promise(resolve => setTimeout(resolve, 3000));
12
 
13
  const words = text.split(/\b/)
14
+ return words.map(word => ({ text: word, logprob: -word.length, replacements: word.length < 4 ? [] : ["foo", "bar"] }))
15
  }
16
 
17
+ // Add a new Spinner component
18
+ const Spinner = () => (
19
+ <div className="spinner-overlay">
20
+ <div className="spinner"></div>
21
+ </div>
22
+ );
23
+
24
  export default function App() {
25
  const [threshold, setThreshold] = useState(-5.0)
26
  const [context, setContext] = useState("")
 
29
  const [text, setText] = useState("")
30
  const [mode, setMode] = useState<"edit" | "check">("edit")
31
  const [words, setWords] = useState<Word[]>([])
32
+ const [isLoading, setIsLoading] = useState(false)
33
 
34
  const toggleMode = async () => {
35
  if (mode === "edit") {
36
+ setIsLoading(true)
37
+ try {
38
+ const checkedWords = await checkText(text)
39
+ setWords(checkedWords)
40
+ } finally {
41
+ setMode("check")
42
+ setIsLoading(false)
43
+ }
44
  } else {
45
  setMode("edit")
46
  }
 
49
  let result
50
 
51
  if (mode === "edit") {
52
+ result = (
53
+ <div className="result-container">
54
+ {isLoading && <Spinner />}
55
+ <textarea value={text} onChange={e => setText(e.target.value)} />
56
+ </div>
57
+ )
58
  } else {
59
  result = (
60
+ <div className="result-container">
61
+ {isLoading && <Spinner />}
62
+ <div className="result">
63
+ {words.map((word, index) => (
64
+ <TokenChip
65
+ key={index}
66
+ token={word.text}
67
+ logprob={word.logprob}
68
+ threshold={threshold}
69
+ />
70
+ ))}
71
+ </div>
72
  </div>
73
  )
74
  }