@blank-utils/llm 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -57,10 +57,10 @@ function getAugmentedNamespace(n) {
57
57
  return n;
58
58
  var f = n.default;
59
59
  if (typeof f == "function") {
60
- var a = function a() {
60
+ var a = function a2() {
61
61
  var isInstance = false;
62
62
  try {
63
- isInstance = this instanceof a;
63
+ isInstance = this instanceof a2;
64
64
  } catch {}
65
65
  if (isInstance) {
66
66
  return Reflect.construct(f, arguments, this.constructor);
@@ -56591,7 +56591,7 @@ async function logCapabilities() {
56591
56591
  console.log(` Recommended device: ${caps.recommendedDevice}`);
56592
56592
  return caps;
56593
56593
  }
56594
- // src/backends/webllm.ts
56594
+ // src/models.ts
56595
56595
  var DEFAULT_WEBLLM_MODEL = "Phi-3.5-mini-instruct-q4f16_1-MLC";
56596
56596
  var WEBLLM_MODELS = {
56597
56597
  "llama-3.2-1b": "Llama-3.2-1B-Instruct-q4f16_1-MLC",
@@ -56623,6 +56623,21 @@ var WEBLLM_MODELS = {
56623
56623
  "hermes-3-llama-3.2-3b": "Hermes-3-Llama-3.2-3B-q4f16_1-MLC",
56624
56624
  "hermes-3-llama-3.1-8b": "Hermes-3-Llama-3.1-8B-q4f16_1-MLC"
56625
56625
  };
56626
+ var DEFAULT_TRANSFORMERS_MODEL = "onnx-community/Qwen2.5-0.5B-Instruct";
56627
+ var TRANSFORMERS_MODELS = {
56628
+ "qwen-2.5-0.5b": "onnx-community/Qwen2.5-0.5B-Instruct",
56629
+ "qwen-2.5-1.5b": "onnx-community/Qwen2.5-1.5B-Instruct",
56630
+ "qwen-2.5-coder-0.5b": "onnx-community/Qwen2.5-Coder-0.5B-Instruct",
56631
+ "qwen-2.5-coder-1.5b": "onnx-community/Qwen2.5-Coder-1.5B-Instruct",
56632
+ "qwen-3-0.6b": "onnx-community/Qwen3-0.6B-ONNX",
56633
+ "smollm2-135m": "HuggingFaceTB/SmolLM2-135M-Instruct",
56634
+ "smollm2-360m": "HuggingFaceTB/SmolLM2-360M-Instruct",
56635
+ "smollm2-1.7b": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
56636
+ "phi-3-mini": "Xenova/Phi-3-mini-4k-instruct",
56637
+ tinyllama: "Xenova/TinyLlama-1.1B-Chat-v1.0"
56638
+ };
56639
+
56640
+ // src/backends/webllm.ts
56626
56641
  function resolveModelId(model) {
56627
56642
  if (model in WEBLLM_MODELS) {
56628
56643
  return WEBLLM_MODELS[model];
@@ -56710,19 +56725,6 @@ function createWebLLMProvider() {
56710
56725
  return new WebLLMProvider;
56711
56726
  }
56712
56727
  // src/backends/transformers.ts
56713
- var DEFAULT_TRANSFORMERS_MODEL = "onnx-community/Qwen2.5-0.5B-Instruct";
56714
- var TRANSFORMERS_MODELS = {
56715
- "qwen-2.5-0.5b": "onnx-community/Qwen2.5-0.5B-Instruct",
56716
- "qwen-2.5-1.5b": "onnx-community/Qwen2.5-1.5B-Instruct",
56717
- "qwen-2.5-coder-0.5b": "onnx-community/Qwen2.5-Coder-0.5B-Instruct",
56718
- "qwen-2.5-coder-1.5b": "onnx-community/Qwen2.5-Coder-1.5B-Instruct",
56719
- "qwen-3-0.6b": "onnx-community/Qwen3-0.6B-ONNX",
56720
- "smollm2-135m": "HuggingFaceTB/SmolLM2-135M-Instruct",
56721
- "smollm2-360m": "HuggingFaceTB/SmolLM2-360M-Instruct",
56722
- "smollm2-1.7b": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
56723
- "phi-3-mini": "Xenova/Phi-3-mini-4k-instruct",
56724
- tinyllama: "Xenova/TinyLlama-1.1B-Chat-v1.0"
56725
- };
56726
56728
  function detectChatFormat(modelId) {
56727
56729
  const lower = modelId.toLowerCase();
56728
56730
  if (lower.includes("qwen") || lower.includes("smollm")) {
@@ -57127,13 +57129,727 @@ async function isWebGPUSupported() {
57127
57129
  import {
57128
57130
  createContext,
57129
57131
  useContext,
57130
- useState,
57131
- useCallback,
57132
- useEffect,
57132
+ useState as useState2,
57133
+ useCallback as useCallback2,
57134
+ useEffect as useEffect3,
57133
57135
  useMemo,
57134
- useRef
57136
+ useRef as useRef3
57135
57137
  } from "react";
57136
- import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
57138
+
57139
+ // src/react/components.tsx
57140
+ import { useRef as useRef2, useEffect as useEffect2, useState } from "react";
57141
+
57142
+ // src/react/chat-input.tsx
57143
+ import { useRef, useEffect, useCallback } from "react";
57144
+ import { jsxDEV } from "react/jsx-dev-runtime";
57145
+ function SendIcon() {
57146
+ return /* @__PURE__ */ jsxDEV("svg", {
57147
+ width: "16",
57148
+ height: "16",
57149
+ viewBox: "0 0 24 24",
57150
+ fill: "none",
57151
+ stroke: "currentColor",
57152
+ strokeWidth: "2",
57153
+ strokeLinecap: "round",
57154
+ strokeLinejoin: "round",
57155
+ children: [
57156
+ /* @__PURE__ */ jsxDEV("path", {
57157
+ d: "M22 2L11 13"
57158
+ }, undefined, false, undefined, this),
57159
+ /* @__PURE__ */ jsxDEV("path", {
57160
+ d: "M22 2L15 22L11 13L2 9L22 2Z"
57161
+ }, undefined, false, undefined, this)
57162
+ ]
57163
+ }, undefined, true, undefined, this);
57164
+ }
57165
+ function StopIcon() {
57166
+ return /* @__PURE__ */ jsxDEV("svg", {
57167
+ width: "16",
57168
+ height: "16",
57169
+ viewBox: "0 0 24 24",
57170
+ fill: "currentColor",
57171
+ children: /* @__PURE__ */ jsxDEV("rect", {
57172
+ x: "4",
57173
+ y: "4",
57174
+ width: "16",
57175
+ height: "16",
57176
+ rx: "2"
57177
+ }, undefined, false, undefined, this)
57178
+ }, undefined, false, undefined, this);
57179
+ }
57180
+ var STYLE_ID = "__llm-chat-input-styles";
57181
+ function injectStyles(theme) {
57182
+ if (typeof document === "undefined")
57183
+ return;
57184
+ const existing = document.getElementById(STYLE_ID);
57185
+ if (existing)
57186
+ existing.remove();
57187
+ const isDark = theme === "dark";
57188
+ const css = `
57189
+ .llm-ci {
57190
+ display: flex;
57191
+ flex-direction: column;
57192
+ border-radius: 16px;
57193
+ border: 1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.12)"};
57194
+ background: ${isDark ? "rgba(17,17,17,0.95)" : "rgba(255,255,255,0.98)"};
57195
+ padding: 8px;
57196
+ transition: border-color 0.2s, box-shadow 0.2s;
57197
+ position: relative;
57198
+ }
57199
+ .llm-ci:focus-within {
57200
+ border-color: ${isDark ? "rgba(56,189,248,0.4)" : "rgba(59,130,246,0.4)"};
57201
+ box-shadow: 0 0 0 2px ${isDark ? "rgba(56,189,248,0.1)" : "rgba(59,130,246,0.1)"};
57202
+ }
57203
+ .llm-ci textarea {
57204
+ width: 100%;
57205
+ min-height: 40px;
57206
+ max-height: 160px;
57207
+ resize: none;
57208
+ border: none;
57209
+ outline: none;
57210
+ background: transparent;
57211
+ color: ${isDark ? "#e5e5e5" : "#1a1a1a"};
57212
+ font-size: 14px;
57213
+ line-height: 1.5;
57214
+ padding: 8px 12px;
57215
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
57216
+ scrollbar-width: thin;
57217
+ }
57218
+ .llm-ci textarea::placeholder {
57219
+ color: ${isDark ? "rgba(255,255,255,0.3)" : "rgba(0,0,0,0.35)"};
57220
+ }
57221
+ .llm-ci-toolbar {
57222
+ display: flex;
57223
+ align-items: center;
57224
+ justify-content: space-between;
57225
+ padding: 4px 4px 0;
57226
+ }
57227
+ .llm-ci-actions {
57228
+ display: flex;
57229
+ align-items: center;
57230
+ gap: 2px;
57231
+ }
57232
+ .llm-ci-send {
57233
+ display: flex;
57234
+ align-items: center;
57235
+ justify-content: center;
57236
+ width: 32px;
57237
+ height: 32px;
57238
+ border-radius: 50%;
57239
+ border: none;
57240
+ cursor: pointer;
57241
+ transition: all 0.15s ease;
57242
+ flex-shrink: 0;
57243
+ }
57244
+ .llm-ci-send--active {
57245
+ background: ${isDark ? "#38bdf8" : "#3b82f6"};
57246
+ color: white;
57247
+ }
57248
+ .llm-ci-send--active:hover {
57249
+ background: ${isDark ? "#0ea5e9" : "#2563eb"};
57250
+ transform: scale(1.05);
57251
+ }
57252
+ .llm-ci-send--disabled {
57253
+ background: ${isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)"};
57254
+ color: ${isDark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"};
57255
+ cursor: not-allowed;
57256
+ }
57257
+ .llm-ci-send--stop {
57258
+ background: ${isDark ? "rgba(239,68,68,0.15)" : "rgba(239,68,68,0.1)"};
57259
+ color: ${isDark ? "#f87171" : "#ef4444"};
57260
+ }
57261
+ .llm-ci-send--stop:hover {
57262
+ background: ${isDark ? "rgba(239,68,68,0.25)" : "rgba(239,68,68,0.2)"};
57263
+ }
57264
+ `;
57265
+ const style = document.createElement("style");
57266
+ style.id = STYLE_ID;
57267
+ style.textContent = css;
57268
+ document.head.appendChild(style);
57269
+ }
57270
+ function ChatInput({
57271
+ value,
57272
+ onChange,
57273
+ onSend,
57274
+ onStop,
57275
+ disabled = false,
57276
+ isGenerating = false,
57277
+ placeholder = "Type a message...",
57278
+ maxRows = 5,
57279
+ actions,
57280
+ theme = "dark",
57281
+ className
57282
+ }) {
57283
+ const textareaRef = useRef(null);
57284
+ useEffect(() => {
57285
+ injectStyles(theme);
57286
+ }, [theme]);
57287
+ useEffect(() => {
57288
+ const textarea = textareaRef.current;
57289
+ if (!textarea)
57290
+ return;
57291
+ textarea.style.height = "auto";
57292
+ const lineHeight = 21;
57293
+ const maxHeight = lineHeight * maxRows + 16;
57294
+ const newHeight = Math.min(textarea.scrollHeight, maxHeight);
57295
+ textarea.style.height = `${newHeight}px`;
57296
+ }, [value, maxRows]);
57297
+ const handleKeyDown = useCallback((e) => {
57298
+ if (e.key === "Enter" && !e.shiftKey) {
57299
+ e.preventDefault();
57300
+ if (!disabled && value.trim()) {
57301
+ onSend();
57302
+ }
57303
+ }
57304
+ }, [disabled, value, onSend]);
57305
+ const hasValue = value.trim().length > 0;
57306
+ const canSend = hasValue && !disabled && !isGenerating;
57307
+ let sendClass = "llm-ci-send";
57308
+ if (isGenerating) {
57309
+ sendClass += " llm-ci-send--stop";
57310
+ } else if (canSend) {
57311
+ sendClass += " llm-ci-send--active";
57312
+ } else {
57313
+ sendClass += " llm-ci-send--disabled";
57314
+ }
57315
+ return /* @__PURE__ */ jsxDEV("div", {
57316
+ className: `llm-ci${className ? ` ${className}` : ""}`,
57317
+ children: [
57318
+ /* @__PURE__ */ jsxDEV("textarea", {
57319
+ ref: textareaRef,
57320
+ value,
57321
+ onChange: (e) => onChange(e.target.value),
57322
+ onKeyDown: handleKeyDown,
57323
+ placeholder,
57324
+ disabled: disabled && !isGenerating,
57325
+ rows: 1
57326
+ }, undefined, false, undefined, this),
57327
+ /* @__PURE__ */ jsxDEV("div", {
57328
+ className: "llm-ci-toolbar",
57329
+ children: [
57330
+ /* @__PURE__ */ jsxDEV("div", {
57331
+ className: "llm-ci-actions",
57332
+ children: actions
57333
+ }, undefined, false, undefined, this),
57334
+ /* @__PURE__ */ jsxDEV("button", {
57335
+ type: "button",
57336
+ className: sendClass,
57337
+ onClick: isGenerating ? onStop : onSend,
57338
+ disabled: !isGenerating && !canSend,
57339
+ "aria-label": isGenerating ? "Stop generation" : "Send message",
57340
+ children: isGenerating ? /* @__PURE__ */ jsxDEV(StopIcon, {}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV(SendIcon, {}, undefined, false, undefined, this)
57341
+ }, undefined, false, undefined, this)
57342
+ ]
57343
+ }, undefined, true, undefined, this)
57344
+ ]
57345
+ }, undefined, true, undefined, this);
57346
+ }
57347
+
57348
+ // src/react/components.tsx
57349
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
57350
+ function RetryIcon() {
57351
+ return /* @__PURE__ */ jsxDEV2("svg", {
57352
+ width: "14",
57353
+ height: "14",
57354
+ viewBox: "0 0 24 24",
57355
+ fill: "none",
57356
+ stroke: "currentColor",
57357
+ strokeWidth: "2",
57358
+ strokeLinecap: "round",
57359
+ strokeLinejoin: "round",
57360
+ children: [
57361
+ /* @__PURE__ */ jsxDEV2("polyline", {
57362
+ points: "23 4 23 10 17 10"
57363
+ }, undefined, false, undefined, this),
57364
+ /* @__PURE__ */ jsxDEV2("path", {
57365
+ d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10"
57366
+ }, undefined, false, undefined, this)
57367
+ ]
57368
+ }, undefined, true, undefined, this);
57369
+ }
57370
+ var STYLE_ID2 = "__llm-chat-styles";
57371
+ function injectChatStyles(theme) {
57372
+ if (typeof document === "undefined")
57373
+ return;
57374
+ const existing = document.getElementById(STYLE_ID2);
57375
+ if (existing)
57376
+ existing.remove();
57377
+ const d = theme === "dark";
57378
+ const css = `
57379
+ .llm-chat {
57380
+ display: flex;
57381
+ flex-direction: column;
57382
+ border-radius: 16px;
57383
+ border: 1px solid ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.08)"};
57384
+ background: ${d ? "#0a0a0a" : "#fafafa"};
57385
+ overflow: hidden;
57386
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
57387
+ color: ${d ? "#e5e5e5" : "#1a1a1a"};
57388
+ }
57389
+
57390
+ /* Header */
57391
+ .llm-chat-header {
57392
+ display: flex;
57393
+ align-items: center;
57394
+ justify-content: space-between;
57395
+ padding: 12px 16px;
57396
+ border-bottom: 1px solid ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)"};
57397
+ font-size: 12px;
57398
+ color: ${d ? "rgba(255,255,255,0.45)" : "rgba(0,0,0,0.45)"};
57399
+ }
57400
+ .llm-chat-header-model {
57401
+ font-weight: 600;
57402
+ color: ${d ? "rgba(255,255,255,0.7)" : "rgba(0,0,0,0.7)"};
57403
+ }
57404
+ .llm-chat-header-status {
57405
+ display: flex;
57406
+ align-items: center;
57407
+ gap: 6px;
57408
+ }
57409
+ .llm-chat-dot {
57410
+ width: 6px;
57411
+ height: 6px;
57412
+ border-radius: 50%;
57413
+ flex-shrink: 0;
57414
+ }
57415
+ .llm-chat-dot--loading {
57416
+ background: #f59e0b;
57417
+ animation: llm-pulse 1.5s ease-in-out infinite;
57418
+ }
57419
+ .llm-chat-dot--ready {
57420
+ background: #22c55e;
57421
+ }
57422
+ .llm-chat-dot--error {
57423
+ background: #ef4444;
57424
+ }
57425
+
57426
+ /* Progress */
57427
+ .llm-chat-progress {
57428
+ padding: 0 16px 8px;
57429
+ }
57430
+ .llm-chat-progress-bar {
57431
+ height: 3px;
57432
+ border-radius: 2px;
57433
+ background: ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)"};
57434
+ overflow: hidden;
57435
+ }
57436
+ .llm-chat-progress-fill {
57437
+ height: 100%;
57438
+ border-radius: 2px;
57439
+ background: linear-gradient(90deg, #38bdf8, #818cf8);
57440
+ transition: width 0.3s ease;
57441
+ }
57442
+ .llm-chat-progress-text {
57443
+ font-size: 11px;
57444
+ color: ${d ? "rgba(255,255,255,0.35)" : "rgba(0,0,0,0.35)"};
57445
+ margin-top: 4px;
57446
+ }
57447
+
57448
+ /* Messages */
57449
+ .llm-chat-messages {
57450
+ flex: 1;
57451
+ overflow-y: auto;
57452
+ padding: 16px;
57453
+ display: flex;
57454
+ flex-direction: column;
57455
+ gap: 12px;
57456
+ scrollbar-width: thin;
57457
+ scrollbar-color: ${d ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)"} transparent;
57458
+ }
57459
+
57460
+ /* Welcome */
57461
+ .llm-chat-welcome {
57462
+ display: flex;
57463
+ align-items: center;
57464
+ justify-content: center;
57465
+ flex: 1;
57466
+ text-align: center;
57467
+ color: ${d ? "rgba(255,255,255,0.25)" : "rgba(0,0,0,0.25)"};
57468
+ font-size: 14px;
57469
+ padding: 40px 20px;
57470
+ line-height: 1.5;
57471
+ }
57472
+
57473
+ /* Bubble */
57474
+ .llm-chat-bubble {
57475
+ display: flex;
57476
+ max-width: 80%;
57477
+ animation: llm-fadein 0.2s ease;
57478
+ }
57479
+ .llm-chat-bubble--user {
57480
+ align-self: flex-end;
57481
+ }
57482
+ .llm-chat-bubble--assistant {
57483
+ align-self: flex-start;
57484
+ }
57485
+ .llm-chat-bubble-content {
57486
+ padding: 10px 14px;
57487
+ border-radius: 16px;
57488
+ font-size: 14px;
57489
+ line-height: 1.55;
57490
+ white-space: pre-wrap;
57491
+ word-break: break-word;
57492
+ }
57493
+ .llm-chat-bubble--user .llm-chat-bubble-content {
57494
+ background: linear-gradient(135deg, #38bdf8, #818cf8);
57495
+ color: white;
57496
+ border-bottom-right-radius: 4px;
57497
+ }
57498
+ .llm-chat-bubble--assistant .llm-chat-bubble-content {
57499
+ background: ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.05)"};
57500
+ color: ${d ? "#d4d4d4" : "#333"};
57501
+ border-bottom-left-radius: 4px;
57502
+ }
57503
+
57504
+ /* Streaming */
57505
+ .llm-chat-streaming .llm-chat-bubble-content {
57506
+ border: 1px solid ${d ? "rgba(56,189,248,0.2)" : "rgba(59,130,246,0.2)"};
57507
+ }
57508
+ .llm-chat-cursor {
57509
+ display: inline-block;
57510
+ width: 2px;
57511
+ height: 14px;
57512
+ background: ${d ? "#38bdf8" : "#3b82f6"};
57513
+ margin-left: 2px;
57514
+ vertical-align: text-bottom;
57515
+ animation: llm-blink 0.8s step-end infinite;
57516
+ }
57517
+
57518
+ /* Pending */
57519
+ .llm-chat-pending {
57520
+ display: flex;
57521
+ justify-content: center;
57522
+ animation: llm-fadein 0.3s ease;
57523
+ }
57524
+ .llm-chat-pending-badge {
57525
+ font-size: 12px;
57526
+ color: #f59e0b;
57527
+ background: rgba(245,158,11,0.1);
57528
+ padding: 4px 12px;
57529
+ border-radius: 12px;
57530
+ }
57531
+
57532
+ /* Error */
57533
+ .llm-chat-error {
57534
+ margin: 0 16px;
57535
+ padding: 10px 14px;
57536
+ border-radius: 12px;
57537
+ background: ${d ? "rgba(239,68,68,0.08)" : "rgba(239,68,68,0.05)"};
57538
+ border: 1px solid ${d ? "rgba(239,68,68,0.2)" : "rgba(239,68,68,0.15)"};
57539
+ display: flex;
57540
+ align-items: center;
57541
+ justify-content: space-between;
57542
+ gap: 8px;
57543
+ }
57544
+ .llm-chat-error-text {
57545
+ font-size: 13px;
57546
+ color: ${d ? "#f87171" : "#dc2626"};
57547
+ flex: 1;
57548
+ }
57549
+ .llm-chat-error-retry {
57550
+ display: flex;
57551
+ align-items: center;
57552
+ gap: 4px;
57553
+ padding: 4px 10px;
57554
+ border-radius: 8px;
57555
+ border: 1px solid ${d ? "rgba(239,68,68,0.3)" : "rgba(239,68,68,0.2)"};
57556
+ background: transparent;
57557
+ color: ${d ? "#f87171" : "#dc2626"};
57558
+ font-size: 12px;
57559
+ cursor: pointer;
57560
+ transition: background 0.15s;
57561
+ flex-shrink: 0;
57562
+ }
57563
+ .llm-chat-error-retry:hover {
57564
+ background: ${d ? "rgba(239,68,68,0.12)" : "rgba(239,68,68,0.08)"};
57565
+ }
57566
+
57567
+ /* Loading overlay */
57568
+ .llm-chat-loading {
57569
+ display: flex;
57570
+ flex-direction: column;
57571
+ align-items: center;
57572
+ justify-content: center;
57573
+ gap: 12px;
57574
+ flex: 1;
57575
+ padding: 40px 20px;
57576
+ }
57577
+ .llm-chat-spinner {
57578
+ width: 28px;
57579
+ height: 28px;
57580
+ border: 2.5px solid ${d ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)"};
57581
+ border-top-color: #38bdf8;
57582
+ border-radius: 50%;
57583
+ animation: llm-spin 0.7s linear infinite;
57584
+ }
57585
+ .llm-chat-loading-text {
57586
+ font-size: 13px;
57587
+ color: ${d ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)"};
57588
+ }
57589
+
57590
+ /* Input area */
57591
+ .llm-chat-input-area {
57592
+ padding: 8px 12px 12px;
57593
+ border-top: 1px solid ${d ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.04)"};
57594
+ }
57595
+
57596
+ /* Animations */
57597
+ @keyframes llm-fadein {
57598
+ from { opacity: 0; transform: translateY(4px); }
57599
+ to { opacity: 1; transform: translateY(0); }
57600
+ }
57601
+ @keyframes llm-pulse {
57602
+ 0%, 100% { opacity: 1; }
57603
+ 50% { opacity: 0.4; }
57604
+ }
57605
+ @keyframes llm-blink {
57606
+ 0%, 100% { opacity: 1; }
57607
+ 50% { opacity: 0; }
57608
+ }
57609
+ @keyframes llm-spin {
57610
+ to { transform: rotate(360deg); }
57611
+ }
57612
+ `;
57613
+ const style = document.createElement("style");
57614
+ style.id = STYLE_ID2;
57615
+ style.textContent = css;
57616
+ document.head.appendChild(style);
57617
+ }
57618
+ function Chat2({
57619
+ systemPrompt = "You are a helpful assistant. Keep responses concise and clear.",
57620
+ placeholder = "Type a message...",
57621
+ theme = "dark",
57622
+ className,
57623
+ maxHeight = "600px",
57624
+ inputActions,
57625
+ onSend: onSendProp,
57626
+ onResponse,
57627
+ onError: onErrorProp,
57628
+ showHeader = true,
57629
+ showProgress = true,
57630
+ welcomeMessage = "Send a message to start chatting"
57631
+ }) {
57632
+ const { llm, isLoading, isReady, loadProgress, error, modelId, backend: backend2, reload } = useLLM();
57633
+ const [messages, setMessages] = useState([]);
57634
+ const [input, setInput] = useState("");
57635
+ const [isGenerating, setIsGenerating] = useState(false);
57636
+ const [streamingText, setStreamingText] = useState("");
57637
+ const [pendingMessage, setPendingMessage] = useState(null);
57638
+ const messagesEndRef = useRef2(null);
57639
+ const abortRef = useRef2(false);
57640
+ const isProcessingRef = useRef2(false);
57641
+ useEffect2(() => {
57642
+ injectChatStyles(theme);
57643
+ }, [theme]);
57644
+ useEffect2(() => {
57645
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
57646
+ }, [messages, streamingText]);
57647
+ const generate = async (userContent, currentMessages) => {
57648
+ if (!llm || !isReady || isProcessingRef.current)
57649
+ return;
57650
+ isProcessingRef.current = true;
57651
+ const userMsg = { role: "user", content: userContent };
57652
+ setMessages((prev) => [...prev, userMsg]);
57653
+ const apiMessages = [];
57654
+ if (systemPrompt) {
57655
+ apiMessages.push({ role: "system", content: systemPrompt });
57656
+ }
57657
+ apiMessages.push(...currentMessages, userMsg);
57658
+ setIsGenerating(true);
57659
+ setStreamingText("");
57660
+ abortRef.current = false;
57661
+ try {
57662
+ const response = await llm.stream(apiMessages, (_token, fullText) => {
57663
+ if (abortRef.current)
57664
+ return;
57665
+ setStreamingText(fullText);
57666
+ });
57667
+ if (!abortRef.current) {
57668
+ const assistantMsg = { role: "assistant", content: response };
57669
+ setMessages((prev) => [...prev, assistantMsg]);
57670
+ setStreamingText("");
57671
+ onResponse?.(response);
57672
+ }
57673
+ } catch (err) {
57674
+ const error2 = err instanceof Error ? err : new Error(String(err));
57675
+ onErrorProp?.(error2);
57676
+ } finally {
57677
+ setIsGenerating(false);
57678
+ isProcessingRef.current = false;
57679
+ }
57680
+ };
57681
+ useEffect2(() => {
57682
+ if (isReady && pendingMessage && !isProcessingRef.current) {
57683
+ const msg = pendingMessage;
57684
+ setPendingMessage(null);
57685
+ generate(msg, messages);
57686
+ }
57687
+ }, [isReady, pendingMessage]);
57688
+ const handleSend = () => {
57689
+ const text = input.trim();
57690
+ if (!text)
57691
+ return;
57692
+ setInput("");
57693
+ onSendProp?.(text);
57694
+ if (llm && isReady) {
57695
+ generate(text, messages);
57696
+ } else if (isLoading) {
57697
+ const userMsg = { role: "user", content: text };
57698
+ setMessages((prev) => [...prev, userMsg]);
57699
+ setPendingMessage(text);
57700
+ }
57701
+ };
57702
+ const handleStop = () => {
57703
+ abortRef.current = true;
57704
+ setIsGenerating(false);
57705
+ if (streamingText) {
57706
+ setMessages((prev) => [...prev, { role: "assistant", content: streamingText + "..." }]);
57707
+ setStreamingText("");
57708
+ }
57709
+ };
57710
+ const statusDotClass = error ? "llm-chat-dot llm-chat-dot--error" : isReady ? "llm-chat-dot llm-chat-dot--ready" : "llm-chat-dot llm-chat-dot--loading";
57711
+ const statusText = error ? "Error" : isReady ? "Ready" : isLoading ? "Loading..." : "Idle";
57712
+ return /* @__PURE__ */ jsxDEV2("div", {
57713
+ className: `llm-chat${className ? ` ${className}` : ""}`,
57714
+ style: { maxHeight, height: "100%" },
57715
+ children: [
57716
+ showHeader && /* @__PURE__ */ jsxDEV2("div", {
57717
+ className: "llm-chat-header",
57718
+ children: [
57719
+ /* @__PURE__ */ jsxDEV2("span", {
57720
+ className: "llm-chat-header-model",
57721
+ children: [
57722
+ modelId ? modelId.split("/").pop()?.substring(0, 30) : "No model",
57723
+ backend2 && /* @__PURE__ */ jsxDEV2("span", {
57724
+ style: { fontWeight: 400, marginLeft: 6, opacity: 0.6 },
57725
+ children: [
57726
+ "(",
57727
+ backend2,
57728
+ ")"
57729
+ ]
57730
+ }, undefined, true, undefined, this)
57731
+ ]
57732
+ }, undefined, true, undefined, this),
57733
+ /* @__PURE__ */ jsxDEV2("div", {
57734
+ className: "llm-chat-header-status",
57735
+ children: [
57736
+ /* @__PURE__ */ jsxDEV2("span", {
57737
+ className: statusDotClass
57738
+ }, undefined, false, undefined, this),
57739
+ /* @__PURE__ */ jsxDEV2("span", {
57740
+ children: statusText
57741
+ }, undefined, false, undefined, this)
57742
+ ]
57743
+ }, undefined, true, undefined, this)
57744
+ ]
57745
+ }, undefined, true, undefined, this),
57746
+ showProgress && isLoading && loadProgress && /* @__PURE__ */ jsxDEV2("div", {
57747
+ className: "llm-chat-progress",
57748
+ children: [
57749
+ /* @__PURE__ */ jsxDEV2("div", {
57750
+ className: "llm-chat-progress-bar",
57751
+ children: /* @__PURE__ */ jsxDEV2("div", {
57752
+ className: "llm-chat-progress-fill",
57753
+ style: { width: `${Math.min(100, loadProgress.progress)}%` }
57754
+ }, undefined, false, undefined, this)
57755
+ }, undefined, false, undefined, this),
57756
+ /* @__PURE__ */ jsxDEV2("div", {
57757
+ className: "llm-chat-progress-text",
57758
+ children: loadProgress.status
57759
+ }, undefined, false, undefined, this)
57760
+ ]
57761
+ }, undefined, true, undefined, this),
57762
+ error && /* @__PURE__ */ jsxDEV2("div", {
57763
+ className: "llm-chat-error",
57764
+ children: [
57765
+ /* @__PURE__ */ jsxDEV2("span", {
57766
+ className: "llm-chat-error-text",
57767
+ children: error.message
57768
+ }, undefined, false, undefined, this),
57769
+ /* @__PURE__ */ jsxDEV2("button", {
57770
+ className: "llm-chat-error-retry",
57771
+ onClick: reload,
57772
+ children: [
57773
+ /* @__PURE__ */ jsxDEV2(RetryIcon, {}, undefined, false, undefined, this),
57774
+ " Retry"
57775
+ ]
57776
+ }, undefined, true, undefined, this)
57777
+ ]
57778
+ }, undefined, true, undefined, this),
57779
+ /* @__PURE__ */ jsxDEV2("div", {
57780
+ className: "llm-chat-messages",
57781
+ children: [
57782
+ isLoading && messages.length === 0 && !error && /* @__PURE__ */ jsxDEV2("div", {
57783
+ className: "llm-chat-loading",
57784
+ children: [
57785
+ /* @__PURE__ */ jsxDEV2("div", {
57786
+ className: "llm-chat-spinner"
57787
+ }, undefined, false, undefined, this),
57788
+ /* @__PURE__ */ jsxDEV2("div", {
57789
+ className: "llm-chat-loading-text",
57790
+ children: loadProgress?.status || "Initializing model..."
57791
+ }, undefined, false, undefined, this)
57792
+ ]
57793
+ }, undefined, true, undefined, this),
57794
+ !isLoading && messages.length === 0 && !error && /* @__PURE__ */ jsxDEV2("div", {
57795
+ className: "llm-chat-welcome",
57796
+ children: welcomeMessage
57797
+ }, undefined, false, undefined, this),
57798
+ messages.map((msg, i) => {
57799
+ if (msg.role === "system")
57800
+ return null;
57801
+ return /* @__PURE__ */ jsxDEV2("div", {
57802
+ className: `llm-chat-bubble llm-chat-bubble--${msg.role}`,
57803
+ children: /* @__PURE__ */ jsxDEV2("div", {
57804
+ className: "llm-chat-bubble-content",
57805
+ children: msg.content
57806
+ }, undefined, false, undefined, this)
57807
+ }, i, false, undefined, this);
57808
+ }),
57809
+ streamingText && /* @__PURE__ */ jsxDEV2("div", {
57810
+ className: "llm-chat-bubble llm-chat-bubble--assistant llm-chat-streaming",
57811
+ children: /* @__PURE__ */ jsxDEV2("div", {
57812
+ className: "llm-chat-bubble-content",
57813
+ children: [
57814
+ streamingText,
57815
+ /* @__PURE__ */ jsxDEV2("span", {
57816
+ className: "llm-chat-cursor"
57817
+ }, undefined, false, undefined, this)
57818
+ ]
57819
+ }, undefined, true, undefined, this)
57820
+ }, undefined, false, undefined, this),
57821
+ pendingMessage !== null && /* @__PURE__ */ jsxDEV2("div", {
57822
+ className: "llm-chat-pending",
57823
+ children: /* @__PURE__ */ jsxDEV2("span", {
57824
+ className: "llm-chat-pending-badge",
57825
+ children: "⏳ Waiting for model to load..."
57826
+ }, undefined, false, undefined, this)
57827
+ }, undefined, false, undefined, this),
57828
+ /* @__PURE__ */ jsxDEV2("div", {
57829
+ ref: messagesEndRef
57830
+ }, undefined, false, undefined, this)
57831
+ ]
57832
+ }, undefined, true, undefined, this),
57833
+ /* @__PURE__ */ jsxDEV2("div", {
57834
+ className: "llm-chat-input-area",
57835
+ children: /* @__PURE__ */ jsxDEV2(ChatInput, {
57836
+ value: input,
57837
+ onChange: setInput,
57838
+ onSend: handleSend,
57839
+ onStop: handleStop,
57840
+ disabled: !isReady && !isLoading,
57841
+ isGenerating,
57842
+ placeholder: isLoading ? "Type now, send when ready..." : placeholder,
57843
+ theme,
57844
+ actions: inputActions
57845
+ }, undefined, false, undefined, this)
57846
+ }, undefined, false, undefined, this)
57847
+ ]
57848
+ }, undefined, true, undefined, this);
57849
+ }
57850
+
57851
+ // src/react/index.tsx
57852
+ import { jsxDEV as jsxDEV3, Fragment } from "react/jsx-dev-runtime";
57137
57853
  var LLMContext = createContext(null);
57138
57854
  function LLMProvider({
57139
57855
  children,
@@ -57143,14 +57859,14 @@ function LLMProvider({
57143
57859
  onError,
57144
57860
  ...config
57145
57861
  }) {
57146
- const [llm, setLLM] = useState(null);
57147
- const [isLoading, setIsLoading] = useState(false);
57148
- const [loadProgress, setLoadProgress] = useState(null);
57149
- const [error, setError] = useState(null);
57150
- const hasLoadedRef = useRef(false);
57151
- const configRef = useRef(config);
57862
+ const [llm, setLLM] = useState2(null);
57863
+ const [isLoading, setIsLoading] = useState2(false);
57864
+ const [loadProgress, setLoadProgress] = useState2(null);
57865
+ const [error, setError] = useState2(null);
57866
+ const hasLoadedRef = useRef3(false);
57867
+ const configRef = useRef3(config);
57152
57868
  configRef.current = config;
57153
- const load = useCallback(async () => {
57869
+ const load = useCallback2(async () => {
57154
57870
  if (isLoading)
57155
57871
  return;
57156
57872
  setIsLoading(true);
@@ -57175,7 +57891,7 @@ function LLMProvider({
57175
57891
  setIsLoading(false);
57176
57892
  }
57177
57893
  }, [isLoading, onLoad, onProgress, onError]);
57178
- const unload = useCallback(async () => {
57894
+ const unload = useCallback2(async () => {
57179
57895
  if (llm) {
57180
57896
  await llm.unload();
57181
57897
  setLLM(null);
@@ -57183,17 +57899,17 @@ function LLMProvider({
57183
57899
  hasLoadedRef.current = false;
57184
57900
  }
57185
57901
  }, [llm]);
57186
- const reload = useCallback(async () => {
57902
+ const reload = useCallback2(async () => {
57187
57903
  await unload();
57188
57904
  await load();
57189
57905
  }, [unload, load]);
57190
- useEffect(() => {
57906
+ useEffect3(() => {
57191
57907
  if (autoLoad && !hasLoadedRef.current && !llm && !isLoading) {
57192
57908
  hasLoadedRef.current = true;
57193
57909
  load();
57194
57910
  }
57195
57911
  }, [autoLoad, llm, isLoading, load]);
57196
- useEffect(() => {
57912
+ useEffect3(() => {
57197
57913
  return () => {
57198
57914
  if (llm) {
57199
57915
  llm.unload().catch(console.error);
@@ -57211,7 +57927,7 @@ function LLMProvider({
57211
57927
  reload,
57212
57928
  unload
57213
57929
  }), [llm, isLoading, loadProgress, error, reload, unload]);
57214
- return /* @__PURE__ */ jsxDEV(LLMContext.Provider, {
57930
+ return /* @__PURE__ */ jsxDEV3(LLMContext.Provider, {
57215
57931
  value,
57216
57932
  children
57217
57933
  }, undefined, false, undefined, this);
@@ -57235,14 +57951,14 @@ function useChat(options = {}) {
57235
57951
  onFinish,
57236
57952
  onError
57237
57953
  } = options;
57238
- const [messages, setMessages] = useState(initialMessages);
57239
- const [input, setInput] = useState("");
57240
- const [isGenerating, setIsGenerating] = useState(false);
57241
- const [streamingText, setStreamingText] = useState("");
57242
- const [pendingMessage, setPendingMessage] = useState(null);
57243
- const abortRef = useRef(false);
57244
- const isProcessingRef = useRef(false);
57245
- const generateResponse = useCallback(async (userContent, currentMessages) => {
57954
+ const [messages, setMessages] = useState2(initialMessages);
57955
+ const [input, setInput] = useState2("");
57956
+ const [isGenerating, setIsGenerating] = useState2(false);
57957
+ const [streamingText, setStreamingText] = useState2("");
57958
+ const [pendingMessage, setPendingMessage] = useState2(null);
57959
+ const abortRef = useRef3(false);
57960
+ const isProcessingRef = useRef3(false);
57961
+ const generateResponse = useCallback2(async (userContent, currentMessages) => {
57246
57962
  if (!llm || !isReady || isProcessingRef.current) {
57247
57963
  return "";
57248
57964
  }
@@ -57284,14 +58000,14 @@ function useChat(options = {}) {
57284
58000
  isProcessingRef.current = false;
57285
58001
  }
57286
58002
  }, [llm, isReady, systemPrompt, generateOptions, onStart, onToken, onFinish, onError]);
57287
- useEffect(() => {
58003
+ useEffect3(() => {
57288
58004
  if (isReady && pendingMessage && !isProcessingRef.current) {
57289
58005
  const messageToProcess = pendingMessage;
57290
58006
  setPendingMessage(null);
57291
58007
  generateResponse(messageToProcess, messages);
57292
58008
  }
57293
58009
  }, [isReady, pendingMessage, messages, generateResponse]);
57294
- const send = useCallback(async (content) => {
58010
+ const send = useCallback2(async (content) => {
57295
58011
  const messageContent = content ?? input;
57296
58012
  if (!messageContent.trim()) {
57297
58013
  return "";
@@ -57310,7 +58026,7 @@ function useChat(options = {}) {
57310
58026
  }
57311
58027
  return "";
57312
58028
  }, [input, llm, isReady, isLoading, queueWhileLoading, messages, generateResponse]);
57313
- const stop = useCallback(() => {
58029
+ const stop = useCallback2(() => {
57314
58030
  abortRef.current = true;
57315
58031
  setIsGenerating(false);
57316
58032
  setPendingMessage(null);
@@ -57322,16 +58038,16 @@ function useChat(options = {}) {
57322
58038
  setStreamingText("");
57323
58039
  }
57324
58040
  }, [streamingText]);
57325
- const clear = useCallback(() => {
58041
+ const clear = useCallback2(() => {
57326
58042
  setMessages(initialMessages);
57327
58043
  setStreamingText("");
57328
58044
  setInput("");
57329
58045
  setPendingMessage(null);
57330
58046
  }, [initialMessages]);
57331
- const append = useCallback((message) => {
58047
+ const append = useCallback2((message) => {
57332
58048
  setMessages((prev) => [...prev, message]);
57333
58049
  }, []);
57334
- const reload = useCallback(async () => {
58050
+ const reload = useCallback2(async () => {
57335
58051
  if (messages.length === 0)
57336
58052
  return "";
57337
58053
  const lastUserIndex = messages.findLastIndex((m) => m.role === "user");
@@ -57361,10 +58077,10 @@ function useChat(options = {}) {
57361
58077
  function useStream(options = {}) {
57362
58078
  const { llm, isReady } = useLLM();
57363
58079
  const { generateOptions, onToken, onFinish, onError } = options;
57364
- const [text, setText] = useState("");
57365
- const [isStreaming, setIsStreaming] = useState(false);
57366
- const abortRef = useRef(false);
57367
- const stream = useCallback(async (input) => {
58080
+ const [text, setText] = useState2("");
58081
+ const [isStreaming, setIsStreaming] = useState2(false);
58082
+ const abortRef = useRef3(false);
58083
+ const stream = useCallback2(async (input) => {
57368
58084
  if (!llm || !isReady) {
57369
58085
  return "";
57370
58086
  }
@@ -57388,11 +58104,11 @@ function useStream(options = {}) {
57388
58104
  setIsStreaming(false);
57389
58105
  }
57390
58106
  }, [llm, isReady, generateOptions, onToken, onFinish, onError]);
57391
- const stop = useCallback(() => {
58107
+ const stop = useCallback2(() => {
57392
58108
  abortRef.current = true;
57393
58109
  setIsStreaming(false);
57394
58110
  }, []);
57395
- const clear = useCallback(() => {
58111
+ const clear = useCallback2(() => {
57396
58112
  setText("");
57397
58113
  }, []);
57398
58114
  return {
@@ -57406,9 +58122,9 @@ function useStream(options = {}) {
57406
58122
  function useCompletion(options = {}) {
57407
58123
  const { llm, isReady } = useLLM();
57408
58124
  const { generateOptions } = options;
57409
- const [completion, setCompletion] = useState("");
57410
- const [isLoading, setIsLoading] = useState(false);
57411
- const complete = useCallback(async (prompt) => {
58125
+ const [completion, setCompletion] = useState2("");
58126
+ const [isLoading, setIsLoading] = useState2(false);
58127
+ const complete = useCallback2(async (prompt) => {
57412
58128
  if (!llm || !isReady) {
57413
58129
  return "";
57414
58130
  }
@@ -57424,7 +58140,7 @@ function useCompletion(options = {}) {
57424
58140
  setIsLoading(false);
57425
58141
  }
57426
58142
  }, [llm, isReady, generateOptions]);
57427
- const clear = useCallback(() => {
58143
+ const clear = useCallback2(() => {
57428
58144
  setCompletion("");
57429
58145
  }, []);
57430
58146
  return {
@@ -57439,22 +58155,22 @@ function LLMLoading({ children, className }) {
57439
58155
  if (!isLoading)
57440
58156
  return null;
57441
58157
  if (children) {
57442
- return /* @__PURE__ */ jsxDEV("div", {
58158
+ return /* @__PURE__ */ jsxDEV3("div", {
57443
58159
  className,
57444
58160
  children
57445
58161
  }, undefined, false, undefined, this);
57446
58162
  }
57447
- return /* @__PURE__ */ jsxDEV("div", {
58163
+ return /* @__PURE__ */ jsxDEV3("div", {
57448
58164
  className,
57449
58165
  children: [
57450
- /* @__PURE__ */ jsxDEV("p", {
58166
+ /* @__PURE__ */ jsxDEV3("p", {
57451
58167
  children: [
57452
58168
  "Loading model... ",
57453
58169
  loadProgress?.progress ?? 0,
57454
58170
  "%"
57455
58171
  ]
57456
58172
  }, undefined, true, undefined, this),
57457
- /* @__PURE__ */ jsxDEV("p", {
58173
+ /* @__PURE__ */ jsxDEV3("p", {
57458
58174
  children: loadProgress?.status
57459
58175
  }, undefined, false, undefined, this)
57460
58176
  ]
@@ -57463,11 +58179,11 @@ function LLMLoading({ children, className }) {
57463
58179
  function LLMReady({ children, fallback = null }) {
57464
58180
  const { isReady, isLoading } = useLLM();
57465
58181
  if (isLoading || !isReady) {
57466
- return /* @__PURE__ */ jsxDEV(Fragment, {
58182
+ return /* @__PURE__ */ jsxDEV3(Fragment, {
57467
58183
  children: fallback
57468
58184
  }, undefined, false, undefined, this);
57469
58185
  }
57470
- return /* @__PURE__ */ jsxDEV(Fragment, {
58186
+ return /* @__PURE__ */ jsxDEV3(Fragment, {
57471
58187
  children
57472
58188
  }, undefined, false, undefined, this);
57473
58189
  }
@@ -57497,5 +58213,7 @@ export {
57497
58213
  LLMProvider,
57498
58214
  LLMLoading,
57499
58215
  DEFAULT_WEBLLM_MODEL,
57500
- DEFAULT_TRANSFORMERS_MODEL
58216
+ DEFAULT_TRANSFORMERS_MODEL,
58217
+ ChatInput,
58218
+ Chat2 as Chat
57501
58219
  };