yasserrmd commited on
Commit
a41c437
Β·
verified Β·
1 Parent(s): 5bdac71

Upload index.html

Browse files
Files changed (1) hide show
  1. index.html +91 -36
index.html CHANGED
@@ -265,6 +265,18 @@
265
 
266
  #model-progress-bar { transition: width 0.4s ease; }
267
 
 
 
 
 
 
 
 
 
 
 
 
 
268
  .chip {
269
  display: inline-flex; align-items: center; gap: 6px;
270
  background: #1c2128; border: 1px solid #30363d; border-radius: 20px;
@@ -297,6 +309,16 @@
297
  <div class="text-xs" style="color:#8b949e">IT Support Assistant</div>
298
  </div>
299
  </div>
 
 
 
 
 
 
 
 
 
 
300
  <div id="model-status-wrap" class="ml-auto flex items-center gap-3">
301
  <div id="model-progress-wrap" class="w-36 h-1 rounded-full hidden" style="background:#21262d">
302
  <div id="model-progress-bar" class="h-1 rounded-full" style="width:0%;background:#388bfd"></div>
@@ -1469,12 +1491,32 @@ document.querySelectorAll('.chip').forEach(chip => {
1469
  sendMessage();
1470
  });
1471
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1472
  </script>
1473
 
1474
  <!-- ── WebGPU / LLM module ───────────────────────────────────────────────── -->
1475
  <script type="module">
1476
  import { pipeline, TextStreamer, env }
1477
- from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3.5.0/dist/transformers.min.js';
1478
 
1479
  env.allowLocalModels = false;
1480
  if (env.backends?.onnx?.wasm) {
@@ -1482,7 +1524,6 @@ if (env.backends?.onnx?.wasm) {
1482
  env.backends.onnx.wasm.wasmPaths = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/';
1483
  }
1484
 
1485
- const MODEL_ID = 'HuggingFaceTB/SmolLM2-360M-Instruct';
1486
  const statusEl = document.getElementById('model-status');
1487
  const progressWrap= document.getElementById('model-progress-wrap');
1488
  const progressBar = document.getElementById('model-progress-bar');
@@ -1499,36 +1540,7 @@ function setStatusUI(text, color, pct) {
1499
  }
1500
  }
1501
 
1502
- if (!navigator.gpu) {
1503
- window._llm.status = 'unavailable';
1504
- setStatusUI('⚠️ Templates only (no WebGPU)', '#d29922', null);
1505
- setTimeout(() => statusWrap.classList.add('hidden'), 4000);
1506
- } else {
1507
- setStatusUI('⏳ Loading AI…', '#d29922', 0);
1508
- progressWrap.classList.remove('hidden');
1509
-
1510
- (async () => {
1511
- window._llm.status = 'loading';
1512
- try {
1513
- window._llm.generator = await pipeline('text-generation', MODEL_ID, {
1514
- dtype: 'q4',
1515
- device: 'webgpu',
1516
- progress_callback: (p) => {
1517
- if (p.status !== 'progress') return;
1518
- setStatusUI(`⏳ Loading AI… ${Math.round(p.progress ?? 0)}%`, '#d29922', p.progress ?? 0);
1519
- },
1520
- });
1521
- window._llm.status = 'ready';
1522
- setStatusUI('βœ… AI model ready', '#3fb950', null);
1523
- setTimeout(() => statusWrap.classList.add('hidden'), 3000);
1524
- } catch (err) {
1525
- console.error('[DeskFlow] Model load failed:', err);
1526
- window._llm.status = 'error';
1527
- setStatusUI('⚠️ Templates only (AI unavailable)', '#d29922', null);
1528
- setTimeout(() => statusWrap.classList.add('hidden'), 5000);
1529
- }
1530
- })();
1531
-
1532
  window._llmGenerate = async function(systemPrompt, userPrompt, templateFallback, onToken, onDone, onFallback) {
1533
  if (!window._llm.generator) { onFallback(templateFallback); return; }
1534
  try {
@@ -1539,10 +1551,7 @@ if (!navigator.gpu) {
1539
  let accumulated = '';
1540
  const streamer = new TextStreamer(window._llm.generator.tokenizer, {
1541
  skip_prompt: true,
1542
- callback_function: (token) => {
1543
- accumulated += token;
1544
- onToken(accumulated);
1545
- },
1546
  });
1547
  const result = await window._llm.generator(messages, {
1548
  max_new_tokens: 512,
@@ -1558,6 +1567,52 @@ if (!navigator.gpu) {
1558
  }
1559
  };
1560
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1561
  </script>
1562
 
1563
  </body>
 
265
 
266
  #model-progress-bar { transition: width 0.4s ease; }
267
 
268
+ /* Model switcher pills */
269
+ .model-pill {
270
+ background: #1c2128; border: 1px solid #30363d; border-radius: 20px;
271
+ padding: 3px 11px; font-size: 0.7rem; color: #8b949e; font-family: inherit;
272
+ cursor: pointer; transition: background .15s, border-color .15s, color .15s; white-space: nowrap;
273
+ }
274
+ .model-pill:hover:not(:disabled) { border-color: #58a6ff; color: #58a6ff; }
275
+ .model-pill.active {
276
+ background: rgba(56,139,253,0.12); border-color: #388bfd; color: #58a6ff; font-weight: 500;
277
+ }
278
+ .model-pill:disabled { opacity: 0.45; cursor: not-allowed; }
279
+
280
  .chip {
281
  display: inline-flex; align-items: center; gap: 6px;
282
  background: #1c2128; border: 1px solid #30363d; border-radius: 20px;
 
309
  <div class="text-xs" style="color:#8b949e">IT Support Assistant</div>
310
  </div>
311
  </div>
312
+ <!-- Model switcher -->
313
+ <div id="model-switcher" class="flex items-center gap-1.5 ml-4">
314
+ <button class="model-pill active"
315
+ data-model-id="HuggingFaceTB/SmolLM2-360M-Instruct"
316
+ data-model-label="SmolLM2-360M">SmolLM2</button>
317
+ <button class="model-pill"
318
+ data-model-id="LiquidAI/LFM2.5-350M-ONNX"
319
+ data-model-label="LFM2.5-350M">LFM2.5</button>
320
+ </div>
321
+
322
  <div id="model-status-wrap" class="ml-auto flex items-center gap-3">
323
  <div id="model-progress-wrap" class="w-36 h-1 rounded-full hidden" style="background:#21262d">
324
  <div id="model-progress-bar" class="h-1 rounded-full" style="width:0%;background:#388bfd"></div>
 
1491
  sendMessage();
1492
  });
1493
  });
1494
+
1495
+ // ── Model switcher ────────────────────────────────────────────────────────── //
1496
+ document.querySelectorAll('.model-pill').forEach(pill => {
1497
+ pill.addEventListener('click', () => {
1498
+ if (pill.classList.contains('active')) return;
1499
+ if (typeof window._llmSwitchModel !== 'function') return;
1500
+
1501
+ document.querySelectorAll('.model-pill').forEach(p => {
1502
+ p.classList.remove('active');
1503
+ p.disabled = true;
1504
+ });
1505
+ pill.classList.add('active');
1506
+
1507
+ window._llmSwitchModel(
1508
+ pill.dataset.modelId,
1509
+ pill.dataset.modelLabel,
1510
+ () => document.querySelectorAll('.model-pill').forEach(p => { p.disabled = false; }),
1511
+ );
1512
+ });
1513
+ });
1514
  </script>
1515
 
1516
  <!-- ── WebGPU / LLM module ───────────────────────────────────────────────── -->
1517
  <script type="module">
1518
  import { pipeline, TextStreamer, env }
1519
+ from 'https://cdn.jsdelivr.net/npm/@huggingface/transformers@3/dist/transformers.min.js';
1520
 
1521
  env.allowLocalModels = false;
1522
  if (env.backends?.onnx?.wasm) {
 
1524
  env.backends.onnx.wasm.wasmPaths = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/';
1525
  }
1526
 
 
1527
  const statusEl = document.getElementById('model-status');
1528
  const progressWrap= document.getElementById('model-progress-wrap');
1529
  const progressBar = document.getElementById('model-progress-bar');
 
1540
  }
1541
  }
1542
 
1543
+ function bindGenerate() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1544
  window._llmGenerate = async function(systemPrompt, userPrompt, templateFallback, onToken, onDone, onFallback) {
1545
  if (!window._llm.generator) { onFallback(templateFallback); return; }
1546
  try {
 
1551
  let accumulated = '';
1552
  const streamer = new TextStreamer(window._llm.generator.tokenizer, {
1553
  skip_prompt: true,
1554
+ callback_function: (token) => { accumulated += token; onToken(accumulated); },
 
 
 
1555
  });
1556
  const result = await window._llm.generator(messages, {
1557
  max_new_tokens: 512,
 
1567
  }
1568
  };
1569
  }
1570
+
1571
+ async function loadModel(modelId, label, onComplete) {
1572
+ window._llmGenerate = null;
1573
+ window._llm.status = 'loading';
1574
+
1575
+ if (window._llm.generator) {
1576
+ try { await window._llm.generator.dispose(); } catch {}
1577
+ window._llm.generator = null;
1578
+ }
1579
+
1580
+ statusWrap.classList.remove('hidden');
1581
+ setStatusUI(`⏳ Loading ${label}…`, '#d29922', 0);
1582
+ progressWrap.classList.remove('hidden');
1583
+
1584
+ try {
1585
+ window._llm.generator = await pipeline('text-generation', modelId, {
1586
+ dtype: 'q4',
1587
+ device: 'webgpu',
1588
+ progress_callback: (p) => {
1589
+ if (p.status !== 'progress') return;
1590
+ setStatusUI(`⏳ ${label} ${Math.round(p.progress ?? 0)}%`, '#d29922', p.progress ?? 0);
1591
+ },
1592
+ });
1593
+ window._llm.status = 'ready';
1594
+ bindGenerate();
1595
+ setStatusUI(`βœ… ${label} ready`, '#3fb950', null);
1596
+ setTimeout(() => statusWrap.classList.add('hidden'), 3000);
1597
+ } catch (err) {
1598
+ console.error('[DeskFlow] Model load failed:', err);
1599
+ window._llm.status = 'error';
1600
+ setStatusUI(`⚠️ ${label} unavailable β€” using templates`, '#d29922', null);
1601
+ setTimeout(() => statusWrap.classList.add('hidden'), 5000);
1602
+ }
1603
+
1604
+ onComplete?.();
1605
+ }
1606
+
1607
+ window._llmSwitchModel = loadModel;
1608
+
1609
+ if (!navigator.gpu) {
1610
+ window._llm.status = 'unavailable';
1611
+ setStatusUI('⚠️ Templates only (no WebGPU)', '#d29922', null);
1612
+ setTimeout(() => statusWrap.classList.add('hidden'), 4000);
1613
+ } else {
1614
+ loadModel('HuggingFaceTB/SmolLM2-360M-Instruct', 'SmolLM2-360M', null);
1615
+ }
1616
  </script>
1617
 
1618
  </body>