Skip to content

Commit 2d777ba

Browse files
jeremymanningclaude
andcommitted
fix(demos): Resolve JavaScript errors across multiple demos
Fixes issue #32 - Demo 02: Use encode()+decode() instead of non-existent tokenize() - Demo 04: Align Transformers.js version to 2.17.1 - Demo 05: Switch OrbitControls CDN to jsdelivr for reliability - Demo 10: Switch Compromise NLP CDN to jsdelivr - Demo 13: Add proper ES module import for Transformers.js Root causes addressed: - Transformers.js requires ES module imports, not window globals - Unreliable CDNs replaced with jsdelivr - Corrected API method usage for tokenizers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent f9237a9 commit 2d777ba

File tree

6 files changed

+119
-13
lines changed

6 files changed

+119
-13
lines changed

demos/02-tokenization/js/tokenizer-comparison.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,21 +148,32 @@ async function tokenizeText(text) {
148148

149149
// Process individual tokenizer
150150
async function processTokenizer(name, text, tokenizer) {
151+
// encode() returns the token IDs as an array
151152
const encoded = await tokenizer.encode(text);
152-
const tokens = await tokenizer.tokenize(text);
153+
154+
// Get token strings by decoding each ID individually
155+
// This works around the fact that tokenize() may not be available
156+
const tokens = [];
157+
for (let i = 0; i < encoded.length; i++) {
158+
const tokenStr = tokenizer.decode([encoded[i]], { skip_special_tokens: false });
159+
tokens.push(tokenStr);
160+
}
153161

154162
const outputDiv = document.getElementById(`${name}-output`);
155163
const idsDiv = document.getElementById(`${name}-ids`);
156164
const tokenCountSpan = document.getElementById(`${name}-token-count`);
157165
const ratioSpan = document.getElementById(`${name}-ratio`);
158166

159-
// Clear previous output
160-
outputDiv.innerHTML = '';
167+
// Clear previous output using safe DOM method
168+
while (outputDiv.firstChild) {
169+
outputDiv.removeChild(outputDiv.firstChild);
170+
}
161171

162172
// Display tokens with colors
163173
tokens.forEach((token, idx) => {
164174
const span = document.createElement('span');
165175
span.className = `token token-${idx % 8}`;
176+
// Clean up special characters for display
166177
span.textContent = token.replace(//g, '·').replace(/Ġ/g, '·');
167178
span.title = `Token ID: ${encoded[idx]}`;
168179
outputDiv.appendChild(span);
@@ -183,7 +194,10 @@ async function processTokenizer(name, text, tokenizer) {
183194
// Clear all outputs
184195
function clearOutputs() {
185196
['gpt2', 'bert', 't5'].forEach(name => {
186-
document.getElementById(`${name}-output`).innerHTML = '';
197+
const outputEl = document.getElementById(`${name}-output`);
198+
while (outputEl.firstChild) {
199+
outputEl.removeChild(outputEl.firstChild);
200+
}
187201
document.getElementById(`${name}-ids`).textContent = '';
188202
document.getElementById(`${name}-token-count`).textContent = 'Tokens: -';
189203
document.getElementById(`${name}-ratio`).textContent = 'Ratio: -';

demos/04-attention/js/attention-extractor.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Uses Transformers.js to load models and retrieve attention patterns
44
*/
55

6-
import { pipeline, AutoTokenizer, AutoModel } from 'https://cdn.jsdelivr.net/npm/@xenova/[email protected].2';
6+
import { pipeline, AutoTokenizer, AutoModel } from 'https://cdn.jsdelivr.net/npm/@xenova/[email protected].1';
77

88
export class AttentionExtractor {
99
constructor() {

demos/05-transformer/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<link rel="stylesheet" href="../shared/css/demo-styles.css">
88
<link rel="stylesheet" href="css/transformer.css">
99
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
10-
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
10+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
1111
<script src="https://d3js.org/d3.v7.min.js"></script>
1212
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
1313
</head>

demos/10-pos-tagging/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<link rel="stylesheet" href="../shared/css/demo-styles.css">
88
<link rel="stylesheet" href="css/pos.css">
99
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
10-
<script src="https://unpkg.com/[email protected]/builds/compromise.min.js"></script>
10+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/builds/compromise.min.js"></script>
1111
</head>
1212
<body>
1313
<nav class="demo-nav">

demos/13-bert-mlm/js/bert-model.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
* Handles masked language modeling and attention extraction
44
*/
55

6+
// Import Transformers.js at module level
7+
import { pipeline, AutoTokenizer, AutoModelForMaskedLM, Tensor } from 'https://cdn.jsdelivr.net/npm/@xenova/[email protected]';
8+
69
export class BERTModel {
710
constructor(modelId = 'bert-base-uncased') {
811
this.modelId = modelId;
@@ -18,8 +21,6 @@ export class BERTModel {
1821
console.log(`Loading model: ${this.modelId}`);
1922

2023
try {
21-
// Import Transformers.js
22-
const { pipeline, AutoTokenizer, AutoModelForMaskedLM } = window.Transformers;
2324

2425
// Load tokenizer
2526
this.tokenizer = await AutoTokenizer.from_pretrained(this.modelId);
@@ -88,8 +89,7 @@ export class BERTModel {
8889
maskedInputIds[idx] = this.maskTokenId;
8990
});
9091

91-
// Create input tensor
92-
const { Tensor } = await import('https://cdn.jsdelivr.net/npm/@xenova/[email protected]');
92+
// Create input tensor (Tensor is now imported at module level)
9393
const inputs = {
9494
input_ids: new Tensor('int64', BigInt64Array.from(maskedInputIds.map(id => BigInt(id))), [1, maskedInputIds.length]),
9595
attention_mask: new Tensor('int64', BigInt64Array.from(maskedInputIds.map(() => BigInt(1))), [1, maskedInputIds.length])
@@ -231,8 +231,6 @@ export class BERTModel {
231231
* Fill mask using the fill-mask pipeline (alternative method)
232232
*/
233233
async fillMaskPipeline(text) {
234-
const { pipeline } = window.Transformers;
235-
236234
const unmasker = await pipeline('fill-mask', this.modelId);
237235
const results = await unmasker(text);
238236

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Session Notes: JavaScript Error Fixes (Issue #32)
2+
3+
## Date: 2026-01-01
4+
5+
## Summary
6+
7+
Fixed JavaScript errors in multiple LLM course demos as documented in GitHub issue #32.
8+
9+
## Changes Made
10+
11+
### 1. Demo 02 (Tokenization) - `tokenizer.tokenize is not a function`
12+
**File:** `demos/02-tokenization/js/tokenizer-comparison.js`
13+
14+
**Issue:** The `tokenizer.tokenize()` method doesn't exist in Transformers.js AutoTokenizer. Only `encode()` and `decode()` are available.
15+
16+
**Fix:** Changed the implementation to:
17+
1. Use `tokenizer.encode(text)` to get token IDs
18+
2. Decode each token ID individually with `tokenizer.decode([id])` to get token strings
19+
3. Also fixed innerHTML usage to use safe DOM methods (removeChild loop)
20+
21+
### 2. Demo 04 (Attention) - Version Inconsistency
22+
**File:** `demos/04-attention/js/attention-extractor.js`
23+
24+
**Issue:** Used Transformers.js version @2.17.2 while other demos use @2.17.1
25+
26+
**Fix:** Changed import to use consistent version @2.17.1
27+
28+
### 3. Demo 05 (Transformer) - OrbitControls Error
29+
**File:** `demos/05-transformer/index.html`
30+
31+
**Issue:** OrbitControls was loaded from `https://threejs.org/examples/js/controls/OrbitControls.js` which may not be available or have CORS issues.
32+
33+
**Fix:** Changed to use jsdelivr CDN: `https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js`
34+
35+
### 4. Demo 10 (POS Tagging) - `nlp is not defined`
36+
**File:** `demos/10-pos-tagging/index.html`
37+
38+
**Issue:** Compromise.js was loaded from unpkg CDN which may have reliability issues.
39+
40+
**Fix:** Changed from `https://unpkg.com/[email protected]/builds/compromise.min.js` to `https://cdn.jsdelivr.net/npm/[email protected]/builds/compromise.min.js`
41+
42+
### 5. Demo 13 (BERT MLM) - Transformers.js Not Loading
43+
**File:** `demos/13-bert-mlm/js/bert-model.js`
44+
45+
**Issue:** The code tried to destructure `{ pipeline, AutoTokenizer, AutoModelForMaskedLM }` from `window.Transformers`, but the Transformers.js script tag doesn't set a global `window.Transformers` object.
46+
47+
**Fix:**
48+
1. Added ES module import at top of file: `import { pipeline, AutoTokenizer, AutoModelForMaskedLM, Tensor } from 'https://cdn.jsdelivr.net/npm/@xenova/[email protected]'`
49+
2. Removed references to `window.Transformers`
50+
3. Moved `Tensor` import to module level instead of dynamic import
51+
52+
## Demos Analyzed But Not Changed
53+
54+
The following demos were analyzed and found to have correct code structure. Their issues are likely environment-related:
55+
56+
### Demo 01 (ELIZA) - Path Error
57+
- Code correctly loads from `data/eliza-rules.json`
58+
- The JSON file exists at the correct path
59+
- Issue may be CORS/local file access when not using a web server
60+
61+
### Demo 03, 12, 14 (Embeddings, Semantic Search, Embeddings Comparison) - ES Module Issues
62+
- All three demos already have `type="module"` on script tags
63+
- Code correctly uses ES module syntax
64+
- Dynamic imports use proper CDN URLs
65+
- Issue may be CORS or CDN availability
66+
67+
### Demo 07 (RAG) - Model Loading Fails
68+
- Uses dynamic import for Transformers.js (correct approach)
69+
- Data file `wikipedia-articles.json` exists (5MB)
70+
- Issue is likely network-related (large model download, CDN availability)
71+
72+
### Demo 11 (Analogies) - Plotly 3D Cameraposition Error
73+
- Visualization code uses correct Plotly layout syntax
74+
- Camera configuration is properly structured: `camera: { eye: { x, y, z } }`
75+
- Error may be intermittent or browser-specific
76+
77+
## Root Causes Identified
78+
79+
1. **CDN Reliability:** unpkg and threejs.org direct links can be unreliable. jsdelivr is more consistent.
80+
81+
2. **Transformers.js API:**
82+
- No `window.Transformers` global - must use ES module imports
83+
- `tokenizer.tokenize()` doesn't exist - use `encode()` + `decode()`
84+
85+
3. **Three.js OrbitControls:** Must use versioned CDN URL that matches Three.js version
86+
87+
4. **ES Modules:** Script tags must have `type="module"` for import/export syntax
88+
89+
## Files Changed
90+
- `demos/02-tokenization/js/tokenizer-comparison.js`
91+
- `demos/04-attention/js/attention-extractor.js`
92+
- `demos/05-transformer/index.html`
93+
- `demos/10-pos-tagging/index.html`
94+
- `demos/13-bert-mlm/js/bert-model.js`

0 commit comments

Comments
 (0)