File size: 3,262 Bytes
8c96555
308bca9
1fe47b1
a88e9cf
 
 
 
308bca9
a88e9cf
 
 
 
e9e1da2
1fe47b1
 
 
 
a88e9cf
8c96555
a88e9cf
 
8c96555
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1fe47b1
a88e9cf
 
 
 
 
1fe47b1
0a795e1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308bca9
 
 
 
 
1fe47b1
8c96555
 
 
 
 
1fe47b1
0a795e1
 
 
8c96555
a88e9cf
8c96555
 
 
 
 
a88e9cf
 
 
 
 
 
 
8c96555
 
308bca9
a88e9cf
 
308bca9
a88e9cf
 
 
 
 
308bca9
 
a88e9cf
 
308bca9
a88e9cf
8c96555
a88e9cf
8c96555
 
1fe47b1
0970991
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
import React, { useState, useEffect, useRef } from "react"
import { Replacement } from "../interfaces";

interface WordChipProps {
  word: string;
  logprob: number;
  threshold: number;
  replacements: Replacement[];
  onReplace: (newWord: string) => Promise<void>;
}

export function WordChip({
  word,
  logprob,
  threshold,
  replacements,
  onReplace
}: WordChipProps) {
  const [isExpanded, setIsExpanded] = useState(false);
  const [selectedIndex, setSelectedIndex] = useState(-1);
  const dropdownRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
        setIsExpanded(false);
      }
    };

    document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, []);

  const handleClick = () => {
    if (logprob < threshold && replacements.length > 0) {
      setIsExpanded(true);
    }
  }

  const handleReplacement = async (newWord: string) => {
    console.log("handleReplacement", newWord);
    await onReplace(newWord);
    setIsExpanded(false);  // Close the dropdown
  };

  console.log(`word: ->${word}<-`);

  let w1;
  let w2;
  let w3;
  // if word contains a newline, render a <br />
  if (word.includes("\n")) {
    [w1, w3] = word.split("\n");
    w2 = "\n";
    console.log(`split: ${w1} | ${w2} | ${w3}`);
  } else {
    w1 = word;
    w2 = "";
    w3 = "";
  }

  // sort replacements by logprob (make sure not to mutate the original array)
  const sortedReplacements = [...replacements].sort((a, b) => b.logprob - a.logprob)
  // convert logprobs to probabilities
  const withProbabilities = sortedReplacements.map(r => ({ ...r, probability: Math.exp(r.logprob)*100 }))

  return (
    <span
      title={logprob.toFixed(2)}
      className={`word-chip ${logprob < threshold ? "flagged" : ""}`}
      style={{ position: "relative", cursor: logprob < threshold ? "pointer" : "default" }}
      onClick={handleClick}
    >
      {w1}
      {w2 && <br />}
      {w3}
      {isExpanded && (
        <div
          ref={dropdownRef}
          style={{
            position: "absolute",
            top: "100%",
            left: 0,
            zIndex: 100,
            maxHeight: "400px",
            overflowY: "auto",
            backgroundColor: "white",
            border: "1px solid #ccc",
            borderRadius: "4px",
            boxShadow: "0 2px 4px rgba(0,0,0,0.1)"
          }}
        >
          {withProbabilities.map((option, index) => (
            <div
              key={index}
              onClick={() => handleReplacement(option.text)}
              onMouseEnter={() => setSelectedIndex(index)}
              style={{
                padding: "5px 10px",
                cursor: "pointer",
                color: "black",
                backgroundColor: selectedIndex === index ? "#f0f0f0" : "white",
                whiteSpace: "nowrap"
              }}
            >
              {option.text} <small style={{ fontSize: "0.7em", color: "#666" }}>{option.probability.toFixed(1)}%</small>
            </div>
          ))}
        </div>
      )}
    </span>
  )
}