Snapshot
Browse files- .gitignore +1 -0
- frontend/src/components/TokenChip.tsx +61 -9
- frontend/src/components/app.tsx +17 -3
- requirements.txt +1 -0
.gitignore
CHANGED
|
@@ -1,3 +1,4 @@
|
|
| 1 |
/.aider*
|
| 2 |
/.env
|
| 3 |
/.venv/
|
|
|
|
|
|
| 1 |
/.aider*
|
| 2 |
/.env
|
| 3 |
/.venv/
|
| 4 |
+
/__pycache__/
|
frontend/src/components/TokenChip.tsx
CHANGED
|
@@ -1,10 +1,62 @@
|
|
| 1 |
-
import React from "react"
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
}
|
|
|
|
| 1 |
+
import React, { useState } from "react"
|
| 2 |
+
|
| 3 |
+
import React, { useState } from "react"
|
| 4 |
+
|
| 5 |
+
export const TokenChip = ({
|
| 6 |
+
token,
|
| 7 |
+
logprob,
|
| 8 |
+
threshold,
|
| 9 |
+
replacements,
|
| 10 |
+
onReplace
|
| 11 |
+
}: {
|
| 12 |
+
token: string,
|
| 13 |
+
logprob: number,
|
| 14 |
+
threshold: number,
|
| 15 |
+
replacements: string[],
|
| 16 |
+
onReplace: (newToken: string) => void
|
| 17 |
+
}) => {
|
| 18 |
+
const [isExpanded, setIsExpanded] = useState(false);
|
| 19 |
+
|
| 20 |
+
const handleClick = () => {
|
| 21 |
+
if (logprob < threshold && replacements.length > 0) {
|
| 22 |
+
setIsExpanded(true);
|
| 23 |
+
}
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
const handleReplacement = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
| 27 |
+
const newToken = event.target.value
|
| 28 |
+
if (newToken !== token) {
|
| 29 |
+
onReplace(newToken)
|
| 30 |
+
}
|
| 31 |
+
setIsExpanded(false);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
return (
|
| 35 |
+
<span
|
| 36 |
+
title={logprob.toFixed(2)}
|
| 37 |
+
className={`token-chip ${logprob < threshold ? "flagged" : ""}`}
|
| 38 |
+
style={{ position: "relative", cursor: logprob < threshold ? "pointer" : "default" }}
|
| 39 |
+
onClick={handleClick}
|
| 40 |
+
>
|
| 41 |
+
{token}
|
| 42 |
+
{isExpanded && (
|
| 43 |
+
<select
|
| 44 |
+
onChange={handleReplacement}
|
| 45 |
+
value={token}
|
| 46 |
+
style={{
|
| 47 |
+
position: "absolute",
|
| 48 |
+
top: "100%",
|
| 49 |
+
left: 0,
|
| 50 |
+
zIndex: 1000
|
| 51 |
+
}}
|
| 52 |
+
size={replacements.length}
|
| 53 |
+
autoFocus
|
| 54 |
+
>
|
| 55 |
+
{replacements.map((rep, idx) => (
|
| 56 |
+
<option key={idx} value={rep}>{rep}</option>
|
| 57 |
+
))}
|
| 58 |
+
</select>
|
| 59 |
+
)}
|
| 60 |
+
</span>
|
| 61 |
+
)
|
| 62 |
}
|
frontend/src/components/app.tsx
CHANGED
|
@@ -8,10 +8,14 @@ interface Word {
|
|
| 8 |
}
|
| 9 |
|
| 10 |
async function checkText(text: string): Promise<Word[]> {
|
| 11 |
-
await new Promise(resolve => setTimeout(resolve,
|
| 12 |
|
| 13 |
const words = text.split(/\b/)
|
| 14 |
-
return words.map(word => ({
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
}
|
| 16 |
|
| 17 |
// Add a new Spinner component
|
|
@@ -26,7 +30,7 @@ export default function App() {
|
|
| 26 |
const [context, setContext] = useState("")
|
| 27 |
const [wordlist, setWordlist] = useState("")
|
| 28 |
const [showWholePrompt, setShowWholePrompt] = useState(false)
|
| 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)
|
|
@@ -46,6 +50,14 @@ export default function App() {
|
|
| 46 |
}
|
| 47 |
}
|
| 48 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
let result
|
| 50 |
|
| 51 |
if (mode === "edit") {
|
|
@@ -66,6 +78,8 @@ export default function App() {
|
|
| 66 |
token={word.text}
|
| 67 |
logprob={word.logprob}
|
| 68 |
threshold={threshold}
|
|
|
|
|
|
|
| 69 |
/>
|
| 70 |
))}
|
| 71 |
</div>
|
|
|
|
| 8 |
}
|
| 9 |
|
| 10 |
async function checkText(text: string): Promise<Word[]> {
|
| 11 |
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
| 12 |
|
| 13 |
const words = text.split(/\b/)
|
| 14 |
+
return words.map(word => ({
|
| 15 |
+
text: word,
|
| 16 |
+
logprob: -word.length,
|
| 17 |
+
replacements: word.length < 4 ? [] : ["foo", "bar"]
|
| 18 |
+
}))
|
| 19 |
}
|
| 20 |
|
| 21 |
// Add a new Spinner component
|
|
|
|
| 30 |
const [context, setContext] = useState("")
|
| 31 |
const [wordlist, setWordlist] = useState("")
|
| 32 |
const [showWholePrompt, setShowWholePrompt] = useState(false)
|
| 33 |
+
const [text, setText] = useState("The cumbersomely quick brown fox jumps over the conspicuously lazy dog.")
|
| 34 |
const [mode, setMode] = useState<"edit" | "check">("edit")
|
| 35 |
const [words, setWords] = useState<Word[]>([])
|
| 36 |
const [isLoading, setIsLoading] = useState(false)
|
|
|
|
| 50 |
}
|
| 51 |
}
|
| 52 |
|
| 53 |
+
const handleReplace = (index: number, newToken: string) => {
|
| 54 |
+
const updatedWords = [...words]
|
| 55 |
+
updatedWords[index].text = newToken
|
| 56 |
+
setWords(updatedWords)
|
| 57 |
+
setText(updatedWords.map(w => w.text).join(""))
|
| 58 |
+
setMode("edit")
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
let result
|
| 62 |
|
| 63 |
if (mode === "edit") {
|
|
|
|
| 78 |
token={word.text}
|
| 79 |
logprob={word.logprob}
|
| 80 |
threshold={threshold}
|
| 81 |
+
replacements={word.replacements}
|
| 82 |
+
onReplace={(newToken) => handleReplace(index, newToken)}
|
| 83 |
/>
|
| 84 |
))}
|
| 85 |
</div>
|
requirements.txt
CHANGED
|
@@ -4,3 +4,4 @@ ipywidgets
|
|
| 4 |
transformers
|
| 5 |
torch
|
| 6 |
huggingface_hub
|
|
|
|
|
|
| 4 |
transformers
|
| 5 |
torch
|
| 6 |
huggingface_hub
|
| 7 |
+
fastapi[standard]
|