File size: 2,499 Bytes
db764ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { useState } from "react";
import { api } from "../api";
import { useApiCall } from "../hooks/useApiCall";
import ScoreBar from "./ScoreBar";
import StatusMessage from "./StatusMessage";

interface SimilarWord {
  word: string;
  score: number;
}

export default function SimilarWords() {
  const [word, setWord] = useState("");
  const [topK, setTopK] = useState(10);
  const { data: results, loading, error, run } = useApiCall<SimilarWord[]>();

  async function handleSearch() {
    if (!word.trim()) return;
    await run(() => api.similarWords({ word: word.trim(), top_k: topK }).then((r) => r.similar));
  }

  return (
    <div>
      <div className="panel">
        <h2>Similar Words</h2>
        <p className="panel-desc">
          Find words that appear in similar contexts using transformer embeddings.
          Unlike Word2Vec (static, one vector per word), this uses the model's contextual understanding.
        </p>
        <div className="form-row">
          <div className="form-group">
            <label>Word</label>
            <input
              value={word}
              onChange={(e) => setWord(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && handleSearch()}
              placeholder="e.g. Epstein, flight, island"
            />
          </div>
          <div className="form-group form-group-sm">
            <label>Top K</label>
            <input type="number" value={topK} onChange={(e) => setTopK(+e.target.value)} min={1} max={50} />
          </div>
          <div className="form-group form-group-sm">
            <label>&nbsp;</label>
            <button className="btn btn-primary" onClick={handleSearch} disabled={loading || !word.trim()}>
              {loading ? "Searching..." : "Find"}
            </button>
          </div>
        </div>
      </div>

      {error && <StatusMessage type="err" message={error} />}

      {results && results.length > 0 && (
        <div className="panel">
          <h3>Words similar to "{word}" ({results.length})</h3>
          <table className="data-table">
            <thead>
              <tr><th>Word</th><th>Similarity</th></tr>
            </thead>
            <tbody>
              {results.map((r, i) => (
                <tr key={i}>
                  <td style={{ fontWeight: 600 }}>{r.word}</td>
                  <td><ScoreBar score={r.score} /></td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}