| <!doctype html> |
| <html> |
| <head> |
| <meta charset="utf-8" /> |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| <title>Selma Lagerlof trigram language model</title> |
| <style> |
| body { font-family: system-ui, sans-serif; max-width: 40rem; |
| margin: 3rem auto; padding: 0 1rem; line-height: 1.5; } |
| input { width: 100%; padding: .6rem; font-size: 1rem; } |
| table { border-collapse: collapse; margin-top: 1rem; } |
| td { padding: .2rem 1.5rem .2rem 0; } |
| td.count { color: #666; } |
| #status { color: #666; } |
| </style> |
| </head> |
| <body> |
| <h1>Selma Lagerlof trigram language model</h1> |
| <p>Type the beginning of a Swedish sentence. The model proposes the five |
| most frequent continuations, counted on the novels of Selma Lagerlof |
| (EDAN20, lab 2).</p> |
|
|
| <input id="box" value="Det var en" disabled /> |
| <p id="status">Loading the trigram counts...</p> |
| <table id="out"></table> |
|
|
| <script> |
| const CAND_NBR = 5; |
| let trigrams = null; |
| |
| |
| fetch('trigrams_compact.json') |
| .then(r => r.json()) |
| .then(data => { |
| trigrams = data; |
| document.getElementById('status').textContent = |
| Object.keys(data).length.toLocaleString() + ' contexts loaded.'; |
| document.getElementById('box').disabled = false; |
| predict(); |
| }) |
| .catch(e => { |
| document.getElementById('status').textContent = 'Could not load: ' + e; |
| }); |
| |
| function predict() { |
| if (!trigrams) return; |
| const tokens = document.getElementById('box').value.toLowerCase().split(/\s+/) |
| .filter(t => t.length > 0); |
| |
| |
| const padded = ['</s>', '<s>'].concat(tokens); |
| const context = padded.slice(-2).join(' '); |
| const candidates = trigrams[context]; |
| |
| const out = document.getElementById('out'); |
| out.innerHTML = ''; |
| if (!candidates) { |
| out.innerHTML = '<tr><td>No prediction, this context is not in the corpus.</td></tr>'; |
| return; |
| } |
| |
| const best = Object.entries(candidates).sort( |
| (a, b) => (b[1] - a[1]) || (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0)); |
| for (const [word, count] of best.slice(0, CAND_NBR)) { |
| const row = out.insertRow(); |
| row.insertCell().textContent = word; |
| const c = row.insertCell(); |
| c.textContent = count; |
| c.className = 'count'; |
| } |
| } |
| |
| document.getElementById('box').addEventListener('input', predict); |
| </script> |
| </body> |
| </html> |
|
|