Debanjum commited on
Commit
e6162a8
·
1 Parent(s): d8a31af

Make url shareable with model, text set via url query params

Browse files

This allows for deep link references to model and text visualization.

The URL is automatically updated with the model, text used to
tokenize. This should ease copy/paste url sharing from address bar.

Files changed (2) hide show
  1. app.py +4 -1
  2. templates/index.html +79 -1
app.py CHANGED
@@ -43,7 +43,10 @@ def load_tokenizer(model_id: str):
43
 
44
  @app.route("/")
45
  def index():
46
- return render_template("index.html")
 
 
 
47
 
48
 
49
  @app.route("/tokenize", methods=["POST"])
 
43
 
44
  @app.route("/")
45
  def index():
46
+ # Get query parameters
47
+ model_id = request.args.get("model", "").strip() or request.args.get("model_id", "").strip()
48
+ text = request.args.get("text", "").strip()
49
+ return render_template("index.html", model_id=model_id, text=text)
50
 
51
 
52
  @app.route("/tokenize", methods=["POST"])
templates/index.html CHANGED
@@ -304,6 +304,39 @@
304
  word-break: break-all;
305
  }
306
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
307
  footer {
308
  text-align: center;
309
  margin-top: 30px;
@@ -330,6 +363,7 @@
330
  id="model-id"
331
  placeholder="e.g., openai-community/gpt2"
332
  autocomplete="off"
 
333
  >
334
  <div class="suggestions" id="suggestions"></div>
335
  </div>
@@ -340,7 +374,7 @@
340
  <textarea
341
  id="text-input"
342
  placeholder="Enter text to tokenize..."
343
- >Hello, world! This is a test of the tokenizer visualization tool.</textarea>
344
  </div>
345
 
346
  <button class="btn" id="tokenize-btn">Tokenize</button>
@@ -362,6 +396,9 @@
362
  <div class="stat-value" id="char-count">0</div>
363
  <div class="stat-label">Characters</div>
364
  </div>
 
 
 
365
  </div>
366
 
367
  <label>Tokenized Output <span style="font-weight: normal; color: #888;">(hover for token IDs)</span></label>
@@ -399,6 +436,14 @@
399
  let suggestions = [];
400
  let currentTokens = [];
401
 
 
 
 
 
 
 
 
 
402
  // Load model suggestions
403
  fetch('/models/suggestions')
404
  .then(res => res.json())
@@ -472,6 +517,12 @@
472
  return;
473
  }
474
 
 
 
 
 
 
 
475
  hideError();
476
  resultsDiv.classList.add('hidden');
477
  loadingDiv.classList.add('show');
@@ -545,6 +596,33 @@
545
  showIdsCheckbox.addEventListener('change', () => {
546
  tokenIdsDiv.classList.toggle('hidden', !showIdsCheckbox.checked);
547
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
548
  </script>
549
  </body>
550
  </html>
 
304
  word-break: break-all;
305
  }
306
 
307
+ .btn-share {
308
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
309
+ color: white;
310
+ border: none;
311
+ padding: 8px 16px;
312
+ font-size: 14px;
313
+ font-weight: 600;
314
+ border-radius: 8px;
315
+ cursor: pointer;
316
+ transition: transform 0.2s, box-shadow 0.2s, opacity 0.2s;
317
+ display: inline-flex;
318
+ align-items: center;
319
+ gap: 6px;
320
+ margin-left: auto;
321
+ }
322
+
323
+ .btn-share:hover {
324
+ transform: translateY(-1px);
325
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
326
+ }
327
+
328
+ .btn-share.copied {
329
+ background: #48bb78;
330
+ }
331
+
332
+ .stats {
333
+ display: flex;
334
+ gap: 20px;
335
+ margin-bottom: 20px;
336
+ flex-wrap: wrap;
337
+ align-items: center;
338
+ }
339
+
340
  footer {
341
  text-align: center;
342
  margin-top: 30px;
 
363
  id="model-id"
364
  placeholder="e.g., openai-community/gpt2"
365
  autocomplete="off"
366
+ value="{{ model_id }}"
367
  >
368
  <div class="suggestions" id="suggestions"></div>
369
  </div>
 
374
  <textarea
375
  id="text-input"
376
  placeholder="Enter text to tokenize..."
377
+ >{% if text %}{{ text }}{% else %}Hello, world! This is how I see text tokens.{% endif %}</textarea>
378
  </div>
379
 
380
  <button class="btn" id="tokenize-btn">Tokenize</button>
 
396
  <div class="stat-value" id="char-count">0</div>
397
  <div class="stat-label">Characters</div>
398
  </div>
399
+ <button class="btn-share" id="share-btn" title="Copy shareable URL to clipboard">
400
+ 🔗 Share
401
+ </button>
402
  </div>
403
 
404
  <label>Tokenized Output <span style="font-weight: normal; color: #888;">(hover for token IDs)</span></label>
 
436
  let suggestions = [];
437
  let currentTokens = [];
438
 
439
+ // Auto-tokenize if both model and text are provided via URL
440
+ const hasModel = modelInput.value.trim() !== '';
441
+ const hasText = textInput.value.trim() !== '';
442
+ if (hasModel && hasText) {
443
+ // Trigger tokenization after page loads
444
+ setTimeout(() => tokenize(), 100);
445
+ }
446
+
447
  // Load model suggestions
448
  fetch('/models/suggestions')
449
  .then(res => res.json())
 
517
  return;
518
  }
519
 
520
+ // Update URL with query parameters
521
+ const url = new URL(window.location);
522
+ url.searchParams.set('model', modelId);
523
+ url.searchParams.set('text', text);
524
+ window.history.pushState({}, '', url);
525
+
526
  hideError();
527
  resultsDiv.classList.add('hidden');
528
  loadingDiv.classList.add('show');
 
596
  showIdsCheckbox.addEventListener('change', () => {
597
  tokenIdsDiv.classList.toggle('hidden', !showIdsCheckbox.checked);
598
  });
599
+
600
+ // Share URL button
601
+ const shareBtn = document.getElementById('share-btn');
602
+
603
+ shareBtn.addEventListener('click', async () => {
604
+ const modelId = modelInput.value.trim();
605
+ const text = textInput.value;
606
+
607
+ // Build the share URL
608
+ const shareUrl = new URL(window.location.origin + window.location.pathname);
609
+ shareUrl.searchParams.set('model', modelId);
610
+ shareUrl.searchParams.set('text', text);
611
+
612
+ try {
613
+ await navigator.clipboard.writeText(shareUrl.toString());
614
+ shareBtn.textContent = '✓ Copied!';
615
+ shareBtn.classList.add('copied');
616
+
617
+ setTimeout(() => {
618
+ shareBtn.innerHTML = '🔗 Share';
619
+ shareBtn.classList.remove('copied');
620
+ }, 2000);
621
+ } catch (err) {
622
+ // Fallback: select text in a prompt
623
+ window.prompt('Copy this URL:', shareUrl.toString());
624
+ }
625
+ });
626
  </script>
627
  </body>
628
  </html>