jasleen02 commited on
Commit
adc0cc3
·
verified ·
1 Parent(s): e0ac6c4

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +82 -74
index.html CHANGED
@@ -3,84 +3,50 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
6
 
7
- <title>English → Swedish Translator</title>
8
-
9
- <script
10
- type="module"
11
- crossorigin
12
- src="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.js">
13
- </script>
14
-
15
- <link
16
- rel="stylesheet"
17
- crossorigin
18
- href="https://cdn.jsdelivr.net/npm/@gradio/lite/dist/lite.css">
19
 
20
  <style>
21
- body {
22
- max-width: 900px;
23
- margin: 0 auto;
24
- padding: 24px;
25
- font-family: Arial, sans-serif;
26
- }
27
-
28
- #status {
29
- color: #555;
30
- margin: 8px 0 18px;
31
- }
32
-
33
- #error {
34
- color: #b00020;
35
- white-space: pre-wrap;
36
- margin-top: 12px;
37
- }
38
-
39
- textarea {
40
- width: 100%;
41
- min-height: 120px;
42
- padding: 12px;
43
- box-sizing: border-box;
44
- font-size: 16px;
45
- }
46
-
47
- button {
48
- margin: 14px 0;
49
- padding: 10px 18px;
50
- font-size: 16px;
51
- cursor: pointer;
52
- }
53
  </style>
54
  </head>
55
 
56
  <body>
57
- <h1>English → Swedish Translator</h1>
58
  <p>
59
- This translation model runs directly in your browser.
60
- The first translation can take a little while because the model must download.
61
  </p>
62
 
63
- <p id="status">Loading translation model…</p>
64
 
65
- <label for="input">English text</label>
66
- <textarea
67
- id="input"
68
- placeholder="Write an English sentence here..."
69
- disabled
70
- ></textarea>
71
 
72
  <br>
73
-
74
  <button id="translate-button" disabled>Translate</button>
75
 
76
- <label for="output">Swedish translation</label>
77
  <textarea id="output" readonly></textarea>
78
 
79
  <p id="error"></p>
80
 
81
- <script type="module">
82
- import { pipeline, env } from
83
- "https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.0.2";
 
 
 
 
 
 
 
 
84
 
85
  const status = document.getElementById("status");
86
  const input = document.getElementById("input");
@@ -88,32 +54,68 @@
88
  const button = document.getElementById("translate-button");
89
  const errorBox = document.getElementById("error");
90
 
91
- let translator;
92
 
93
  async function loadModel() {
94
  try {
95
- env.allowLocalModels = false;
 
96
 
97
- translator = await pipeline(
98
- "translation",
99
- "Xenova/opus-mt-en-sv"
100
- );
101
 
102
- status.textContent = "Model ready. Enter English text and click Translate.";
103
  input.disabled = false;
104
  button.disabled = false;
105
  } catch (error) {
106
  console.error(error);
107
- status.textContent = "The translation model could not load.";
108
  errorBox.textContent = String(error);
109
  }
110
  }
111
 
112
- button.addEventListener("click", async () => {
113
- const text = input.value.trim();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
  if (!text) {
116
- output.value = "Please write something first.";
117
  return;
118
  }
119
 
@@ -122,9 +124,10 @@
122
  errorBox.textContent = "";
123
 
124
  try {
125
- const result = await translator(text);
126
- output.value = result[0].translation_text;
127
- status.textContent = "Done.";
 
128
  } catch (error) {
129
  console.error(error);
130
  status.textContent = "Translation failed.";
@@ -132,9 +135,14 @@
132
  } finally {
133
  button.disabled = false;
134
  }
 
 
 
 
 
135
  });
136
 
137
  loadModel();
138
  </script>
139
  </body>
140
- </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Swedish → English Translator</title>
7
 
8
+ <script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.20.1/dist/ort.min.js"></script>
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  <style>
11
+ body { max-width: 900px; margin: 0 auto; padding: 24px; font-family: Arial, sans-serif; }
12
+ #status { color: #555; margin: 8px 0 18px; }
13
+ #error { color: #b00020; white-space: pre-wrap; margin-top: 12px; }
14
+ textarea { width: 100%; min-height: 120px; padding: 12px; box-sizing: border-box; font-size: 16px; }
15
+ button { margin: 14px 0; padding: 10px 18px; font-size: 16px; cursor: pointer; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  </style>
17
  </head>
18
 
19
  <body>
20
+ <h1>Swedish → English Translator</h1>
21
  <p>
22
+ This is our own character-level Transformer from the lab, running directly in your browser.
23
+ Sentences up to 120 characters work best (that is what it was trained on).
24
  </p>
25
 
26
+ <p id="status">Loading model…</p>
27
 
28
+ <label for="input">Swedish text</label>
29
+ <textarea id="input" placeholder="Skriv en svensk mening här..." disabled></textarea>
 
 
 
 
30
 
31
  <br>
 
32
  <button id="translate-button" disabled>Translate</button>
33
 
34
+ <label for="output">English translation</label>
35
  <textarea id="output" readonly></textarea>
36
 
37
  <p id="error"></p>
38
 
39
+ <script>
40
+ // Files produced by export_onnx.py, placed next to this page
41
+ const ENCODER_URL = "encoder.onnx";
42
+ const DECODER_URL = "decoder.onnx";
43
+ const VOCAB_URL = "vocab.json";
44
+
45
+ // Same constants as the notebook
46
+ const TRAIN_MAX_LEN = 120; // max_len
47
+ const MAX_LEN = TRAIN_MAX_LEN + 2; // + <s> and </s>
48
+
49
+ ort.env.wasm.wasmPaths = "https://cdn.jsdelivr.net/npm/onnxruntime-web@1.20.1/dist/";
50
 
51
  const status = document.getElementById("status");
52
  const input = document.getElementById("input");
 
54
  const button = document.getElementById("translate-button");
55
  const errorBox = document.getElementById("error");
56
 
57
+ let encoder, decoder, token2idx, idx2token;
58
 
59
  async function loadModel() {
60
  try {
61
+ token2idx = await (await fetch(VOCAB_URL)).json();
62
+ idx2token = Object.fromEntries(Object.entries(token2idx).map(([t, i]) => [i, t]));
63
 
64
+ const opts = { executionProviders: ["wasm"] };
65
+ encoder = await ort.InferenceSession.create(ENCODER_URL, opts);
66
+ decoder = await ort.InferenceSession.create(DECODER_URL, opts);
 
67
 
68
+ status.textContent = "Model ready. Enter Swedish text and click Translate.";
69
  input.disabled = false;
70
  button.disabled = false;
71
  } catch (error) {
72
  console.error(error);
73
+ status.textContent = "The model could not load.";
74
  errorBox.textContent = String(error);
75
  }
76
  }
77
 
78
+ // seqs2tensors: <s> + characters + </s>, unknown characters -> <unk> (1)
79
+ function encode(text) {
80
+ const chars = Array.from(text); // iterates by code point, like Python's list(str)
81
+ return [token2idx["<s>"], ...chars.map(c => token2idx[c] ?? 1), token2idx["</s>"]];
82
+ }
83
+
84
+ const toTensor = ids =>
85
+ new ort.Tensor("int64", BigInt64Array.from(ids, BigInt), [1, ids.length]);
86
+
87
+ function argmax(arr) {
88
+ let best = 0;
89
+ for (let i = 1; i < arr.length; i++) if (arr[i] > arr[best]) best = i;
90
+ return best;
91
+ }
92
+
93
+ // Same loop as greedy_decode_batched in the notebook
94
+ async function translate(text) {
95
+ const src = encode(text);
96
+ const memory = (await encoder.run({ src: toTensor(src) })).memory;
97
+
98
+ const eos = token2idx["</s>"];
99
+ const tgt = [token2idx["<s>"]];
100
+ const maxLen = Math.min(src.length + 20, MAX_LEN);
101
 
102
+ for (let step = 0; step < maxLen - 1; step++) {
103
+ const logits = (await decoder.run({ tgt: toTensor(tgt), memory })).logits.data;
104
+ const next = argmax(logits);
105
+ tgt.push(next);
106
+ if (next === eos) break;
107
+ }
108
+
109
+ return tgt.slice(1)
110
+ .filter(i => i !== eos)
111
+ .map(i => idx2token[i] ?? "<unk>")
112
+ .join("");
113
+ }
114
+
115
+ async function run() {
116
+ const text = input.value.trim();
117
  if (!text) {
118
+ output.value = "Skriv något först.";
119
  return;
120
  }
121
 
 
124
  errorBox.textContent = "";
125
 
126
  try {
127
+ output.value = await translate(text);
128
+ status.textContent = text.length > TRAIN_MAX_LEN
129
+ ? `Done. Note: the input is longer than ${TRAIN_MAX_LEN} characters, so the result may be poor.`
130
+ : "Done.";
131
  } catch (error) {
132
  console.error(error);
133
  status.textContent = "Translation failed.";
 
135
  } finally {
136
  button.disabled = false;
137
  }
138
+ }
139
+
140
+ button.addEventListener("click", run);
141
+ input.addEventListener("keydown", e => {
142
+ if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); run(); }
143
  });
144
 
145
  loadModel();
146
  </script>
147
  </body>
148
+ </html>