@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.
@@ -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);
@@ -56542,11 +56542,11 @@ ${fake_token_around_image}` + `${global_img_token}` + image_token.repeat(image_s
56542
56542
  import {
56543
56543
  createContext,
56544
56544
  useContext,
56545
- useState,
56546
- useCallback,
56547
- useEffect,
56545
+ useState as useState2,
56546
+ useCallback as useCallback2,
56547
+ useEffect as useEffect3,
56548
56548
  useMemo,
56549
- useRef
56549
+ useRef as useRef3
56550
56550
  } from "react";
56551
56551
 
56552
56552
  // src/detect.ts
@@ -56594,7 +56594,7 @@ async function detectCapabilities() {
56594
56594
  };
56595
56595
  }
56596
56596
 
56597
- // src/backends/webllm.ts
56597
+ // src/models.ts
56598
56598
  var DEFAULT_WEBLLM_MODEL = "Phi-3.5-mini-instruct-q4f16_1-MLC";
56599
56599
  var WEBLLM_MODELS = {
56600
56600
  "llama-3.2-1b": "Llama-3.2-1B-Instruct-q4f16_1-MLC",
@@ -56626,6 +56626,21 @@ var WEBLLM_MODELS = {
56626
56626
  "hermes-3-llama-3.2-3b": "Hermes-3-Llama-3.2-3B-q4f16_1-MLC",
56627
56627
  "hermes-3-llama-3.1-8b": "Hermes-3-Llama-3.1-8B-q4f16_1-MLC"
56628
56628
  };
56629
+ var DEFAULT_TRANSFORMERS_MODEL = "onnx-community/Qwen2.5-0.5B-Instruct";
56630
+ var TRANSFORMERS_MODELS = {
56631
+ "qwen-2.5-0.5b": "onnx-community/Qwen2.5-0.5B-Instruct",
56632
+ "qwen-2.5-1.5b": "onnx-community/Qwen2.5-1.5B-Instruct",
56633
+ "qwen-2.5-coder-0.5b": "onnx-community/Qwen2.5-Coder-0.5B-Instruct",
56634
+ "qwen-2.5-coder-1.5b": "onnx-community/Qwen2.5-Coder-1.5B-Instruct",
56635
+ "qwen-3-0.6b": "onnx-community/Qwen3-0.6B-ONNX",
56636
+ "smollm2-135m": "HuggingFaceTB/SmolLM2-135M-Instruct",
56637
+ "smollm2-360m": "HuggingFaceTB/SmolLM2-360M-Instruct",
56638
+ "smollm2-1.7b": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
56639
+ "phi-3-mini": "Xenova/Phi-3-mini-4k-instruct",
56640
+ tinyllama: "Xenova/TinyLlama-1.1B-Chat-v1.0"
56641
+ };
56642
+
56643
+ // src/backends/webllm.ts
56629
56644
  function resolveModelId(model) {
56630
56645
  if (model in WEBLLM_MODELS) {
56631
56646
  return WEBLLM_MODELS[model];
@@ -56711,19 +56726,6 @@ class WebLLMProvider {
56711
56726
  }
56712
56727
 
56713
56728
  // src/backends/transformers.ts
56714
- var DEFAULT_TRANSFORMERS_MODEL = "onnx-community/Qwen2.5-0.5B-Instruct";
56715
- var TRANSFORMERS_MODELS = {
56716
- "qwen-2.5-0.5b": "onnx-community/Qwen2.5-0.5B-Instruct",
56717
- "qwen-2.5-1.5b": "onnx-community/Qwen2.5-1.5B-Instruct",
56718
- "qwen-2.5-coder-0.5b": "onnx-community/Qwen2.5-Coder-0.5B-Instruct",
56719
- "qwen-2.5-coder-1.5b": "onnx-community/Qwen2.5-Coder-1.5B-Instruct",
56720
- "qwen-3-0.6b": "onnx-community/Qwen3-0.6B-ONNX",
56721
- "smollm2-135m": "HuggingFaceTB/SmolLM2-135M-Instruct",
56722
- "smollm2-360m": "HuggingFaceTB/SmolLM2-360M-Instruct",
56723
- "smollm2-1.7b": "HuggingFaceTB/SmolLM2-1.7B-Instruct",
56724
- "phi-3-mini": "Xenova/Phi-3-mini-4k-instruct",
56725
- tinyllama: "Xenova/TinyLlama-1.1B-Chat-v1.0"
56726
- };
56727
56729
  function detectChatFormat(modelId) {
56728
56730
  const lower = modelId.toLowerCase();
56729
56731
  if (lower.includes("qwen") || lower.includes("smollm")) {
@@ -57062,8 +57064,720 @@ async function createLLM(config = {}) {
57062
57064
  return llm;
57063
57065
  }
57064
57066
 
57067
+ // src/react/components.tsx
57068
+ import { useRef as useRef2, useEffect as useEffect2, useState } from "react";
57069
+
57070
+ // src/react/chat-input.tsx
57071
+ import { useRef, useEffect, useCallback } from "react";
57072
+ import { jsxDEV } from "react/jsx-dev-runtime";
57073
+ function SendIcon() {
57074
+ return /* @__PURE__ */ jsxDEV("svg", {
57075
+ width: "16",
57076
+ height: "16",
57077
+ viewBox: "0 0 24 24",
57078
+ fill: "none",
57079
+ stroke: "currentColor",
57080
+ strokeWidth: "2",
57081
+ strokeLinecap: "round",
57082
+ strokeLinejoin: "round",
57083
+ children: [
57084
+ /* @__PURE__ */ jsxDEV("path", {
57085
+ d: "M22 2L11 13"
57086
+ }, undefined, false, undefined, this),
57087
+ /* @__PURE__ */ jsxDEV("path", {
57088
+ d: "M22 2L15 22L11 13L2 9L22 2Z"
57089
+ }, undefined, false, undefined, this)
57090
+ ]
57091
+ }, undefined, true, undefined, this);
57092
+ }
57093
+ function StopIcon() {
57094
+ return /* @__PURE__ */ jsxDEV("svg", {
57095
+ width: "16",
57096
+ height: "16",
57097
+ viewBox: "0 0 24 24",
57098
+ fill: "currentColor",
57099
+ children: /* @__PURE__ */ jsxDEV("rect", {
57100
+ x: "4",
57101
+ y: "4",
57102
+ width: "16",
57103
+ height: "16",
57104
+ rx: "2"
57105
+ }, undefined, false, undefined, this)
57106
+ }, undefined, false, undefined, this);
57107
+ }
57108
+ var STYLE_ID = "__llm-chat-input-styles";
57109
+ function injectStyles(theme) {
57110
+ if (typeof document === "undefined")
57111
+ return;
57112
+ const existing = document.getElementById(STYLE_ID);
57113
+ if (existing)
57114
+ existing.remove();
57115
+ const isDark = theme === "dark";
57116
+ const css = `
57117
+ .llm-ci {
57118
+ display: flex;
57119
+ flex-direction: column;
57120
+ border-radius: 16px;
57121
+ border: 1px solid ${isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.12)"};
57122
+ background: ${isDark ? "rgba(17,17,17,0.95)" : "rgba(255,255,255,0.98)"};
57123
+ padding: 8px;
57124
+ transition: border-color 0.2s, box-shadow 0.2s;
57125
+ position: relative;
57126
+ }
57127
+ .llm-ci:focus-within {
57128
+ border-color: ${isDark ? "rgba(56,189,248,0.4)" : "rgba(59,130,246,0.4)"};
57129
+ box-shadow: 0 0 0 2px ${isDark ? "rgba(56,189,248,0.1)" : "rgba(59,130,246,0.1)"};
57130
+ }
57131
+ .llm-ci textarea {
57132
+ width: 100%;
57133
+ min-height: 40px;
57134
+ max-height: 160px;
57135
+ resize: none;
57136
+ border: none;
57137
+ outline: none;
57138
+ background: transparent;
57139
+ color: ${isDark ? "#e5e5e5" : "#1a1a1a"};
57140
+ font-size: 14px;
57141
+ line-height: 1.5;
57142
+ padding: 8px 12px;
57143
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
57144
+ scrollbar-width: thin;
57145
+ }
57146
+ .llm-ci textarea::placeholder {
57147
+ color: ${isDark ? "rgba(255,255,255,0.3)" : "rgba(0,0,0,0.35)"};
57148
+ }
57149
+ .llm-ci-toolbar {
57150
+ display: flex;
57151
+ align-items: center;
57152
+ justify-content: space-between;
57153
+ padding: 4px 4px 0;
57154
+ }
57155
+ .llm-ci-actions {
57156
+ display: flex;
57157
+ align-items: center;
57158
+ gap: 2px;
57159
+ }
57160
+ .llm-ci-send {
57161
+ display: flex;
57162
+ align-items: center;
57163
+ justify-content: center;
57164
+ width: 32px;
57165
+ height: 32px;
57166
+ border-radius: 50%;
57167
+ border: none;
57168
+ cursor: pointer;
57169
+ transition: all 0.15s ease;
57170
+ flex-shrink: 0;
57171
+ }
57172
+ .llm-ci-send--active {
57173
+ background: ${isDark ? "#38bdf8" : "#3b82f6"};
57174
+ color: white;
57175
+ }
57176
+ .llm-ci-send--active:hover {
57177
+ background: ${isDark ? "#0ea5e9" : "#2563eb"};
57178
+ transform: scale(1.05);
57179
+ }
57180
+ .llm-ci-send--disabled {
57181
+ background: ${isDark ? "rgba(255,255,255,0.05)" : "rgba(0,0,0,0.05)"};
57182
+ color: ${isDark ? "rgba(255,255,255,0.2)" : "rgba(0,0,0,0.2)"};
57183
+ cursor: not-allowed;
57184
+ }
57185
+ .llm-ci-send--stop {
57186
+ background: ${isDark ? "rgba(239,68,68,0.15)" : "rgba(239,68,68,0.1)"};
57187
+ color: ${isDark ? "#f87171" : "#ef4444"};
57188
+ }
57189
+ .llm-ci-send--stop:hover {
57190
+ background: ${isDark ? "rgba(239,68,68,0.25)" : "rgba(239,68,68,0.2)"};
57191
+ }
57192
+ `;
57193
+ const style = document.createElement("style");
57194
+ style.id = STYLE_ID;
57195
+ style.textContent = css;
57196
+ document.head.appendChild(style);
57197
+ }
57198
+ function ChatInput({
57199
+ value,
57200
+ onChange,
57201
+ onSend,
57202
+ onStop,
57203
+ disabled = false,
57204
+ isGenerating = false,
57205
+ placeholder = "Type a message...",
57206
+ maxRows = 5,
57207
+ actions,
57208
+ theme = "dark",
57209
+ className
57210
+ }) {
57211
+ const textareaRef = useRef(null);
57212
+ useEffect(() => {
57213
+ injectStyles(theme);
57214
+ }, [theme]);
57215
+ useEffect(() => {
57216
+ const textarea = textareaRef.current;
57217
+ if (!textarea)
57218
+ return;
57219
+ textarea.style.height = "auto";
57220
+ const lineHeight = 21;
57221
+ const maxHeight = lineHeight * maxRows + 16;
57222
+ const newHeight = Math.min(textarea.scrollHeight, maxHeight);
57223
+ textarea.style.height = `${newHeight}px`;
57224
+ }, [value, maxRows]);
57225
+ const handleKeyDown = useCallback((e) => {
57226
+ if (e.key === "Enter" && !e.shiftKey) {
57227
+ e.preventDefault();
57228
+ if (!disabled && value.trim()) {
57229
+ onSend();
57230
+ }
57231
+ }
57232
+ }, [disabled, value, onSend]);
57233
+ const hasValue = value.trim().length > 0;
57234
+ const canSend = hasValue && !disabled && !isGenerating;
57235
+ let sendClass = "llm-ci-send";
57236
+ if (isGenerating) {
57237
+ sendClass += " llm-ci-send--stop";
57238
+ } else if (canSend) {
57239
+ sendClass += " llm-ci-send--active";
57240
+ } else {
57241
+ sendClass += " llm-ci-send--disabled";
57242
+ }
57243
+ return /* @__PURE__ */ jsxDEV("div", {
57244
+ className: `llm-ci${className ? ` ${className}` : ""}`,
57245
+ children: [
57246
+ /* @__PURE__ */ jsxDEV("textarea", {
57247
+ ref: textareaRef,
57248
+ value,
57249
+ onChange: (e) => onChange(e.target.value),
57250
+ onKeyDown: handleKeyDown,
57251
+ placeholder,
57252
+ disabled: disabled && !isGenerating,
57253
+ rows: 1
57254
+ }, undefined, false, undefined, this),
57255
+ /* @__PURE__ */ jsxDEV("div", {
57256
+ className: "llm-ci-toolbar",
57257
+ children: [
57258
+ /* @__PURE__ */ jsxDEV("div", {
57259
+ className: "llm-ci-actions",
57260
+ children: actions
57261
+ }, undefined, false, undefined, this),
57262
+ /* @__PURE__ */ jsxDEV("button", {
57263
+ type: "button",
57264
+ className: sendClass,
57265
+ onClick: isGenerating ? onStop : onSend,
57266
+ disabled: !isGenerating && !canSend,
57267
+ "aria-label": isGenerating ? "Stop generation" : "Send message",
57268
+ children: isGenerating ? /* @__PURE__ */ jsxDEV(StopIcon, {}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV(SendIcon, {}, undefined, false, undefined, this)
57269
+ }, undefined, false, undefined, this)
57270
+ ]
57271
+ }, undefined, true, undefined, this)
57272
+ ]
57273
+ }, undefined, true, undefined, this);
57274
+ }
57275
+
57276
+ // src/react/components.tsx
57277
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
57278
+ function RetryIcon() {
57279
+ return /* @__PURE__ */ jsxDEV2("svg", {
57280
+ width: "14",
57281
+ height: "14",
57282
+ viewBox: "0 0 24 24",
57283
+ fill: "none",
57284
+ stroke: "currentColor",
57285
+ strokeWidth: "2",
57286
+ strokeLinecap: "round",
57287
+ strokeLinejoin: "round",
57288
+ children: [
57289
+ /* @__PURE__ */ jsxDEV2("polyline", {
57290
+ points: "23 4 23 10 17 10"
57291
+ }, undefined, false, undefined, this),
57292
+ /* @__PURE__ */ jsxDEV2("path", {
57293
+ d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10"
57294
+ }, undefined, false, undefined, this)
57295
+ ]
57296
+ }, undefined, true, undefined, this);
57297
+ }
57298
+ var STYLE_ID2 = "__llm-chat-styles";
57299
+ function injectChatStyles(theme) {
57300
+ if (typeof document === "undefined")
57301
+ return;
57302
+ const existing = document.getElementById(STYLE_ID2);
57303
+ if (existing)
57304
+ existing.remove();
57305
+ const d = theme === "dark";
57306
+ const css = `
57307
+ .llm-chat {
57308
+ display: flex;
57309
+ flex-direction: column;
57310
+ border-radius: 16px;
57311
+ border: 1px solid ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.08)"};
57312
+ background: ${d ? "#0a0a0a" : "#fafafa"};
57313
+ overflow: hidden;
57314
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
57315
+ color: ${d ? "#e5e5e5" : "#1a1a1a"};
57316
+ }
57317
+
57318
+ /* Header */
57319
+ .llm-chat-header {
57320
+ display: flex;
57321
+ align-items: center;
57322
+ justify-content: space-between;
57323
+ padding: 12px 16px;
57324
+ border-bottom: 1px solid ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)"};
57325
+ font-size: 12px;
57326
+ color: ${d ? "rgba(255,255,255,0.45)" : "rgba(0,0,0,0.45)"};
57327
+ }
57328
+ .llm-chat-header-model {
57329
+ font-weight: 600;
57330
+ color: ${d ? "rgba(255,255,255,0.7)" : "rgba(0,0,0,0.7)"};
57331
+ }
57332
+ .llm-chat-header-status {
57333
+ display: flex;
57334
+ align-items: center;
57335
+ gap: 6px;
57336
+ }
57337
+ .llm-chat-dot {
57338
+ width: 6px;
57339
+ height: 6px;
57340
+ border-radius: 50%;
57341
+ flex-shrink: 0;
57342
+ }
57343
+ .llm-chat-dot--loading {
57344
+ background: #f59e0b;
57345
+ animation: llm-pulse 1.5s ease-in-out infinite;
57346
+ }
57347
+ .llm-chat-dot--ready {
57348
+ background: #22c55e;
57349
+ }
57350
+ .llm-chat-dot--error {
57351
+ background: #ef4444;
57352
+ }
57353
+
57354
+ /* Progress */
57355
+ .llm-chat-progress {
57356
+ padding: 0 16px 8px;
57357
+ }
57358
+ .llm-chat-progress-bar {
57359
+ height: 3px;
57360
+ border-radius: 2px;
57361
+ background: ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)"};
57362
+ overflow: hidden;
57363
+ }
57364
+ .llm-chat-progress-fill {
57365
+ height: 100%;
57366
+ border-radius: 2px;
57367
+ background: linear-gradient(90deg, #38bdf8, #818cf8);
57368
+ transition: width 0.3s ease;
57369
+ }
57370
+ .llm-chat-progress-text {
57371
+ font-size: 11px;
57372
+ color: ${d ? "rgba(255,255,255,0.35)" : "rgba(0,0,0,0.35)"};
57373
+ margin-top: 4px;
57374
+ }
57375
+
57376
+ /* Messages */
57377
+ .llm-chat-messages {
57378
+ flex: 1;
57379
+ overflow-y: auto;
57380
+ padding: 16px;
57381
+ display: flex;
57382
+ flex-direction: column;
57383
+ gap: 12px;
57384
+ scrollbar-width: thin;
57385
+ scrollbar-color: ${d ? "rgba(255,255,255,0.1)" : "rgba(0,0,0,0.1)"} transparent;
57386
+ }
57387
+
57388
+ /* Welcome */
57389
+ .llm-chat-welcome {
57390
+ display: flex;
57391
+ align-items: center;
57392
+ justify-content: center;
57393
+ flex: 1;
57394
+ text-align: center;
57395
+ color: ${d ? "rgba(255,255,255,0.25)" : "rgba(0,0,0,0.25)"};
57396
+ font-size: 14px;
57397
+ padding: 40px 20px;
57398
+ line-height: 1.5;
57399
+ }
57400
+
57401
+ /* Bubble */
57402
+ .llm-chat-bubble {
57403
+ display: flex;
57404
+ max-width: 80%;
57405
+ animation: llm-fadein 0.2s ease;
57406
+ }
57407
+ .llm-chat-bubble--user {
57408
+ align-self: flex-end;
57409
+ }
57410
+ .llm-chat-bubble--assistant {
57411
+ align-self: flex-start;
57412
+ }
57413
+ .llm-chat-bubble-content {
57414
+ padding: 10px 14px;
57415
+ border-radius: 16px;
57416
+ font-size: 14px;
57417
+ line-height: 1.55;
57418
+ white-space: pre-wrap;
57419
+ word-break: break-word;
57420
+ }
57421
+ .llm-chat-bubble--user .llm-chat-bubble-content {
57422
+ background: linear-gradient(135deg, #38bdf8, #818cf8);
57423
+ color: white;
57424
+ border-bottom-right-radius: 4px;
57425
+ }
57426
+ .llm-chat-bubble--assistant .llm-chat-bubble-content {
57427
+ background: ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.05)"};
57428
+ color: ${d ? "#d4d4d4" : "#333"};
57429
+ border-bottom-left-radius: 4px;
57430
+ }
57431
+
57432
+ /* Streaming */
57433
+ .llm-chat-streaming .llm-chat-bubble-content {
57434
+ border: 1px solid ${d ? "rgba(56,189,248,0.2)" : "rgba(59,130,246,0.2)"};
57435
+ }
57436
+ .llm-chat-cursor {
57437
+ display: inline-block;
57438
+ width: 2px;
57439
+ height: 14px;
57440
+ background: ${d ? "#38bdf8" : "#3b82f6"};
57441
+ margin-left: 2px;
57442
+ vertical-align: text-bottom;
57443
+ animation: llm-blink 0.8s step-end infinite;
57444
+ }
57445
+
57446
+ /* Pending */
57447
+ .llm-chat-pending {
57448
+ display: flex;
57449
+ justify-content: center;
57450
+ animation: llm-fadein 0.3s ease;
57451
+ }
57452
+ .llm-chat-pending-badge {
57453
+ font-size: 12px;
57454
+ color: #f59e0b;
57455
+ background: rgba(245,158,11,0.1);
57456
+ padding: 4px 12px;
57457
+ border-radius: 12px;
57458
+ }
57459
+
57460
+ /* Error */
57461
+ .llm-chat-error {
57462
+ margin: 0 16px;
57463
+ padding: 10px 14px;
57464
+ border-radius: 12px;
57465
+ background: ${d ? "rgba(239,68,68,0.08)" : "rgba(239,68,68,0.05)"};
57466
+ border: 1px solid ${d ? "rgba(239,68,68,0.2)" : "rgba(239,68,68,0.15)"};
57467
+ display: flex;
57468
+ align-items: center;
57469
+ justify-content: space-between;
57470
+ gap: 8px;
57471
+ }
57472
+ .llm-chat-error-text {
57473
+ font-size: 13px;
57474
+ color: ${d ? "#f87171" : "#dc2626"};
57475
+ flex: 1;
57476
+ }
57477
+ .llm-chat-error-retry {
57478
+ display: flex;
57479
+ align-items: center;
57480
+ gap: 4px;
57481
+ padding: 4px 10px;
57482
+ border-radius: 8px;
57483
+ border: 1px solid ${d ? "rgba(239,68,68,0.3)" : "rgba(239,68,68,0.2)"};
57484
+ background: transparent;
57485
+ color: ${d ? "#f87171" : "#dc2626"};
57486
+ font-size: 12px;
57487
+ cursor: pointer;
57488
+ transition: background 0.15s;
57489
+ flex-shrink: 0;
57490
+ }
57491
+ .llm-chat-error-retry:hover {
57492
+ background: ${d ? "rgba(239,68,68,0.12)" : "rgba(239,68,68,0.08)"};
57493
+ }
57494
+
57495
+ /* Loading overlay */
57496
+ .llm-chat-loading {
57497
+ display: flex;
57498
+ flex-direction: column;
57499
+ align-items: center;
57500
+ justify-content: center;
57501
+ gap: 12px;
57502
+ flex: 1;
57503
+ padding: 40px 20px;
57504
+ }
57505
+ .llm-chat-spinner {
57506
+ width: 28px;
57507
+ height: 28px;
57508
+ border: 2.5px solid ${d ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.08)"};
57509
+ border-top-color: #38bdf8;
57510
+ border-radius: 50%;
57511
+ animation: llm-spin 0.7s linear infinite;
57512
+ }
57513
+ .llm-chat-loading-text {
57514
+ font-size: 13px;
57515
+ color: ${d ? "rgba(255,255,255,0.4)" : "rgba(0,0,0,0.4)"};
57516
+ }
57517
+
57518
+ /* Input area */
57519
+ .llm-chat-input-area {
57520
+ padding: 8px 12px 12px;
57521
+ border-top: 1px solid ${d ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.04)"};
57522
+ }
57523
+
57524
+ /* Animations */
57525
+ @keyframes llm-fadein {
57526
+ from { opacity: 0; transform: translateY(4px); }
57527
+ to { opacity: 1; transform: translateY(0); }
57528
+ }
57529
+ @keyframes llm-pulse {
57530
+ 0%, 100% { opacity: 1; }
57531
+ 50% { opacity: 0.4; }
57532
+ }
57533
+ @keyframes llm-blink {
57534
+ 0%, 100% { opacity: 1; }
57535
+ 50% { opacity: 0; }
57536
+ }
57537
+ @keyframes llm-spin {
57538
+ to { transform: rotate(360deg); }
57539
+ }
57540
+ `;
57541
+ const style = document.createElement("style");
57542
+ style.id = STYLE_ID2;
57543
+ style.textContent = css;
57544
+ document.head.appendChild(style);
57545
+ }
57546
+ function Chat2({
57547
+ systemPrompt = "You are a helpful assistant. Keep responses concise and clear.",
57548
+ placeholder = "Type a message...",
57549
+ theme = "dark",
57550
+ className,
57551
+ maxHeight = "600px",
57552
+ inputActions,
57553
+ onSend: onSendProp,
57554
+ onResponse,
57555
+ onError: onErrorProp,
57556
+ showHeader = true,
57557
+ showProgress = true,
57558
+ welcomeMessage = "Send a message to start chatting"
57559
+ }) {
57560
+ const { llm, isLoading, isReady, loadProgress, error, modelId, backend: backend2, reload } = useLLM();
57561
+ const [messages, setMessages] = useState([]);
57562
+ const [input, setInput] = useState("");
57563
+ const [isGenerating, setIsGenerating] = useState(false);
57564
+ const [streamingText, setStreamingText] = useState("");
57565
+ const [pendingMessage, setPendingMessage] = useState(null);
57566
+ const messagesEndRef = useRef2(null);
57567
+ const abortRef = useRef2(false);
57568
+ const isProcessingRef = useRef2(false);
57569
+ useEffect2(() => {
57570
+ injectChatStyles(theme);
57571
+ }, [theme]);
57572
+ useEffect2(() => {
57573
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
57574
+ }, [messages, streamingText]);
57575
+ const generate = async (userContent, currentMessages) => {
57576
+ if (!llm || !isReady || isProcessingRef.current)
57577
+ return;
57578
+ isProcessingRef.current = true;
57579
+ const userMsg = { role: "user", content: userContent };
57580
+ setMessages((prev) => [...prev, userMsg]);
57581
+ const apiMessages = [];
57582
+ if (systemPrompt) {
57583
+ apiMessages.push({ role: "system", content: systemPrompt });
57584
+ }
57585
+ apiMessages.push(...currentMessages, userMsg);
57586
+ setIsGenerating(true);
57587
+ setStreamingText("");
57588
+ abortRef.current = false;
57589
+ try {
57590
+ const response = await llm.stream(apiMessages, (_token, fullText) => {
57591
+ if (abortRef.current)
57592
+ return;
57593
+ setStreamingText(fullText);
57594
+ });
57595
+ if (!abortRef.current) {
57596
+ const assistantMsg = { role: "assistant", content: response };
57597
+ setMessages((prev) => [...prev, assistantMsg]);
57598
+ setStreamingText("");
57599
+ onResponse?.(response);
57600
+ }
57601
+ } catch (err) {
57602
+ const error2 = err instanceof Error ? err : new Error(String(err));
57603
+ onErrorProp?.(error2);
57604
+ } finally {
57605
+ setIsGenerating(false);
57606
+ isProcessingRef.current = false;
57607
+ }
57608
+ };
57609
+ useEffect2(() => {
57610
+ if (isReady && pendingMessage && !isProcessingRef.current) {
57611
+ const msg = pendingMessage;
57612
+ setPendingMessage(null);
57613
+ generate(msg, messages);
57614
+ }
57615
+ }, [isReady, pendingMessage]);
57616
+ const handleSend = () => {
57617
+ const text = input.trim();
57618
+ if (!text)
57619
+ return;
57620
+ setInput("");
57621
+ onSendProp?.(text);
57622
+ if (llm && isReady) {
57623
+ generate(text, messages);
57624
+ } else if (isLoading) {
57625
+ const userMsg = { role: "user", content: text };
57626
+ setMessages((prev) => [...prev, userMsg]);
57627
+ setPendingMessage(text);
57628
+ }
57629
+ };
57630
+ const handleStop = () => {
57631
+ abortRef.current = true;
57632
+ setIsGenerating(false);
57633
+ if (streamingText) {
57634
+ setMessages((prev) => [...prev, { role: "assistant", content: streamingText + "..." }]);
57635
+ setStreamingText("");
57636
+ }
57637
+ };
57638
+ 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";
57639
+ const statusText = error ? "Error" : isReady ? "Ready" : isLoading ? "Loading..." : "Idle";
57640
+ return /* @__PURE__ */ jsxDEV2("div", {
57641
+ className: `llm-chat${className ? ` ${className}` : ""}`,
57642
+ style: { maxHeight, height: "100%" },
57643
+ children: [
57644
+ showHeader && /* @__PURE__ */ jsxDEV2("div", {
57645
+ className: "llm-chat-header",
57646
+ children: [
57647
+ /* @__PURE__ */ jsxDEV2("span", {
57648
+ className: "llm-chat-header-model",
57649
+ children: [
57650
+ modelId ? modelId.split("/").pop()?.substring(0, 30) : "No model",
57651
+ backend2 && /* @__PURE__ */ jsxDEV2("span", {
57652
+ style: { fontWeight: 400, marginLeft: 6, opacity: 0.6 },
57653
+ children: [
57654
+ "(",
57655
+ backend2,
57656
+ ")"
57657
+ ]
57658
+ }, undefined, true, undefined, this)
57659
+ ]
57660
+ }, undefined, true, undefined, this),
57661
+ /* @__PURE__ */ jsxDEV2("div", {
57662
+ className: "llm-chat-header-status",
57663
+ children: [
57664
+ /* @__PURE__ */ jsxDEV2("span", {
57665
+ className: statusDotClass
57666
+ }, undefined, false, undefined, this),
57667
+ /* @__PURE__ */ jsxDEV2("span", {
57668
+ children: statusText
57669
+ }, undefined, false, undefined, this)
57670
+ ]
57671
+ }, undefined, true, undefined, this)
57672
+ ]
57673
+ }, undefined, true, undefined, this),
57674
+ showProgress && isLoading && loadProgress && /* @__PURE__ */ jsxDEV2("div", {
57675
+ className: "llm-chat-progress",
57676
+ children: [
57677
+ /* @__PURE__ */ jsxDEV2("div", {
57678
+ className: "llm-chat-progress-bar",
57679
+ children: /* @__PURE__ */ jsxDEV2("div", {
57680
+ className: "llm-chat-progress-fill",
57681
+ style: { width: `${Math.min(100, loadProgress.progress)}%` }
57682
+ }, undefined, false, undefined, this)
57683
+ }, undefined, false, undefined, this),
57684
+ /* @__PURE__ */ jsxDEV2("div", {
57685
+ className: "llm-chat-progress-text",
57686
+ children: loadProgress.status
57687
+ }, undefined, false, undefined, this)
57688
+ ]
57689
+ }, undefined, true, undefined, this),
57690
+ error && /* @__PURE__ */ jsxDEV2("div", {
57691
+ className: "llm-chat-error",
57692
+ children: [
57693
+ /* @__PURE__ */ jsxDEV2("span", {
57694
+ className: "llm-chat-error-text",
57695
+ children: error.message
57696
+ }, undefined, false, undefined, this),
57697
+ /* @__PURE__ */ jsxDEV2("button", {
57698
+ className: "llm-chat-error-retry",
57699
+ onClick: reload,
57700
+ children: [
57701
+ /* @__PURE__ */ jsxDEV2(RetryIcon, {}, undefined, false, undefined, this),
57702
+ " Retry"
57703
+ ]
57704
+ }, undefined, true, undefined, this)
57705
+ ]
57706
+ }, undefined, true, undefined, this),
57707
+ /* @__PURE__ */ jsxDEV2("div", {
57708
+ className: "llm-chat-messages",
57709
+ children: [
57710
+ isLoading && messages.length === 0 && !error && /* @__PURE__ */ jsxDEV2("div", {
57711
+ className: "llm-chat-loading",
57712
+ children: [
57713
+ /* @__PURE__ */ jsxDEV2("div", {
57714
+ className: "llm-chat-spinner"
57715
+ }, undefined, false, undefined, this),
57716
+ /* @__PURE__ */ jsxDEV2("div", {
57717
+ className: "llm-chat-loading-text",
57718
+ children: loadProgress?.status || "Initializing model..."
57719
+ }, undefined, false, undefined, this)
57720
+ ]
57721
+ }, undefined, true, undefined, this),
57722
+ !isLoading && messages.length === 0 && !error && /* @__PURE__ */ jsxDEV2("div", {
57723
+ className: "llm-chat-welcome",
57724
+ children: welcomeMessage
57725
+ }, undefined, false, undefined, this),
57726
+ messages.map((msg, i) => {
57727
+ if (msg.role === "system")
57728
+ return null;
57729
+ return /* @__PURE__ */ jsxDEV2("div", {
57730
+ className: `llm-chat-bubble llm-chat-bubble--${msg.role}`,
57731
+ children: /* @__PURE__ */ jsxDEV2("div", {
57732
+ className: "llm-chat-bubble-content",
57733
+ children: msg.content
57734
+ }, undefined, false, undefined, this)
57735
+ }, i, false, undefined, this);
57736
+ }),
57737
+ streamingText && /* @__PURE__ */ jsxDEV2("div", {
57738
+ className: "llm-chat-bubble llm-chat-bubble--assistant llm-chat-streaming",
57739
+ children: /* @__PURE__ */ jsxDEV2("div", {
57740
+ className: "llm-chat-bubble-content",
57741
+ children: [
57742
+ streamingText,
57743
+ /* @__PURE__ */ jsxDEV2("span", {
57744
+ className: "llm-chat-cursor"
57745
+ }, undefined, false, undefined, this)
57746
+ ]
57747
+ }, undefined, true, undefined, this)
57748
+ }, undefined, false, undefined, this),
57749
+ pendingMessage !== null && /* @__PURE__ */ jsxDEV2("div", {
57750
+ className: "llm-chat-pending",
57751
+ children: /* @__PURE__ */ jsxDEV2("span", {
57752
+ className: "llm-chat-pending-badge",
57753
+ children: "⏳ Waiting for model to load..."
57754
+ }, undefined, false, undefined, this)
57755
+ }, undefined, false, undefined, this),
57756
+ /* @__PURE__ */ jsxDEV2("div", {
57757
+ ref: messagesEndRef
57758
+ }, undefined, false, undefined, this)
57759
+ ]
57760
+ }, undefined, true, undefined, this),
57761
+ /* @__PURE__ */ jsxDEV2("div", {
57762
+ className: "llm-chat-input-area",
57763
+ children: /* @__PURE__ */ jsxDEV2(ChatInput, {
57764
+ value: input,
57765
+ onChange: setInput,
57766
+ onSend: handleSend,
57767
+ onStop: handleStop,
57768
+ disabled: !isReady && !isLoading,
57769
+ isGenerating,
57770
+ placeholder: isLoading ? "Type now, send when ready..." : placeholder,
57771
+ theme,
57772
+ actions: inputActions
57773
+ }, undefined, false, undefined, this)
57774
+ }, undefined, false, undefined, this)
57775
+ ]
57776
+ }, undefined, true, undefined, this);
57777
+ }
57778
+
57065
57779
  // src/react/index.tsx
57066
- import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
57780
+ import { jsxDEV as jsxDEV3, Fragment } from "react/jsx-dev-runtime";
57067
57781
  var LLMContext = createContext(null);
57068
57782
  function LLMProvider({
57069
57783
  children,
@@ -57073,14 +57787,14 @@ function LLMProvider({
57073
57787
  onError,
57074
57788
  ...config
57075
57789
  }) {
57076
- const [llm, setLLM] = useState(null);
57077
- const [isLoading, setIsLoading] = useState(false);
57078
- const [loadProgress, setLoadProgress] = useState(null);
57079
- const [error, setError] = useState(null);
57080
- const hasLoadedRef = useRef(false);
57081
- const configRef = useRef(config);
57790
+ const [llm, setLLM] = useState2(null);
57791
+ const [isLoading, setIsLoading] = useState2(false);
57792
+ const [loadProgress, setLoadProgress] = useState2(null);
57793
+ const [error, setError] = useState2(null);
57794
+ const hasLoadedRef = useRef3(false);
57795
+ const configRef = useRef3(config);
57082
57796
  configRef.current = config;
57083
- const load = useCallback(async () => {
57797
+ const load = useCallback2(async () => {
57084
57798
  if (isLoading)
57085
57799
  return;
57086
57800
  setIsLoading(true);
@@ -57105,7 +57819,7 @@ function LLMProvider({
57105
57819
  setIsLoading(false);
57106
57820
  }
57107
57821
  }, [isLoading, onLoad, onProgress, onError]);
57108
- const unload = useCallback(async () => {
57822
+ const unload = useCallback2(async () => {
57109
57823
  if (llm) {
57110
57824
  await llm.unload();
57111
57825
  setLLM(null);
@@ -57113,17 +57827,17 @@ function LLMProvider({
57113
57827
  hasLoadedRef.current = false;
57114
57828
  }
57115
57829
  }, [llm]);
57116
- const reload = useCallback(async () => {
57830
+ const reload = useCallback2(async () => {
57117
57831
  await unload();
57118
57832
  await load();
57119
57833
  }, [unload, load]);
57120
- useEffect(() => {
57834
+ useEffect3(() => {
57121
57835
  if (autoLoad && !hasLoadedRef.current && !llm && !isLoading) {
57122
57836
  hasLoadedRef.current = true;
57123
57837
  load();
57124
57838
  }
57125
57839
  }, [autoLoad, llm, isLoading, load]);
57126
- useEffect(() => {
57840
+ useEffect3(() => {
57127
57841
  return () => {
57128
57842
  if (llm) {
57129
57843
  llm.unload().catch(console.error);
@@ -57141,7 +57855,7 @@ function LLMProvider({
57141
57855
  reload,
57142
57856
  unload
57143
57857
  }), [llm, isLoading, loadProgress, error, reload, unload]);
57144
- return /* @__PURE__ */ jsxDEV(LLMContext.Provider, {
57858
+ return /* @__PURE__ */ jsxDEV3(LLMContext.Provider, {
57145
57859
  value,
57146
57860
  children
57147
57861
  }, undefined, false, undefined, this);
@@ -57165,14 +57879,14 @@ function useChat(options = {}) {
57165
57879
  onFinish,
57166
57880
  onError
57167
57881
  } = options;
57168
- const [messages, setMessages] = useState(initialMessages);
57169
- const [input, setInput] = useState("");
57170
- const [isGenerating, setIsGenerating] = useState(false);
57171
- const [streamingText, setStreamingText] = useState("");
57172
- const [pendingMessage, setPendingMessage] = useState(null);
57173
- const abortRef = useRef(false);
57174
- const isProcessingRef = useRef(false);
57175
- const generateResponse = useCallback(async (userContent, currentMessages) => {
57882
+ const [messages, setMessages] = useState2(initialMessages);
57883
+ const [input, setInput] = useState2("");
57884
+ const [isGenerating, setIsGenerating] = useState2(false);
57885
+ const [streamingText, setStreamingText] = useState2("");
57886
+ const [pendingMessage, setPendingMessage] = useState2(null);
57887
+ const abortRef = useRef3(false);
57888
+ const isProcessingRef = useRef3(false);
57889
+ const generateResponse = useCallback2(async (userContent, currentMessages) => {
57176
57890
  if (!llm || !isReady || isProcessingRef.current) {
57177
57891
  return "";
57178
57892
  }
@@ -57214,14 +57928,14 @@ function useChat(options = {}) {
57214
57928
  isProcessingRef.current = false;
57215
57929
  }
57216
57930
  }, [llm, isReady, systemPrompt, generateOptions, onStart, onToken, onFinish, onError]);
57217
- useEffect(() => {
57931
+ useEffect3(() => {
57218
57932
  if (isReady && pendingMessage && !isProcessingRef.current) {
57219
57933
  const messageToProcess = pendingMessage;
57220
57934
  setPendingMessage(null);
57221
57935
  generateResponse(messageToProcess, messages);
57222
57936
  }
57223
57937
  }, [isReady, pendingMessage, messages, generateResponse]);
57224
- const send = useCallback(async (content) => {
57938
+ const send = useCallback2(async (content) => {
57225
57939
  const messageContent = content ?? input;
57226
57940
  if (!messageContent.trim()) {
57227
57941
  return "";
@@ -57240,7 +57954,7 @@ function useChat(options = {}) {
57240
57954
  }
57241
57955
  return "";
57242
57956
  }, [input, llm, isReady, isLoading, queueWhileLoading, messages, generateResponse]);
57243
- const stop = useCallback(() => {
57957
+ const stop = useCallback2(() => {
57244
57958
  abortRef.current = true;
57245
57959
  setIsGenerating(false);
57246
57960
  setPendingMessage(null);
@@ -57252,16 +57966,16 @@ function useChat(options = {}) {
57252
57966
  setStreamingText("");
57253
57967
  }
57254
57968
  }, [streamingText]);
57255
- const clear = useCallback(() => {
57969
+ const clear = useCallback2(() => {
57256
57970
  setMessages(initialMessages);
57257
57971
  setStreamingText("");
57258
57972
  setInput("");
57259
57973
  setPendingMessage(null);
57260
57974
  }, [initialMessages]);
57261
- const append = useCallback((message) => {
57975
+ const append = useCallback2((message) => {
57262
57976
  setMessages((prev) => [...prev, message]);
57263
57977
  }, []);
57264
- const reload = useCallback(async () => {
57978
+ const reload = useCallback2(async () => {
57265
57979
  if (messages.length === 0)
57266
57980
  return "";
57267
57981
  const lastUserIndex = messages.findLastIndex((m) => m.role === "user");
@@ -57291,10 +58005,10 @@ function useChat(options = {}) {
57291
58005
  function useStream(options = {}) {
57292
58006
  const { llm, isReady } = useLLM();
57293
58007
  const { generateOptions, onToken, onFinish, onError } = options;
57294
- const [text, setText] = useState("");
57295
- const [isStreaming, setIsStreaming] = useState(false);
57296
- const abortRef = useRef(false);
57297
- const stream = useCallback(async (input) => {
58008
+ const [text, setText] = useState2("");
58009
+ const [isStreaming, setIsStreaming] = useState2(false);
58010
+ const abortRef = useRef3(false);
58011
+ const stream = useCallback2(async (input) => {
57298
58012
  if (!llm || !isReady) {
57299
58013
  return "";
57300
58014
  }
@@ -57318,11 +58032,11 @@ function useStream(options = {}) {
57318
58032
  setIsStreaming(false);
57319
58033
  }
57320
58034
  }, [llm, isReady, generateOptions, onToken, onFinish, onError]);
57321
- const stop = useCallback(() => {
58035
+ const stop = useCallback2(() => {
57322
58036
  abortRef.current = true;
57323
58037
  setIsStreaming(false);
57324
58038
  }, []);
57325
- const clear = useCallback(() => {
58039
+ const clear = useCallback2(() => {
57326
58040
  setText("");
57327
58041
  }, []);
57328
58042
  return {
@@ -57336,9 +58050,9 @@ function useStream(options = {}) {
57336
58050
  function useCompletion(options = {}) {
57337
58051
  const { llm, isReady } = useLLM();
57338
58052
  const { generateOptions } = options;
57339
- const [completion, setCompletion] = useState("");
57340
- const [isLoading, setIsLoading] = useState(false);
57341
- const complete = useCallback(async (prompt) => {
58053
+ const [completion, setCompletion] = useState2("");
58054
+ const [isLoading, setIsLoading] = useState2(false);
58055
+ const complete = useCallback2(async (prompt) => {
57342
58056
  if (!llm || !isReady) {
57343
58057
  return "";
57344
58058
  }
@@ -57354,7 +58068,7 @@ function useCompletion(options = {}) {
57354
58068
  setIsLoading(false);
57355
58069
  }
57356
58070
  }, [llm, isReady, generateOptions]);
57357
- const clear = useCallback(() => {
58071
+ const clear = useCallback2(() => {
57358
58072
  setCompletion("");
57359
58073
  }, []);
57360
58074
  return {
@@ -57369,22 +58083,22 @@ function LLMLoading({ children, className }) {
57369
58083
  if (!isLoading)
57370
58084
  return null;
57371
58085
  if (children) {
57372
- return /* @__PURE__ */ jsxDEV("div", {
58086
+ return /* @__PURE__ */ jsxDEV3("div", {
57373
58087
  className,
57374
58088
  children
57375
58089
  }, undefined, false, undefined, this);
57376
58090
  }
57377
- return /* @__PURE__ */ jsxDEV("div", {
58091
+ return /* @__PURE__ */ jsxDEV3("div", {
57378
58092
  className,
57379
58093
  children: [
57380
- /* @__PURE__ */ jsxDEV("p", {
58094
+ /* @__PURE__ */ jsxDEV3("p", {
57381
58095
  children: [
57382
58096
  "Loading model... ",
57383
58097
  loadProgress?.progress ?? 0,
57384
58098
  "%"
57385
58099
  ]
57386
58100
  }, undefined, true, undefined, this),
57387
- /* @__PURE__ */ jsxDEV("p", {
58101
+ /* @__PURE__ */ jsxDEV3("p", {
57388
58102
  children: loadProgress?.status
57389
58103
  }, undefined, false, undefined, this)
57390
58104
  ]
@@ -57393,11 +58107,11 @@ function LLMLoading({ children, className }) {
57393
58107
  function LLMReady({ children, fallback = null }) {
57394
58108
  const { isReady, isLoading } = useLLM();
57395
58109
  if (isLoading || !isReady) {
57396
- return /* @__PURE__ */ jsxDEV(Fragment, {
58110
+ return /* @__PURE__ */ jsxDEV3(Fragment, {
57397
58111
  children: fallback
57398
58112
  }, undefined, false, undefined, this);
57399
58113
  }
57400
- return /* @__PURE__ */ jsxDEV(Fragment, {
58114
+ return /* @__PURE__ */ jsxDEV3(Fragment, {
57401
58115
  children
57402
58116
  }, undefined, false, undefined, this);
57403
58117
  }
@@ -57408,5 +58122,7 @@ export {
57408
58122
  useChat,
57409
58123
  LLMReady,
57410
58124
  LLMProvider,
57411
- LLMLoading
58125
+ LLMLoading,
58126
+ ChatInput,
58127
+ Chat2 as Chat
57412
58128
  };