victor HF Staff commited on
Commit
d3fe503
·
0 Parent(s):

Add message trimmer demo with real WildChat conversations

Browse files
Files changed (1) hide show
  1. index.html +516 -0
index.html ADDED
@@ -0,0 +1,516 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Message Trimmer Demo - WildChat Conversations</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
16
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
+ padding: 20px;
18
+ min-height: 100vh;
19
+ }
20
+
21
+ .container {
22
+ max-width: 1200px;
23
+ margin: 0 auto;
24
+ background: white;
25
+ border-radius: 12px;
26
+ box-shadow: 0 20px 60px rgba(0,0,0,0.3);
27
+ overflow: hidden;
28
+ }
29
+
30
+ header {
31
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
32
+ color: white;
33
+ padding: 30px;
34
+ text-align: center;
35
+ }
36
+
37
+ h1 {
38
+ font-size: 2em;
39
+ margin-bottom: 10px;
40
+ }
41
+
42
+ .subtitle {
43
+ opacity: 0.9;
44
+ font-size: 0.95em;
45
+ }
46
+
47
+ .controls {
48
+ padding: 25px 30px;
49
+ background: #f8f9fa;
50
+ border-bottom: 1px solid #e9ecef;
51
+ }
52
+
53
+ .control-group {
54
+ margin-bottom: 20px;
55
+ }
56
+
57
+ .control-group:last-child {
58
+ margin-bottom: 0;
59
+ }
60
+
61
+ label {
62
+ display: block;
63
+ font-weight: 600;
64
+ margin-bottom: 8px;
65
+ color: #495057;
66
+ font-size: 0.9em;
67
+ }
68
+
69
+ input[type="range"] {
70
+ width: 100%;
71
+ height: 6px;
72
+ border-radius: 3px;
73
+ background: #dee2e6;
74
+ outline: none;
75
+ -webkit-appearance: none;
76
+ }
77
+
78
+ input[type="range"]::-webkit-slider-thumb {
79
+ -webkit-appearance: none;
80
+ appearance: none;
81
+ width: 18px;
82
+ height: 18px;
83
+ border-radius: 50%;
84
+ background: #667eea;
85
+ cursor: pointer;
86
+ }
87
+
88
+ input[type="range"]::-moz-range-thumb {
89
+ width: 18px;
90
+ height: 18px;
91
+ border-radius: 50%;
92
+ background: #667eea;
93
+ cursor: pointer;
94
+ border: none;
95
+ }
96
+
97
+ .value-display {
98
+ display: inline-block;
99
+ background: #667eea;
100
+ color: white;
101
+ padding: 4px 12px;
102
+ border-radius: 12px;
103
+ font-size: 0.85em;
104
+ font-weight: 600;
105
+ margin-left: 10px;
106
+ }
107
+
108
+ select {
109
+ width: 100%;
110
+ padding: 10px;
111
+ border: 2px solid #dee2e6;
112
+ border-radius: 6px;
113
+ font-size: 0.95em;
114
+ background: white;
115
+ cursor: pointer;
116
+ }
117
+
118
+ select:focus {
119
+ outline: none;
120
+ border-color: #667eea;
121
+ }
122
+
123
+ .conversation {
124
+ padding: 30px;
125
+ }
126
+
127
+ .message {
128
+ margin-bottom: 30px;
129
+ animation: fadeIn 0.3s ease-in;
130
+ }
131
+
132
+ @keyframes fadeIn {
133
+ from { opacity: 0; transform: translateY(10px); }
134
+ to { opacity: 1; transform: translateY(0); }
135
+ }
136
+
137
+ .message-header {
138
+ display: flex;
139
+ align-items: center;
140
+ margin-bottom: 12px;
141
+ gap: 10px;
142
+ }
143
+
144
+ .role-badge {
145
+ padding: 6px 14px;
146
+ border-radius: 20px;
147
+ font-size: 0.75em;
148
+ font-weight: 700;
149
+ text-transform: uppercase;
150
+ letter-spacing: 0.5px;
151
+ }
152
+
153
+ .role-user {
154
+ background: #e7f5ff;
155
+ color: #1971c2;
156
+ }
157
+
158
+ .role-assistant {
159
+ background: #f3f0ff;
160
+ color: #5f3dc4;
161
+ }
162
+
163
+ .char-count {
164
+ font-size: 0.75em;
165
+ color: #868e96;
166
+ font-weight: 500;
167
+ }
168
+
169
+ .message-content {
170
+ background: #f8f9fa;
171
+ padding: 20px;
172
+ border-radius: 8px;
173
+ border-left: 4px solid #dee2e6;
174
+ position: relative;
175
+ }
176
+
177
+ .message-user .message-content {
178
+ border-left-color: #1971c2;
179
+ }
180
+
181
+ .message-assistant .message-content {
182
+ border-left-color: #5f3dc4;
183
+ }
184
+
185
+ .original {
186
+ margin-bottom: 15px;
187
+ padding-bottom: 15px;
188
+ border-bottom: 2px dashed #dee2e6;
189
+ }
190
+
191
+ .trimmed {
192
+ background: #fff3bf;
193
+ padding: 15px;
194
+ border-radius: 6px;
195
+ border: 2px solid #ffd43b;
196
+ }
197
+
198
+ .section-label {
199
+ font-size: 0.7em;
200
+ font-weight: 700;
201
+ text-transform: uppercase;
202
+ letter-spacing: 0.5px;
203
+ color: #495057;
204
+ margin-bottom: 8px;
205
+ }
206
+
207
+ .trimmed .section-label {
208
+ color: #e67700;
209
+ }
210
+
211
+ .content-text {
212
+ line-height: 1.6;
213
+ color: #212529;
214
+ white-space: pre-wrap;
215
+ word-wrap: break-word;
216
+ }
217
+
218
+ .stats {
219
+ margin-top: 10px;
220
+ padding: 10px;
221
+ background: rgba(255,255,255,0.7);
222
+ border-radius: 4px;
223
+ font-size: 0.8em;
224
+ color: #495057;
225
+ }
226
+
227
+ .stats strong {
228
+ color: #212529;
229
+ }
230
+
231
+ .reduction {
232
+ color: #e67700;
233
+ font-weight: 600;
234
+ }
235
+
236
+ .code-reference {
237
+ background: #f8f9fa;
238
+ border: 1px solid #dee2e6;
239
+ border-radius: 6px;
240
+ padding: 20px;
241
+ margin: 20px 30px;
242
+ font-family: 'Monaco', 'Menlo', monospace;
243
+ font-size: 0.85em;
244
+ line-height: 1.6;
245
+ }
246
+
247
+ .code-reference h3 {
248
+ margin-bottom: 15px;
249
+ color: #495057;
250
+ font-size: 1em;
251
+ }
252
+
253
+ .code-line {
254
+ color: #212529;
255
+ margin: 4px 0;
256
+ }
257
+
258
+ .comment {
259
+ color: #6c757d;
260
+ }
261
+
262
+ button {
263
+ background: #667eea;
264
+ color: white;
265
+ border: none;
266
+ padding: 10px 20px;
267
+ border-radius: 6px;
268
+ cursor: pointer;
269
+ font-size: 0.9em;
270
+ font-weight: 600;
271
+ margin-top: 10px;
272
+ }
273
+
274
+ button:hover {
275
+ background: #5568d3;
276
+ }
277
+
278
+ .info-box {
279
+ background: #e7f5ff;
280
+ border: 2px solid #1971c2;
281
+ border-radius: 8px;
282
+ padding: 20px;
283
+ margin: 20px 30px;
284
+ }
285
+
286
+ .info-box h3 {
287
+ color: #1971c2;
288
+ margin-bottom: 10px;
289
+ font-size: 1em;
290
+ }
291
+
292
+ .info-box p {
293
+ color: #495057;
294
+ line-height: 1.6;
295
+ font-size: 0.9em;
296
+ }
297
+
298
+ .no-trim {
299
+ background: #d3f9d8;
300
+ padding: 15px;
301
+ border-radius: 6px;
302
+ border: 2px solid #51cf66;
303
+ }
304
+
305
+ .no-trim .section-label {
306
+ color: #2b8a3e;
307
+ }
308
+ </style>
309
+ </head>
310
+ <body>
311
+ <div class="container">
312
+ <header>
313
+ <h1>Message Trimmer Demo</h1>
314
+ <p class="subtitle">Demonstrating trim functions on real WildChat-1M conversations</p>
315
+ </header>
316
+
317
+ <div class="info-box">
318
+ <h3>About This Demo</h3>
319
+ <p>
320
+ This demo shows how the <strong>trimMiddle()</strong> function works in the LLM router architecture.
321
+ The function trims messages by keeping the start (60%) and end (40%) with a clear
322
+ <strong>[... CONTENT TRIMMED ...]</strong> indicator in between,
323
+ reducing token count while preserving context for intent classification.
324
+ Adjust the max length sliders below to see how different messages are trimmed.
325
+ </p>
326
+ </div>
327
+
328
+ <div class="controls">
329
+ <div class="control-group">
330
+ <label>
331
+ Max Assistant Message Length: <span class="value-display" id="assistantLengthValue">500</span>
332
+ </label>
333
+ <input type="range" id="assistantLength" min="50" max="1000" value="500" step="10">
334
+ </div>
335
+
336
+ <div class="control-group">
337
+ <label>
338
+ Max Previous User Message Length: <span class="value-display" id="userLengthValue">400</span>
339
+ </label>
340
+ <input type="range" id="userLength" min="50" max="1000" value="400" step="10">
341
+ </div>
342
+
343
+ <div class="control-group">
344
+ <label>Select Conversation:</label>
345
+ <select id="conversationSelect">
346
+ <option value="0">Loading conversations...</option>
347
+ </select>
348
+ </div>
349
+ </div>
350
+
351
+ <div class="code-reference">
352
+ <h3>Implementation (from src/lib/server/router/arch.ts)</h3>
353
+ <div class="code-line"><span class="comment">// Trim assistant messages to reduce routing prompt size</span></div>
354
+ <div class="code-line">if (m.role === "assistant") {</div>
355
+ <div class="code-line">&nbsp;&nbsp;return { ...m, content: trimMiddle(m.content, maxAssistantLength) };</div>
356
+ <div class="code-line">}</div>
357
+ <div class="code-line"></div>
358
+ <div class="code-line"><span class="comment">// Trim previous user messages (latest preserved)</span></div>
359
+ <div class="code-line">if (m.role === "user" && idx !== lastUserIndex) {</div>
360
+ <div class="code-line">&nbsp;&nbsp;return { ...m, content: trimMiddle(m.content, maxPrevUserLength) };</div>
361
+ <div class="code-line">}</div>
362
+ </div>
363
+
364
+ <div id="conversationDisplay" class="conversation">
365
+ <p style="text-align: center; color: #868e96;">Loading conversations...</p>
366
+ </div>
367
+ </div>
368
+
369
+ <script>
370
+ // Implementation of trimMiddle function from arch.ts
371
+ function trimMiddle(content, maxLength) {
372
+ if (content.length <= maxLength) return content;
373
+
374
+ const indicator = " [... CONTENT TRIMMED ...] ";
375
+ const availableLength = maxLength - indicator.length;
376
+
377
+ if (availableLength <= 0) {
378
+ return content.slice(0, maxLength);
379
+ }
380
+
381
+ // Reserve more space for the start (60%)
382
+ const startLength = Math.ceil(availableLength * 0.6);
383
+ const endLength = availableLength - startLength;
384
+
385
+ if (endLength <= 0) {
386
+ return content.slice(0, availableLength) + indicator;
387
+ }
388
+
389
+ const start = content.slice(0, startLength);
390
+ const end = content.slice(-endLength);
391
+
392
+ return start + indicator + end;
393
+ }
394
+
395
+ // Fetch and store conversations
396
+ let conversations = [];
397
+
398
+ async function loadConversations() {
399
+ try {
400
+ const response = await fetch('https://datasets-server.huggingface.co/rows?dataset=allenai%2FWildChat-1M&config=default&split=train&offset=0&length=100');
401
+ const data = await response.json();
402
+
403
+ // Filter for conversations with multiple turns
404
+ conversations = data.rows
405
+ .filter(row => row.row.conversation && row.row.conversation.length >= 2)
406
+ .map(row => row.row.conversation)
407
+ .slice(0, 20); // Take first 20 conversations
408
+
409
+ populateConversationSelect();
410
+ displayConversation(0);
411
+ } catch (error) {
412
+ console.error('Error loading conversations:', error);
413
+ document.getElementById('conversationDisplay').innerHTML =
414
+ '<p style="text-align: center; color: #dc3545;">Error loading conversations. Please refresh the page.</p>';
415
+ }
416
+ }
417
+
418
+ function populateConversationSelect() {
419
+ const select = document.getElementById('conversationSelect');
420
+ select.innerHTML = conversations.map((conv, idx) => {
421
+ const preview = conv[0].content.slice(0, 60).replace(/\n/g, ' ');
422
+ return `<option value="${idx}">Conversation ${idx + 1}: ${preview}...</option>`;
423
+ }).join('');
424
+ }
425
+
426
+ function displayConversation(index) {
427
+ const conversation = conversations[index];
428
+ if (!conversation) return;
429
+
430
+ const assistantLength = parseInt(document.getElementById('assistantLength').value);
431
+ const userLength = parseInt(document.getElementById('userLength').value);
432
+
433
+ const lastUserIndex = conversation.map((m, idx) => ({ idx, role: m.role }))
434
+ .reverse()
435
+ .find(m => m.role === 'user')?.idx ?? -1;
436
+
437
+ let html = '';
438
+
439
+ conversation.forEach((message, idx) => {
440
+ const isUser = message.role === 'user';
441
+ const isLastUser = idx === lastUserIndex;
442
+ const content = message.content;
443
+ let trimmed = content;
444
+ let shouldTrim = false;
445
+
446
+ // Apply trimming logic
447
+ if (message.role === 'assistant') {
448
+ trimmed = trimMiddle(content, assistantLength);
449
+ shouldTrim = content.length > assistantLength;
450
+ } else if (message.role === 'user' && !isLastUser) {
451
+ trimmed = trimMiddle(content, userLength);
452
+ shouldTrim = content.length > userLength;
453
+ }
454
+
455
+ const reductionPercent = shouldTrim ?
456
+ (((content.length - trimmed.length) / content.length) * 100).toFixed(1) : 0;
457
+
458
+ html += `
459
+ <div class="message message-${message.role}">
460
+ <div class="message-header">
461
+ <span class="role-badge role-${message.role}">${message.role}</span>
462
+ <span class="char-count">${content.length} characters</span>
463
+ ${isLastUser ? '<span class="char-count" style="color: #2b8a3e; font-weight: 600;">★ Latest user message - preserved</span>' : ''}
464
+ </div>
465
+ <div class="message-content">
466
+ <div class="original">
467
+ <div class="section-label">Original</div>
468
+ <div class="content-text">${escapeHtml(content)}</div>
469
+ </div>
470
+ <div class="${shouldTrim ? 'trimmed' : 'no-trim'}">
471
+ <div class="section-label">${shouldTrim ? 'Trimmed for Router' : 'No Trimming Required'}</div>
472
+ <div class="content-text">${escapeHtml(trimmed)}</div>
473
+ ${shouldTrim ? `
474
+ <div class="stats">
475
+ <strong>Original:</strong> ${content.length} chars |
476
+ <strong>Trimmed:</strong> ${trimmed.length} chars |
477
+ <span class="reduction">Reduced by ${reductionPercent}%</span>
478
+ </div>
479
+ ` : ''}
480
+ </div>
481
+ </div>
482
+ </div>
483
+ `;
484
+ });
485
+
486
+ document.getElementById('conversationDisplay').innerHTML = html;
487
+ }
488
+
489
+ function escapeHtml(text) {
490
+ const div = document.createElement('div');
491
+ div.textContent = text;
492
+ return div.innerHTML;
493
+ }
494
+
495
+ // Event listeners
496
+ document.getElementById('assistantLength').addEventListener('input', (e) => {
497
+ document.getElementById('assistantLengthValue').textContent = e.target.value;
498
+ const selectedIndex = parseInt(document.getElementById('conversationSelect').value);
499
+ displayConversation(selectedIndex);
500
+ });
501
+
502
+ document.getElementById('userLength').addEventListener('input', (e) => {
503
+ document.getElementById('userLengthValue').textContent = e.target.value;
504
+ const selectedIndex = parseInt(document.getElementById('conversationSelect').value);
505
+ displayConversation(selectedIndex);
506
+ });
507
+
508
+ document.getElementById('conversationSelect').addEventListener('change', (e) => {
509
+ displayConversation(parseInt(e.target.value));
510
+ });
511
+
512
+ // Initialize
513
+ loadConversations();
514
+ </script>
515
+ </body>
516
+ </html>