@blank-utils/llm 0.2.2 → 0.2.6
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/README.md +487 -89
- package/dist/index.js +1245 -65
- package/dist/react/index.js +1267 -66
- package/package.json +6 -3
- package/dist/backends/transformers.d.ts +0 -62
- package/dist/backends/transformers.d.ts.map +0 -1
- package/dist/backends/webllm.d.ts +0 -70
- package/dist/backends/webllm.d.ts.map +0 -1
- package/dist/core.d.ts +0 -71
- package/dist/core.d.ts.map +0 -1
- package/dist/detect.d.ts +0 -21
- package/dist/detect.d.ts.map +0 -1
- package/dist/helpers.d.ts +0 -35
- package/dist/helpers.d.ts.map +0 -1
- package/dist/index.d.ts +0 -27
- package/dist/index.d.ts.map +0 -1
- package/dist/react/index.d.ts +0 -309
- package/dist/react/index.d.ts.map +0 -1
- package/dist/types.d.ts +0 -178
- package/dist/types.d.ts.map +0 -1
package/dist/react/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
|
|
60
|
+
var a = function a2() {
|
|
61
61
|
var isInstance = false;
|
|
62
62
|
try {
|
|
63
|
-
isInstance = this instanceof
|
|
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,
|
|
56548
|
-
useMemo,
|
|
56549
|
-
useRef
|
|
56545
|
+
useState as useState3,
|
|
56546
|
+
useCallback as useCallback2,
|
|
56547
|
+
useEffect as useEffect3,
|
|
56548
|
+
useMemo as useMemo2,
|
|
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/
|
|
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,1204 @@ async function createLLM(config = {}) {
|
|
|
57062
57064
|
return llm;
|
|
57063
57065
|
}
|
|
57064
57066
|
|
|
57065
|
-
// src/react/
|
|
57067
|
+
// src/react/components.tsx
|
|
57068
|
+
import { useRef as useRef2, useEffect as useEffect2, useState as useState2, useMemo } from "react";
|
|
57069
|
+
|
|
57070
|
+
// src/react/chat-input.tsx
|
|
57071
|
+
import { useRef, useEffect, useCallback, useState } from "react";
|
|
57066
57072
|
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
|
|
57073
|
+
function SendIcon() {
|
|
57074
|
+
return /* @__PURE__ */ jsxDEV("svg", {
|
|
57075
|
+
width: "14",
|
|
57076
|
+
height: "14",
|
|
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("line", {
|
|
57085
|
+
x1: "5",
|
|
57086
|
+
y1: "12",
|
|
57087
|
+
x2: "19",
|
|
57088
|
+
y2: "12"
|
|
57089
|
+
}, undefined, false, undefined, this),
|
|
57090
|
+
/* @__PURE__ */ jsxDEV("polyline", {
|
|
57091
|
+
points: "12 5 19 12 12 19"
|
|
57092
|
+
}, undefined, false, undefined, this)
|
|
57093
|
+
]
|
|
57094
|
+
}, undefined, true, undefined, this);
|
|
57095
|
+
}
|
|
57096
|
+
function StopIcon() {
|
|
57097
|
+
return /* @__PURE__ */ jsxDEV("svg", {
|
|
57098
|
+
width: "14",
|
|
57099
|
+
height: "14",
|
|
57100
|
+
viewBox: "0 0 24 24",
|
|
57101
|
+
fill: "currentColor",
|
|
57102
|
+
children: /* @__PURE__ */ jsxDEV("rect", {
|
|
57103
|
+
x: "6",
|
|
57104
|
+
y: "6",
|
|
57105
|
+
width: "12",
|
|
57106
|
+
height: "12"
|
|
57107
|
+
}, undefined, false, undefined, this)
|
|
57108
|
+
}, undefined, false, undefined, this);
|
|
57109
|
+
}
|
|
57110
|
+
function ImageIcon() {
|
|
57111
|
+
return /* @__PURE__ */ jsxDEV("svg", {
|
|
57112
|
+
width: "14",
|
|
57113
|
+
height: "14",
|
|
57114
|
+
viewBox: "0 0 24 24",
|
|
57115
|
+
fill: "none",
|
|
57116
|
+
stroke: "currentColor",
|
|
57117
|
+
strokeWidth: "2",
|
|
57118
|
+
strokeLinecap: "round",
|
|
57119
|
+
strokeLinejoin: "round",
|
|
57120
|
+
children: [
|
|
57121
|
+
/* @__PURE__ */ jsxDEV("rect", {
|
|
57122
|
+
x: "3",
|
|
57123
|
+
y: "3",
|
|
57124
|
+
width: "18",
|
|
57125
|
+
height: "18",
|
|
57126
|
+
rx: "0",
|
|
57127
|
+
ry: "0"
|
|
57128
|
+
}, undefined, false, undefined, this),
|
|
57129
|
+
/* @__PURE__ */ jsxDEV("circle", {
|
|
57130
|
+
cx: "8.5",
|
|
57131
|
+
cy: "8.5",
|
|
57132
|
+
r: "1.5"
|
|
57133
|
+
}, undefined, false, undefined, this),
|
|
57134
|
+
/* @__PURE__ */ jsxDEV("polyline", {
|
|
57135
|
+
points: "21 15 16 10 5 21"
|
|
57136
|
+
}, undefined, false, undefined, this)
|
|
57137
|
+
]
|
|
57138
|
+
}, undefined, true, undefined, this);
|
|
57139
|
+
}
|
|
57140
|
+
function XIcon() {
|
|
57141
|
+
return /* @__PURE__ */ jsxDEV("svg", {
|
|
57142
|
+
width: "10",
|
|
57143
|
+
height: "10",
|
|
57144
|
+
viewBox: "0 0 24 24",
|
|
57145
|
+
fill: "none",
|
|
57146
|
+
stroke: "currentColor",
|
|
57147
|
+
strokeWidth: "3",
|
|
57148
|
+
strokeLinecap: "round",
|
|
57149
|
+
strokeLinejoin: "round",
|
|
57150
|
+
children: [
|
|
57151
|
+
/* @__PURE__ */ jsxDEV("line", {
|
|
57152
|
+
x1: "18",
|
|
57153
|
+
y1: "6",
|
|
57154
|
+
x2: "6",
|
|
57155
|
+
y2: "18"
|
|
57156
|
+
}, undefined, false, undefined, this),
|
|
57157
|
+
/* @__PURE__ */ jsxDEV("line", {
|
|
57158
|
+
x1: "6",
|
|
57159
|
+
y1: "6",
|
|
57160
|
+
x2: "18",
|
|
57161
|
+
y2: "18"
|
|
57162
|
+
}, undefined, false, undefined, this)
|
|
57163
|
+
]
|
|
57164
|
+
}, undefined, true, undefined, this);
|
|
57165
|
+
}
|
|
57166
|
+
var STYLE_ID = "__llm-chat-input-styles";
|
|
57167
|
+
function injectStyles(theme) {
|
|
57168
|
+
if (typeof document === "undefined")
|
|
57169
|
+
return;
|
|
57170
|
+
const existing = document.getElementById(STYLE_ID);
|
|
57171
|
+
if (existing)
|
|
57172
|
+
existing.remove();
|
|
57173
|
+
const d = theme === "dark";
|
|
57174
|
+
const border = d ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.12)";
|
|
57175
|
+
const borderFocus = d ? "rgba(255,255,255,0.35)" : "rgba(0,0,0,0.35)";
|
|
57176
|
+
const bg2 = d ? "#000000" : "#ffffff";
|
|
57177
|
+
const text = d ? "#ffffff" : "#000000";
|
|
57178
|
+
const textMuted = d ? "rgba(255,255,255,0.3)" : "rgba(0,0,0,0.3)";
|
|
57179
|
+
const textSecondary = d ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)";
|
|
57180
|
+
const monoFont = `ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, monospace`;
|
|
57181
|
+
const sansFont = `-apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", Roboto, Helvetica, Arial, sans-serif`;
|
|
57182
|
+
const css = `
|
|
57183
|
+
.llm-ci {
|
|
57184
|
+
display: flex;
|
|
57185
|
+
flex-direction: column;
|
|
57186
|
+
border: 1px solid ${border};
|
|
57187
|
+
background: ${bg2};
|
|
57188
|
+
padding: 12px;
|
|
57189
|
+
transition: border-color 0.15s;
|
|
57190
|
+
position: relative;
|
|
57191
|
+
}
|
|
57192
|
+
.llm-ci:focus-within {
|
|
57193
|
+
border-color: ${borderFocus};
|
|
57194
|
+
}
|
|
57195
|
+
|
|
57196
|
+
/* Attached Images */
|
|
57197
|
+
.llm-ci-images {
|
|
57198
|
+
display: flex;
|
|
57199
|
+
flex-wrap: wrap;
|
|
57200
|
+
gap: 6px;
|
|
57201
|
+
margin-bottom: 8px;
|
|
57202
|
+
}
|
|
57203
|
+
.llm-ci-image-preview {
|
|
57204
|
+
position: relative;
|
|
57205
|
+
width: 52px;
|
|
57206
|
+
height: 52px;
|
|
57207
|
+
overflow: hidden;
|
|
57208
|
+
border: 1px solid ${border};
|
|
57209
|
+
}
|
|
57210
|
+
.llm-ci-image-preview img {
|
|
57211
|
+
width: 100%;
|
|
57212
|
+
height: 100%;
|
|
57213
|
+
object-fit: cover;
|
|
57214
|
+
}
|
|
57215
|
+
.llm-ci-image-remove {
|
|
57216
|
+
position: absolute;
|
|
57217
|
+
top: 2px;
|
|
57218
|
+
right: 2px;
|
|
57219
|
+
width: 16px;
|
|
57220
|
+
height: 16px;
|
|
57221
|
+
background: ${d ? "rgba(0,0,0,0.7)" : "rgba(255,255,255,0.8)"};
|
|
57222
|
+
color: ${text};
|
|
57223
|
+
border: none;
|
|
57224
|
+
display: flex;
|
|
57225
|
+
align-items: center;
|
|
57226
|
+
justify-content: center;
|
|
57227
|
+
cursor: pointer;
|
|
57228
|
+
opacity: 0;
|
|
57229
|
+
transition: opacity 0.1s;
|
|
57230
|
+
}
|
|
57231
|
+
.llm-ci-image-preview:hover .llm-ci-image-remove {
|
|
57232
|
+
opacity: 1;
|
|
57233
|
+
}
|
|
57234
|
+
|
|
57235
|
+
/* Textarea */
|
|
57236
|
+
.llm-ci textarea {
|
|
57237
|
+
width: 100%;
|
|
57238
|
+
min-height: 24px;
|
|
57239
|
+
max-height: 200px;
|
|
57240
|
+
resize: none;
|
|
57241
|
+
border: none;
|
|
57242
|
+
outline: none;
|
|
57243
|
+
background: transparent;
|
|
57244
|
+
color: ${text};
|
|
57245
|
+
font-size: 14px;
|
|
57246
|
+
line-height: 1.5;
|
|
57247
|
+
padding: 0;
|
|
57248
|
+
margin: 0;
|
|
57249
|
+
font-family: ${sansFont};
|
|
57250
|
+
scrollbar-width: thin;
|
|
57251
|
+
}
|
|
57252
|
+
.llm-ci textarea::placeholder {
|
|
57253
|
+
color: ${textMuted};
|
|
57254
|
+
}
|
|
57255
|
+
|
|
57256
|
+
/* Toolbar */
|
|
57257
|
+
.llm-ci-toolbar {
|
|
57258
|
+
display: flex;
|
|
57259
|
+
align-items: center;
|
|
57260
|
+
justify-content: space-between;
|
|
57261
|
+
margin-top: 8px;
|
|
57262
|
+
min-height: 28px;
|
|
57263
|
+
}
|
|
57264
|
+
.llm-ci-left-actions {
|
|
57265
|
+
display: flex;
|
|
57266
|
+
align-items: center;
|
|
57267
|
+
gap: 2px;
|
|
57268
|
+
}
|
|
57269
|
+
.llm-ci-right-actions {
|
|
57270
|
+
display: flex;
|
|
57271
|
+
align-items: center;
|
|
57272
|
+
gap: 8px;
|
|
57273
|
+
}
|
|
57274
|
+
|
|
57275
|
+
/* Icon Buttons */
|
|
57276
|
+
.llm-ci-btn-icon {
|
|
57277
|
+
display: flex;
|
|
57278
|
+
align-items: center;
|
|
57279
|
+
justify-content: center;
|
|
57280
|
+
width: 28px;
|
|
57281
|
+
height: 28px;
|
|
57282
|
+
border: none;
|
|
57283
|
+
background: transparent;
|
|
57284
|
+
color: ${textSecondary};
|
|
57285
|
+
cursor: pointer;
|
|
57286
|
+
transition: color 0.1s;
|
|
57287
|
+
}
|
|
57288
|
+
.llm-ci-btn-icon:hover {
|
|
57289
|
+
color: ${text};
|
|
57290
|
+
}
|
|
57291
|
+
|
|
57292
|
+
/* Send / Stop — flat, monospace, uppercase */
|
|
57293
|
+
.llm-ci-send {
|
|
57294
|
+
display: flex;
|
|
57295
|
+
align-items: center;
|
|
57296
|
+
justify-content: center;
|
|
57297
|
+
height: 28px;
|
|
57298
|
+
padding: 0 12px;
|
|
57299
|
+
border: 1px solid ${border};
|
|
57300
|
+
font-size: 10px;
|
|
57301
|
+
font-weight: 400;
|
|
57302
|
+
font-family: ${monoFont};
|
|
57303
|
+
text-transform: uppercase;
|
|
57304
|
+
letter-spacing: 0.08em;
|
|
57305
|
+
cursor: pointer;
|
|
57306
|
+
transition: all 0.1s;
|
|
57307
|
+
gap: 6px;
|
|
57308
|
+
background: transparent;
|
|
57309
|
+
color: ${textSecondary};
|
|
57310
|
+
}
|
|
57311
|
+
.llm-ci-send--active {
|
|
57312
|
+
background: ${text};
|
|
57313
|
+
color: ${bg2};
|
|
57314
|
+
border-color: ${text};
|
|
57315
|
+
}
|
|
57316
|
+
.llm-ci-send--active:hover {
|
|
57317
|
+
opacity: 0.8;
|
|
57318
|
+
}
|
|
57319
|
+
.llm-ci-send--disabled {
|
|
57320
|
+
color: ${textMuted};
|
|
57321
|
+
border-color: ${d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)"};
|
|
57322
|
+
cursor: not-allowed;
|
|
57323
|
+
}
|
|
57324
|
+
.llm-ci-send--stop {
|
|
57325
|
+
background: transparent;
|
|
57326
|
+
border-color: ${border};
|
|
57327
|
+
color: ${textSecondary};
|
|
57328
|
+
}
|
|
57329
|
+
.llm-ci-send--stop:hover {
|
|
57330
|
+
border-color: ${borderFocus};
|
|
57331
|
+
color: ${text};
|
|
57332
|
+
}
|
|
57333
|
+
|
|
57334
|
+
/* Model Selector Slot */
|
|
57335
|
+
.llm-ci-model-selector {
|
|
57336
|
+
margin-right: auto;
|
|
57337
|
+
}
|
|
57338
|
+
|
|
57339
|
+
/* Hidden file input */
|
|
57340
|
+
.llm-ci-file-input {
|
|
57341
|
+
display: none;
|
|
57342
|
+
}
|
|
57343
|
+
|
|
57344
|
+
/* Drag Overlay */
|
|
57345
|
+
.llm-ci-drag-overlay {
|
|
57346
|
+
position: absolute;
|
|
57347
|
+
inset: 0;
|
|
57348
|
+
background: ${d ? "rgba(0,0,0,0.9)" : "rgba(255,255,255,0.9)"};
|
|
57349
|
+
display: flex;
|
|
57350
|
+
align-items: center;
|
|
57351
|
+
justify-content: center;
|
|
57352
|
+
z-index: 10;
|
|
57353
|
+
border: 1px dashed ${textSecondary};
|
|
57354
|
+
color: ${textSecondary};
|
|
57355
|
+
font-size: 11px;
|
|
57356
|
+
font-family: ${monoFont};
|
|
57357
|
+
text-transform: uppercase;
|
|
57358
|
+
letter-spacing: 0.08em;
|
|
57359
|
+
}
|
|
57360
|
+
`;
|
|
57361
|
+
const style = document.createElement("style");
|
|
57362
|
+
style.id = STYLE_ID;
|
|
57363
|
+
style.textContent = css;
|
|
57364
|
+
document.head.appendChild(style);
|
|
57365
|
+
}
|
|
57366
|
+
function ChatInput({
|
|
57367
|
+
value,
|
|
57368
|
+
onChange,
|
|
57369
|
+
onSend,
|
|
57370
|
+
onStop,
|
|
57371
|
+
disabled = false,
|
|
57372
|
+
isGenerating = false,
|
|
57373
|
+
placeholder = "Type a message...",
|
|
57374
|
+
maxRows = 8,
|
|
57375
|
+
actions,
|
|
57376
|
+
theme = "dark",
|
|
57377
|
+
className,
|
|
57378
|
+
images = [],
|
|
57379
|
+
onImageAdd,
|
|
57380
|
+
onImageRemove,
|
|
57381
|
+
modelSelector
|
|
57382
|
+
}) {
|
|
57383
|
+
const textareaRef = useRef(null);
|
|
57384
|
+
const fileInputRef = useRef(null);
|
|
57385
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
57386
|
+
useEffect(() => {
|
|
57387
|
+
injectStyles(theme);
|
|
57388
|
+
}, [theme]);
|
|
57389
|
+
useEffect(() => {
|
|
57390
|
+
const textarea = textareaRef.current;
|
|
57391
|
+
if (!textarea)
|
|
57392
|
+
return;
|
|
57393
|
+
textarea.style.height = "auto";
|
|
57394
|
+
const lineHeight = 21;
|
|
57395
|
+
const maxHeight = lineHeight * maxRows + 24;
|
|
57396
|
+
const newHeight = Math.min(textarea.scrollHeight, maxHeight);
|
|
57397
|
+
textarea.style.height = `${newHeight}px`;
|
|
57398
|
+
}, [value, maxRows]);
|
|
57399
|
+
const handleKeyDown = useCallback((e) => {
|
|
57400
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
57401
|
+
e.preventDefault();
|
|
57402
|
+
if (!disabled && (value.trim() || images.length > 0)) {
|
|
57403
|
+
onSend();
|
|
57404
|
+
}
|
|
57405
|
+
}
|
|
57406
|
+
}, [disabled, value, images.length, onSend]);
|
|
57407
|
+
const processFile = useCallback((file) => {
|
|
57408
|
+
if (!file.type.startsWith("image/"))
|
|
57409
|
+
return;
|
|
57410
|
+
const reader = new FileReader;
|
|
57411
|
+
reader.onload = (e) => {
|
|
57412
|
+
if (e.target?.result && typeof e.target.result === "string") {
|
|
57413
|
+
const id2 = Math.random().toString(36).substring(7);
|
|
57414
|
+
onImageAdd?.({
|
|
57415
|
+
id: id2,
|
|
57416
|
+
dataUrl: e.target.result,
|
|
57417
|
+
file,
|
|
57418
|
+
name: file.name
|
|
57419
|
+
});
|
|
57420
|
+
}
|
|
57421
|
+
};
|
|
57422
|
+
reader.readAsDataURL(file);
|
|
57423
|
+
}, [onImageAdd]);
|
|
57424
|
+
const handlePaste = useCallback((e) => {
|
|
57425
|
+
const items = e.clipboardData.items;
|
|
57426
|
+
for (let i = 0;i < items.length; i++) {
|
|
57427
|
+
const item = items[i];
|
|
57428
|
+
if (item && item.type.indexOf("image") !== -1) {
|
|
57429
|
+
const file = item.getAsFile();
|
|
57430
|
+
if (file)
|
|
57431
|
+
processFile(file);
|
|
57432
|
+
}
|
|
57433
|
+
}
|
|
57434
|
+
}, [processFile]);
|
|
57435
|
+
const handleDrop = useCallback((e) => {
|
|
57436
|
+
e.preventDefault();
|
|
57437
|
+
setIsDragging(false);
|
|
57438
|
+
const files = e.dataTransfer.files;
|
|
57439
|
+
for (let i = 0;i < files.length; i++) {
|
|
57440
|
+
const file = files.item(i);
|
|
57441
|
+
if (file)
|
|
57442
|
+
processFile(file);
|
|
57443
|
+
}
|
|
57444
|
+
}, [processFile]);
|
|
57445
|
+
const handleFileSelect = useCallback((e) => {
|
|
57446
|
+
const files = e.target.files;
|
|
57447
|
+
if (!files)
|
|
57448
|
+
return;
|
|
57449
|
+
for (let i = 0;i < files.length; i++) {
|
|
57450
|
+
const file = files.item(i);
|
|
57451
|
+
if (file)
|
|
57452
|
+
processFile(file);
|
|
57453
|
+
}
|
|
57454
|
+
e.target.value = "";
|
|
57455
|
+
}, [processFile]);
|
|
57456
|
+
const hasValue = value.trim().length > 0 || images.length > 0;
|
|
57457
|
+
const canSend = hasValue && !disabled && !isGenerating;
|
|
57458
|
+
let sendClass = "llm-ci-send";
|
|
57459
|
+
if (isGenerating) {
|
|
57460
|
+
sendClass += " llm-ci-send--stop";
|
|
57461
|
+
} else if (canSend) {
|
|
57462
|
+
sendClass += " llm-ci-send--active";
|
|
57463
|
+
} else {
|
|
57464
|
+
sendClass += " llm-ci-send--disabled";
|
|
57465
|
+
}
|
|
57466
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
57467
|
+
className: `llm-ci${className ? ` ${className}` : ""}`,
|
|
57468
|
+
onDragOver: (e) => {
|
|
57469
|
+
e.preventDefault();
|
|
57470
|
+
setIsDragging(true);
|
|
57471
|
+
},
|
|
57472
|
+
onDragLeave: () => setIsDragging(false),
|
|
57473
|
+
onDrop: handleDrop,
|
|
57474
|
+
children: [
|
|
57475
|
+
isDragging && /* @__PURE__ */ jsxDEV("div", {
|
|
57476
|
+
className: "llm-ci-drag-overlay",
|
|
57477
|
+
children: "[Drop image to attach]"
|
|
57478
|
+
}, undefined, false, undefined, this),
|
|
57479
|
+
/* @__PURE__ */ jsxDEV("input", {
|
|
57480
|
+
ref: fileInputRef,
|
|
57481
|
+
type: "file",
|
|
57482
|
+
accept: "image/*",
|
|
57483
|
+
multiple: true,
|
|
57484
|
+
className: "llm-ci-file-input",
|
|
57485
|
+
onChange: handleFileSelect
|
|
57486
|
+
}, undefined, false, undefined, this),
|
|
57487
|
+
images.length > 0 && /* @__PURE__ */ jsxDEV("div", {
|
|
57488
|
+
className: "llm-ci-images",
|
|
57489
|
+
children: images.map((img) => /* @__PURE__ */ jsxDEV("div", {
|
|
57490
|
+
className: "llm-ci-image-preview",
|
|
57491
|
+
children: [
|
|
57492
|
+
/* @__PURE__ */ jsxDEV("img", {
|
|
57493
|
+
src: img.dataUrl,
|
|
57494
|
+
alt: "attachment"
|
|
57495
|
+
}, undefined, false, undefined, this),
|
|
57496
|
+
/* @__PURE__ */ jsxDEV("button", {
|
|
57497
|
+
type: "button",
|
|
57498
|
+
className: "llm-ci-image-remove",
|
|
57499
|
+
onClick: () => onImageRemove?.(img.id),
|
|
57500
|
+
children: /* @__PURE__ */ jsxDEV(XIcon, {}, undefined, false, undefined, this)
|
|
57501
|
+
}, undefined, false, undefined, this)
|
|
57502
|
+
]
|
|
57503
|
+
}, img.id, true, undefined, this))
|
|
57504
|
+
}, undefined, false, undefined, this),
|
|
57505
|
+
/* @__PURE__ */ jsxDEV("textarea", {
|
|
57506
|
+
ref: textareaRef,
|
|
57507
|
+
value,
|
|
57508
|
+
onChange: (e) => onChange(e.target.value),
|
|
57509
|
+
onKeyDown: handleKeyDown,
|
|
57510
|
+
onPaste: handlePaste,
|
|
57511
|
+
placeholder,
|
|
57512
|
+
disabled: disabled && !isGenerating,
|
|
57513
|
+
rows: 1
|
|
57514
|
+
}, undefined, false, undefined, this),
|
|
57515
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
57516
|
+
className: "llm-ci-toolbar",
|
|
57517
|
+
children: [
|
|
57518
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
57519
|
+
className: "llm-ci-left-actions",
|
|
57520
|
+
children: [
|
|
57521
|
+
modelSelector && /* @__PURE__ */ jsxDEV("div", {
|
|
57522
|
+
className: "llm-ci-model-selector",
|
|
57523
|
+
children: modelSelector
|
|
57524
|
+
}, undefined, false, undefined, this),
|
|
57525
|
+
/* @__PURE__ */ jsxDEV("button", {
|
|
57526
|
+
type: "button",
|
|
57527
|
+
className: "llm-ci-btn-icon",
|
|
57528
|
+
onClick: () => fileInputRef.current?.click(),
|
|
57529
|
+
title: "Attach image (or Ctrl+V to paste)",
|
|
57530
|
+
children: /* @__PURE__ */ jsxDEV(ImageIcon, {}, undefined, false, undefined, this)
|
|
57531
|
+
}, undefined, false, undefined, this),
|
|
57532
|
+
actions
|
|
57533
|
+
]
|
|
57534
|
+
}, undefined, true, undefined, this),
|
|
57535
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
57536
|
+
className: "llm-ci-right-actions",
|
|
57537
|
+
children: /* @__PURE__ */ jsxDEV("button", {
|
|
57538
|
+
type: "button",
|
|
57539
|
+
className: sendClass,
|
|
57540
|
+
onClick: isGenerating ? onStop : onSend,
|
|
57541
|
+
disabled: !isGenerating && !canSend,
|
|
57542
|
+
"aria-label": isGenerating ? "Stop generation" : "Send message",
|
|
57543
|
+
children: isGenerating ? /* @__PURE__ */ jsxDEV(Fragment, {
|
|
57544
|
+
children: [
|
|
57545
|
+
/* @__PURE__ */ jsxDEV(StopIcon, {}, undefined, false, undefined, this),
|
|
57546
|
+
" Stop"
|
|
57547
|
+
]
|
|
57548
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV(Fragment, {
|
|
57549
|
+
children: [
|
|
57550
|
+
"Send ",
|
|
57551
|
+
/* @__PURE__ */ jsxDEV(SendIcon, {}, undefined, false, undefined, this)
|
|
57552
|
+
]
|
|
57553
|
+
}, undefined, true, undefined, this)
|
|
57554
|
+
}, undefined, false, undefined, this)
|
|
57555
|
+
}, undefined, false, undefined, this)
|
|
57556
|
+
]
|
|
57557
|
+
}, undefined, true, undefined, this)
|
|
57558
|
+
]
|
|
57559
|
+
}, undefined, true, undefined, this);
|
|
57560
|
+
}
|
|
57561
|
+
|
|
57562
|
+
// src/react/components.tsx
|
|
57563
|
+
import { Streamdown } from "streamdown";
|
|
57564
|
+
import { code } from "@streamdown/code";
|
|
57565
|
+
import { mermaid } from "@streamdown/mermaid";
|
|
57566
|
+
import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
|
|
57567
|
+
var DEFAULT_SYSTEM_PROMPT = `You are a helpful AI assistant.
|
|
57568
|
+
- You can use full Markdown (bold, italic, headers, lists).
|
|
57569
|
+
- You can use Code Blocks with language syntax highlighting.
|
|
57570
|
+
- You can use Mermaid diagrams (\`\`\`mermaid ... \`\`\`).
|
|
57571
|
+
- You can use LaTeX math ($$ ... $$).`;
|
|
57572
|
+
var ALL_MODELS = { ...WEBLLM_MODELS, ...TRANSFORMERS_MODELS };
|
|
57573
|
+
function RetryIcon() {
|
|
57574
|
+
return /* @__PURE__ */ jsxDEV2("svg", {
|
|
57575
|
+
width: "14",
|
|
57576
|
+
height: "14",
|
|
57577
|
+
viewBox: "0 0 24 24",
|
|
57578
|
+
fill: "none",
|
|
57579
|
+
stroke: "currentColor",
|
|
57580
|
+
strokeWidth: "2",
|
|
57581
|
+
strokeLinecap: "round",
|
|
57582
|
+
strokeLinejoin: "round",
|
|
57583
|
+
children: [
|
|
57584
|
+
/* @__PURE__ */ jsxDEV2("polyline", {
|
|
57585
|
+
points: "23 4 23 10 17 10"
|
|
57586
|
+
}, undefined, false, undefined, this),
|
|
57587
|
+
/* @__PURE__ */ jsxDEV2("path", {
|
|
57588
|
+
d: "M20.49 15a9 9 0 1 1-2.12-9.36L23 10"
|
|
57589
|
+
}, undefined, false, undefined, this)
|
|
57590
|
+
]
|
|
57591
|
+
}, undefined, true, undefined, this);
|
|
57592
|
+
}
|
|
57593
|
+
function ChevronDownIcon() {
|
|
57594
|
+
return /* @__PURE__ */ jsxDEV2("svg", {
|
|
57595
|
+
width: "12",
|
|
57596
|
+
height: "12",
|
|
57597
|
+
viewBox: "0 0 24 24",
|
|
57598
|
+
fill: "none",
|
|
57599
|
+
stroke: "currentColor",
|
|
57600
|
+
strokeWidth: "2",
|
|
57601
|
+
strokeLinecap: "round",
|
|
57602
|
+
strokeLinejoin: "round",
|
|
57603
|
+
children: /* @__PURE__ */ jsxDEV2("polyline", {
|
|
57604
|
+
points: "6 9 12 15 18 9"
|
|
57605
|
+
}, undefined, false, undefined, this)
|
|
57606
|
+
}, undefined, false, undefined, this);
|
|
57607
|
+
}
|
|
57608
|
+
var STYLE_ID2 = "__llm-chat-styles";
|
|
57609
|
+
function injectChatStyles(theme) {
|
|
57610
|
+
if (typeof document === "undefined")
|
|
57611
|
+
return;
|
|
57612
|
+
const existing = document.getElementById(STYLE_ID2);
|
|
57613
|
+
if (existing)
|
|
57614
|
+
existing.remove();
|
|
57615
|
+
const d = theme === "dark";
|
|
57616
|
+
const bg2 = d ? "#000000" : "#ffffff";
|
|
57617
|
+
const border = d ? "rgba(255,255,255,0.12)" : "rgba(0,0,0,0.12)";
|
|
57618
|
+
const borderSubtle = d ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)";
|
|
57619
|
+
const text = d ? "#ffffff" : "#000000";
|
|
57620
|
+
const textSecondary = d ? "rgba(255,255,255,0.5)" : "rgba(0,0,0,0.5)";
|
|
57621
|
+
const textTertiary = d ? "rgba(255,255,255,0.3)" : "rgba(0,0,0,0.3)";
|
|
57622
|
+
const surfaceSubtle = d ? "rgba(255,255,255,0.04)" : "rgba(0,0,0,0.03)";
|
|
57623
|
+
const monoFont = `ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace`;
|
|
57624
|
+
const sansFont = `-apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", Roboto, Helvetica, Arial, sans-serif`;
|
|
57625
|
+
const css = `
|
|
57626
|
+
.llm-chat {
|
|
57627
|
+
display: flex;
|
|
57628
|
+
flex-direction: column;
|
|
57629
|
+
border: 1px solid ${border};
|
|
57630
|
+
background: ${bg2};
|
|
57631
|
+
overflow: hidden;
|
|
57632
|
+
font-family: ${sansFont};
|
|
57633
|
+
color: ${text};
|
|
57634
|
+
}
|
|
57635
|
+
|
|
57636
|
+
/* Header */
|
|
57637
|
+
.llm-chat-header {
|
|
57638
|
+
display: flex;
|
|
57639
|
+
align-items: center;
|
|
57640
|
+
justify-content: space-between;
|
|
57641
|
+
padding: 12px 16px;
|
|
57642
|
+
border-bottom: 1px solid ${borderSubtle};
|
|
57643
|
+
}
|
|
57644
|
+
|
|
57645
|
+
/* Model Selector */
|
|
57646
|
+
.llm-chat-model-select {
|
|
57647
|
+
position: relative;
|
|
57648
|
+
}
|
|
57649
|
+
.llm-chat-model-btn {
|
|
57650
|
+
display: flex;
|
|
57651
|
+
align-items: center;
|
|
57652
|
+
gap: 6px;
|
|
57653
|
+
background: transparent;
|
|
57654
|
+
border: none;
|
|
57655
|
+
color: ${text};
|
|
57656
|
+
font-weight: 400;
|
|
57657
|
+
font-size: 11px;
|
|
57658
|
+
font-family: ${monoFont};
|
|
57659
|
+
text-transform: uppercase;
|
|
57660
|
+
letter-spacing: 0.05em;
|
|
57661
|
+
padding: 4px 0;
|
|
57662
|
+
cursor: pointer;
|
|
57663
|
+
transition: opacity 0.1s;
|
|
57664
|
+
}
|
|
57665
|
+
.llm-chat-model-btn:hover {
|
|
57666
|
+
opacity: 0.6;
|
|
57667
|
+
}
|
|
57668
|
+
.llm-chat-model-menu {
|
|
57669
|
+
position: absolute;
|
|
57670
|
+
top: 100%;
|
|
57671
|
+
left: 0;
|
|
57672
|
+
margin-top: 4px;
|
|
57673
|
+
width: 280px;
|
|
57674
|
+
max-height: 300px;
|
|
57675
|
+
overflow-y: auto;
|
|
57676
|
+
background: ${d ? "#0a0a0a" : "#fafafa"};
|
|
57677
|
+
border: 1px solid ${border};
|
|
57678
|
+
z-index: 50;
|
|
57679
|
+
padding: 4px 0;
|
|
57680
|
+
scrollbar-width: thin;
|
|
57681
|
+
}
|
|
57682
|
+
.llm-chat-model-group {
|
|
57683
|
+
padding: 8px 12px 4px;
|
|
57684
|
+
font-size: 10px;
|
|
57685
|
+
font-weight: 400;
|
|
57686
|
+
color: ${textSecondary};
|
|
57687
|
+
text-transform: uppercase;
|
|
57688
|
+
letter-spacing: 0.08em;
|
|
57689
|
+
font-family: ${monoFont};
|
|
57690
|
+
}
|
|
57691
|
+
.llm-chat-model-item {
|
|
57692
|
+
display: block;
|
|
57693
|
+
width: 100%;
|
|
57694
|
+
text-align: left;
|
|
57695
|
+
padding: 6px 12px;
|
|
57696
|
+
font-size: 12px;
|
|
57697
|
+
font-family: ${monoFont};
|
|
57698
|
+
color: ${textSecondary};
|
|
57699
|
+
background: transparent;
|
|
57700
|
+
border: none;
|
|
57701
|
+
cursor: pointer;
|
|
57702
|
+
white-space: nowrap;
|
|
57703
|
+
overflow: hidden;
|
|
57704
|
+
text-overflow: ellipsis;
|
|
57705
|
+
transition: color 0.1s;
|
|
57706
|
+
}
|
|
57707
|
+
.llm-chat-model-item:hover {
|
|
57708
|
+
color: ${text};
|
|
57709
|
+
}
|
|
57710
|
+
.llm-chat-model-item--active {
|
|
57711
|
+
color: ${text};
|
|
57712
|
+
}
|
|
57713
|
+
|
|
57714
|
+
/* Status */
|
|
57715
|
+
.llm-chat-status {
|
|
57716
|
+
display: flex;
|
|
57717
|
+
align-items: center;
|
|
57718
|
+
gap: 8px;
|
|
57719
|
+
font-size: 10px;
|
|
57720
|
+
font-family: ${monoFont};
|
|
57721
|
+
text-transform: uppercase;
|
|
57722
|
+
letter-spacing: 0.08em;
|
|
57723
|
+
color: ${textSecondary};
|
|
57724
|
+
}
|
|
57725
|
+
.llm-chat-dot {
|
|
57726
|
+
width: 5px;
|
|
57727
|
+
height: 5px;
|
|
57728
|
+
border-radius: 50%;
|
|
57729
|
+
}
|
|
57730
|
+
.llm-chat-dot--loading {
|
|
57731
|
+
background: ${textSecondary};
|
|
57732
|
+
animation: llm-pulse 1.5s infinite;
|
|
57733
|
+
}
|
|
57734
|
+
.llm-chat-dot--ready {
|
|
57735
|
+
background: ${text};
|
|
57736
|
+
}
|
|
57737
|
+
.llm-chat-dot--error {
|
|
57738
|
+
background: #ff3333;
|
|
57739
|
+
}
|
|
57740
|
+
|
|
57741
|
+
/* Progress */
|
|
57742
|
+
.llm-chat-progress {
|
|
57743
|
+
padding: 0 16px 8px;
|
|
57744
|
+
}
|
|
57745
|
+
.llm-chat-progress-bar {
|
|
57746
|
+
height: 1px;
|
|
57747
|
+
background: ${borderSubtle};
|
|
57748
|
+
overflow: hidden;
|
|
57749
|
+
}
|
|
57750
|
+
.llm-chat-progress-fill {
|
|
57751
|
+
height: 100%;
|
|
57752
|
+
background: ${text};
|
|
57753
|
+
transition: width 0.3s ease;
|
|
57754
|
+
}
|
|
57755
|
+
.llm-chat-progress-text {
|
|
57756
|
+
font-size: 10px;
|
|
57757
|
+
font-family: ${monoFont};
|
|
57758
|
+
color: ${textTertiary};
|
|
57759
|
+
margin-top: 4px;
|
|
57760
|
+
text-align: right;
|
|
57761
|
+
text-transform: uppercase;
|
|
57762
|
+
letter-spacing: 0.05em;
|
|
57763
|
+
}
|
|
57764
|
+
|
|
57765
|
+
/* Messages */
|
|
57766
|
+
.llm-chat-messages {
|
|
57767
|
+
flex: 1;
|
|
57768
|
+
overflow-y: auto;
|
|
57769
|
+
padding: 20px 16px;
|
|
57770
|
+
display: flex;
|
|
57771
|
+
flex-direction: column;
|
|
57772
|
+
gap: 24px;
|
|
57773
|
+
scrollbar-width: thin;
|
|
57774
|
+
}
|
|
57775
|
+
|
|
57776
|
+
/* Welcome */
|
|
57777
|
+
.llm-chat-welcome {
|
|
57778
|
+
display: flex;
|
|
57779
|
+
flex-direction: column;
|
|
57780
|
+
align-items: flex-start;
|
|
57781
|
+
justify-content: center;
|
|
57782
|
+
flex: 1;
|
|
57783
|
+
color: ${textTertiary};
|
|
57784
|
+
padding: 40px 0;
|
|
57785
|
+
}
|
|
57786
|
+
.llm-chat-welcome h3 {
|
|
57787
|
+
font-size: 11px;
|
|
57788
|
+
font-weight: 400;
|
|
57789
|
+
font-family: ${monoFont};
|
|
57790
|
+
text-transform: uppercase;
|
|
57791
|
+
letter-spacing: 0.08em;
|
|
57792
|
+
color: ${textSecondary};
|
|
57793
|
+
margin: 0 0 8px;
|
|
57794
|
+
}
|
|
57795
|
+
.llm-chat-welcome p {
|
|
57796
|
+
font-size: 13px;
|
|
57797
|
+
margin: 0;
|
|
57798
|
+
max-width: 360px;
|
|
57799
|
+
line-height: 1.6;
|
|
57800
|
+
color: ${textTertiary};
|
|
57801
|
+
}
|
|
57802
|
+
|
|
57803
|
+
/* Bubble */
|
|
57804
|
+
.llm-chat-bubble {
|
|
57805
|
+
display: flex;
|
|
57806
|
+
flex-direction: column;
|
|
57807
|
+
max-width: 100%;
|
|
57808
|
+
}
|
|
57809
|
+
.llm-chat-bubble--user {
|
|
57810
|
+
align-self: flex-end;
|
|
57811
|
+
max-width: 80%;
|
|
57812
|
+
}
|
|
57813
|
+
.llm-chat-bubble--assistant {
|
|
57814
|
+
align-self: flex-start;
|
|
57815
|
+
width: 100%;
|
|
57816
|
+
}
|
|
57817
|
+
|
|
57818
|
+
/* User message — flat, subtle bg, no radius */
|
|
57819
|
+
.llm-chat-user-content {
|
|
57820
|
+
padding: 10px 14px;
|
|
57821
|
+
font-size: 14px;
|
|
57822
|
+
line-height: 1.6;
|
|
57823
|
+
white-space: pre-wrap;
|
|
57824
|
+
background: ${surfaceSubtle};
|
|
57825
|
+
border: 1px solid ${borderSubtle};
|
|
57826
|
+
color: ${text};
|
|
57827
|
+
}
|
|
57828
|
+
|
|
57829
|
+
/* Assistant message */
|
|
57830
|
+
.llm-chat-assistant-content {
|
|
57831
|
+
font-size: 14px;
|
|
57832
|
+
line-height: 1.7;
|
|
57833
|
+
color: ${d ? "rgba(255,255,255,0.85)" : "rgba(0,0,0,0.85)"};
|
|
57834
|
+
}
|
|
57835
|
+
|
|
57836
|
+
/* Streamdown Overrides */
|
|
57837
|
+
.llm-chat-assistant-content pre {
|
|
57838
|
+
background: ${surfaceSubtle} !important;
|
|
57839
|
+
border: 1px solid ${borderSubtle} !important;
|
|
57840
|
+
border-radius: 0 !important;
|
|
57841
|
+
padding: 12px !important;
|
|
57842
|
+
margin: 12px 0 !important;
|
|
57843
|
+
}
|
|
57844
|
+
.llm-chat-assistant-content code {
|
|
57845
|
+
font-family: ${monoFont} !important;
|
|
57846
|
+
font-size: 13px !important;
|
|
57847
|
+
}
|
|
57848
|
+
.llm-chat-assistant-content :not(pre) > code {
|
|
57849
|
+
background: ${surfaceSubtle};
|
|
57850
|
+
border: 1px solid ${borderSubtle};
|
|
57851
|
+
padding: 1px 5px;
|
|
57852
|
+
font-size: 12.5px !important;
|
|
57853
|
+
}
|
|
57854
|
+
|
|
57855
|
+
/* Attachments in message */
|
|
57856
|
+
.llm-chat-msg-images {
|
|
57857
|
+
display: flex;
|
|
57858
|
+
flex-wrap: wrap;
|
|
57859
|
+
gap: 6px;
|
|
57860
|
+
margin-bottom: 8px;
|
|
57861
|
+
justify-content: flex-end;
|
|
57862
|
+
}
|
|
57863
|
+
.llm-chat-msg-img {
|
|
57864
|
+
width: 100px;
|
|
57865
|
+
height: 100px;
|
|
57866
|
+
object-fit: cover;
|
|
57867
|
+
border: 1px solid ${border};
|
|
57868
|
+
}
|
|
57869
|
+
|
|
57870
|
+
/* Error */
|
|
57871
|
+
.llm-chat-error {
|
|
57872
|
+
margin: 0 16px;
|
|
57873
|
+
padding: 10px 14px;
|
|
57874
|
+
border: 1px solid ${d ? "rgba(255,50,50,0.2)" : "rgba(200,0,0,0.15)"};
|
|
57875
|
+
display: flex;
|
|
57876
|
+
align-items: center;
|
|
57877
|
+
justify-content: space-between;
|
|
57878
|
+
gap: 12px;
|
|
57879
|
+
}
|
|
57880
|
+
.llm-chat-error-text {
|
|
57881
|
+
font-size: 12px;
|
|
57882
|
+
font-family: ${monoFont};
|
|
57883
|
+
color: ${d ? "#ff6666" : "#cc0000"};
|
|
57884
|
+
flex: 1;
|
|
57885
|
+
}
|
|
57886
|
+
.llm-chat-error-retry {
|
|
57887
|
+
display: flex;
|
|
57888
|
+
align-items: center;
|
|
57889
|
+
gap: 4px;
|
|
57890
|
+
padding: 4px 10px;
|
|
57891
|
+
border: 1px solid ${d ? "rgba(255,50,50,0.3)" : "rgba(200,0,0,0.2)"};
|
|
57892
|
+
background: transparent;
|
|
57893
|
+
color: ${d ? "#ff6666" : "#cc0000"};
|
|
57894
|
+
font-size: 11px;
|
|
57895
|
+
font-family: ${monoFont};
|
|
57896
|
+
text-transform: uppercase;
|
|
57897
|
+
letter-spacing: 0.05em;
|
|
57898
|
+
cursor: pointer;
|
|
57899
|
+
}
|
|
57900
|
+
.llm-chat-error-retry:hover {
|
|
57901
|
+
background: ${d ? "rgba(255,50,50,0.08)" : "rgba(200,0,0,0.04)"};
|
|
57902
|
+
}
|
|
57903
|
+
|
|
57904
|
+
/* Input Area */
|
|
57905
|
+
.llm-chat-input-area {
|
|
57906
|
+
padding: 12px 16px 16px;
|
|
57907
|
+
border-top: 1px solid ${borderSubtle};
|
|
57908
|
+
}
|
|
57909
|
+
|
|
57910
|
+
@keyframes llm-pulse {
|
|
57911
|
+
0%, 100% { opacity: 1; }
|
|
57912
|
+
50% { opacity: 0.2; }
|
|
57913
|
+
}
|
|
57914
|
+
`;
|
|
57915
|
+
const style = document.createElement("style");
|
|
57916
|
+
style.id = STYLE_ID2;
|
|
57917
|
+
style.textContent = css;
|
|
57918
|
+
document.head.appendChild(style);
|
|
57919
|
+
}
|
|
57920
|
+
function ModelSelector({
|
|
57921
|
+
currentModel,
|
|
57922
|
+
onSelect,
|
|
57923
|
+
theme
|
|
57924
|
+
}) {
|
|
57925
|
+
const [isOpen, setIsOpen] = useState2(false);
|
|
57926
|
+
const ref = useRef2(null);
|
|
57927
|
+
useEffect2(() => {
|
|
57928
|
+
function handleClickOutside(event) {
|
|
57929
|
+
if (ref.current && !ref.current.contains(event.target)) {
|
|
57930
|
+
setIsOpen(false);
|
|
57931
|
+
}
|
|
57932
|
+
}
|
|
57933
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
57934
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
57935
|
+
}, []);
|
|
57936
|
+
const displayModel = useMemo(() => {
|
|
57937
|
+
if (!currentModel)
|
|
57938
|
+
return "Select Model";
|
|
57939
|
+
const id2 = currentModel.split("/").pop() || currentModel;
|
|
57940
|
+
return id2.length > 25 ? id2.substring(0, 25) + "..." : id2;
|
|
57941
|
+
}, [currentModel]);
|
|
57942
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
57943
|
+
className: "llm-chat-model-select",
|
|
57944
|
+
ref,
|
|
57945
|
+
children: [
|
|
57946
|
+
/* @__PURE__ */ jsxDEV2("button", {
|
|
57947
|
+
type: "button",
|
|
57948
|
+
className: "llm-chat-model-btn",
|
|
57949
|
+
onClick: () => setIsOpen(!isOpen),
|
|
57950
|
+
children: [
|
|
57951
|
+
"[",
|
|
57952
|
+
displayModel,
|
|
57953
|
+
"] ",
|
|
57954
|
+
/* @__PURE__ */ jsxDEV2(ChevronDownIcon, {}, undefined, false, undefined, this)
|
|
57955
|
+
]
|
|
57956
|
+
}, undefined, true, undefined, this),
|
|
57957
|
+
isOpen && /* @__PURE__ */ jsxDEV2("div", {
|
|
57958
|
+
className: "llm-chat-model-menu",
|
|
57959
|
+
children: [
|
|
57960
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
57961
|
+
className: "llm-chat-model-group",
|
|
57962
|
+
children: "[WebLLM]"
|
|
57963
|
+
}, undefined, false, undefined, this),
|
|
57964
|
+
Object.entries(WEBLLM_MODELS).map(([key, value]) => /* @__PURE__ */ jsxDEV2("button", {
|
|
57965
|
+
className: `llm-chat-model-item ${currentModel === value ? "llm-chat-model-item--active" : ""}`,
|
|
57966
|
+
onClick: () => {
|
|
57967
|
+
onSelect(value);
|
|
57968
|
+
setIsOpen(false);
|
|
57969
|
+
},
|
|
57970
|
+
children: key
|
|
57971
|
+
}, key, false, undefined, this)),
|
|
57972
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
57973
|
+
className: "llm-chat-model-group",
|
|
57974
|
+
children: "[Transformers.js]"
|
|
57975
|
+
}, undefined, false, undefined, this),
|
|
57976
|
+
Object.entries(TRANSFORMERS_MODELS).map(([key, value]) => /* @__PURE__ */ jsxDEV2("button", {
|
|
57977
|
+
className: `llm-chat-model-item ${currentModel === value ? "llm-chat-model-item--active" : ""}`,
|
|
57978
|
+
onClick: () => {
|
|
57979
|
+
onSelect(value);
|
|
57980
|
+
setIsOpen(false);
|
|
57981
|
+
},
|
|
57982
|
+
children: key
|
|
57983
|
+
}, key, false, undefined, this))
|
|
57984
|
+
]
|
|
57985
|
+
}, undefined, true, undefined, this)
|
|
57986
|
+
]
|
|
57987
|
+
}, undefined, true, undefined, this);
|
|
57988
|
+
}
|
|
57989
|
+
function Chat2({
|
|
57990
|
+
systemPrompt = DEFAULT_SYSTEM_PROMPT,
|
|
57991
|
+
placeholder = "Type a message...",
|
|
57992
|
+
theme = "dark",
|
|
57993
|
+
className,
|
|
57994
|
+
maxHeight = "600px",
|
|
57995
|
+
inputActions,
|
|
57996
|
+
onSend: onSendProp,
|
|
57997
|
+
onResponse,
|
|
57998
|
+
onError: onErrorProp,
|
|
57999
|
+
showHeader = true,
|
|
58000
|
+
showProgress = true,
|
|
58001
|
+
welcomeMessage = "Ready to assist",
|
|
58002
|
+
onModelChange
|
|
58003
|
+
}) {
|
|
58004
|
+
const { llm, isLoading, isReady, loadProgress, error, modelId, reload } = useLLM();
|
|
58005
|
+
const [messages, setMessages] = useState2([]);
|
|
58006
|
+
const [input, setInput] = useState2("");
|
|
58007
|
+
const [isGenerating, setIsGenerating] = useState2(false);
|
|
58008
|
+
const [streamingText, setStreamingText] = useState2("");
|
|
58009
|
+
const [pendingMessage, setPendingMessage] = useState2(null);
|
|
58010
|
+
const [images, setImages] = useState2([]);
|
|
58011
|
+
const messagesEndRef = useRef2(null);
|
|
58012
|
+
const abortRef = useRef2(false);
|
|
58013
|
+
const isProcessingRef = useRef2(false);
|
|
58014
|
+
useEffect2(() => {
|
|
58015
|
+
injectChatStyles(theme);
|
|
58016
|
+
}, [theme]);
|
|
58017
|
+
useEffect2(() => {
|
|
58018
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
58019
|
+
}, [messages, streamingText, isGenerating]);
|
|
58020
|
+
const generate = async (userContent, currentMessages, attachedImages = []) => {
|
|
58021
|
+
if (!llm || !isReady || isProcessingRef.current)
|
|
58022
|
+
return;
|
|
58023
|
+
isProcessingRef.current = true;
|
|
58024
|
+
const userMsg = {
|
|
58025
|
+
role: "user",
|
|
58026
|
+
content: userContent,
|
|
58027
|
+
images: attachedImages
|
|
58028
|
+
};
|
|
58029
|
+
setMessages((prev) => [...prev, userMsg]);
|
|
58030
|
+
setIsGenerating(true);
|
|
58031
|
+
setStreamingText("");
|
|
58032
|
+
abortRef.current = false;
|
|
58033
|
+
const apiMessages = [];
|
|
58034
|
+
if (systemPrompt) {
|
|
58035
|
+
apiMessages.push({ role: "system", content: systemPrompt });
|
|
58036
|
+
}
|
|
58037
|
+
currentMessages.forEach((m) => {
|
|
58038
|
+
apiMessages.push({ role: m.role, content: m.content });
|
|
58039
|
+
});
|
|
58040
|
+
apiMessages.push({ role: "user", content: userContent });
|
|
58041
|
+
try {
|
|
58042
|
+
const response = await llm.stream(apiMessages, (_token, fullText) => {
|
|
58043
|
+
if (abortRef.current)
|
|
58044
|
+
return;
|
|
58045
|
+
setStreamingText(fullText);
|
|
58046
|
+
});
|
|
58047
|
+
if (!abortRef.current) {
|
|
58048
|
+
const assistantMsg = { role: "assistant", content: response };
|
|
58049
|
+
setMessages((prev) => [...prev, assistantMsg]);
|
|
58050
|
+
setStreamingText("");
|
|
58051
|
+
onResponse?.(response);
|
|
58052
|
+
}
|
|
58053
|
+
} catch (err) {
|
|
58054
|
+
const error2 = err instanceof Error ? err : new Error(String(err));
|
|
58055
|
+
onErrorProp?.(error2);
|
|
58056
|
+
setMessages((prev) => [...prev, {
|
|
58057
|
+
role: "assistant",
|
|
58058
|
+
content: `Error: ${error2.message}`
|
|
58059
|
+
}]);
|
|
58060
|
+
} finally {
|
|
58061
|
+
setIsGenerating(false);
|
|
58062
|
+
isProcessingRef.current = false;
|
|
58063
|
+
}
|
|
58064
|
+
};
|
|
58065
|
+
const handleSend = () => {
|
|
58066
|
+
const text = input.trim();
|
|
58067
|
+
if (!text && images.length === 0)
|
|
58068
|
+
return;
|
|
58069
|
+
const currentImages = [...images];
|
|
58070
|
+
setInput("");
|
|
58071
|
+
setImages([]);
|
|
58072
|
+
onSendProp?.(text);
|
|
58073
|
+
if (llm && isReady) {
|
|
58074
|
+
generate(text, messages, currentImages);
|
|
58075
|
+
} else if (isLoading) {
|
|
58076
|
+
setPendingMessage(text);
|
|
58077
|
+
}
|
|
58078
|
+
};
|
|
58079
|
+
const handleStop = () => {
|
|
58080
|
+
abortRef.current = true;
|
|
58081
|
+
setIsGenerating(false);
|
|
58082
|
+
if (streamingText) {
|
|
58083
|
+
setMessages((prev) => [...prev, { role: "assistant", content: streamingText + "..." }]);
|
|
58084
|
+
setStreamingText("");
|
|
58085
|
+
}
|
|
58086
|
+
};
|
|
58087
|
+
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";
|
|
58088
|
+
const statusText = error ? "Error" : isReady ? "Ready" : isLoading ? "Loading" : "Idle";
|
|
58089
|
+
return /* @__PURE__ */ jsxDEV2("div", {
|
|
58090
|
+
className: `llm-chat${className ? ` ${className}` : ""}`,
|
|
58091
|
+
style: { maxHeight, height: "100%" },
|
|
58092
|
+
children: [
|
|
58093
|
+
showHeader && /* @__PURE__ */ jsxDEV2("div", {
|
|
58094
|
+
className: "llm-chat-header",
|
|
58095
|
+
children: [
|
|
58096
|
+
onModelChange ? /* @__PURE__ */ jsxDEV2(ModelSelector, {
|
|
58097
|
+
currentModel: modelId,
|
|
58098
|
+
onSelect: onModelChange,
|
|
58099
|
+
theme
|
|
58100
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV2("div", {
|
|
58101
|
+
className: "llm-chat-model-select",
|
|
58102
|
+
children: /* @__PURE__ */ jsxDEV2("span", {
|
|
58103
|
+
style: {
|
|
58104
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
|
|
58105
|
+
fontSize: "11px",
|
|
58106
|
+
textTransform: "uppercase",
|
|
58107
|
+
letterSpacing: "0.05em"
|
|
58108
|
+
},
|
|
58109
|
+
children: [
|
|
58110
|
+
"[",
|
|
58111
|
+
modelId?.split("/").pop(),
|
|
58112
|
+
"]"
|
|
58113
|
+
]
|
|
58114
|
+
}, undefined, true, undefined, this)
|
|
58115
|
+
}, undefined, false, undefined, this),
|
|
58116
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58117
|
+
className: "llm-chat-status",
|
|
58118
|
+
children: [
|
|
58119
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
58120
|
+
children: statusText
|
|
58121
|
+
}, undefined, false, undefined, this),
|
|
58122
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58123
|
+
className: statusDotClass
|
|
58124
|
+
}, undefined, false, undefined, this)
|
|
58125
|
+
]
|
|
58126
|
+
}, undefined, true, undefined, this)
|
|
58127
|
+
]
|
|
58128
|
+
}, undefined, true, undefined, this),
|
|
58129
|
+
showProgress && isLoading && loadProgress && /* @__PURE__ */ jsxDEV2("div", {
|
|
58130
|
+
className: "llm-chat-progress",
|
|
58131
|
+
children: [
|
|
58132
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58133
|
+
className: "llm-chat-progress-bar",
|
|
58134
|
+
children: /* @__PURE__ */ jsxDEV2("div", {
|
|
58135
|
+
className: "llm-chat-progress-fill",
|
|
58136
|
+
style: { width: `${Math.min(100, loadProgress.progress)}%` }
|
|
58137
|
+
}, undefined, false, undefined, this)
|
|
58138
|
+
}, undefined, false, undefined, this),
|
|
58139
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58140
|
+
className: "llm-chat-progress-text",
|
|
58141
|
+
children: loadProgress.status
|
|
58142
|
+
}, undefined, false, undefined, this)
|
|
58143
|
+
]
|
|
58144
|
+
}, undefined, true, undefined, this),
|
|
58145
|
+
error && /* @__PURE__ */ jsxDEV2("div", {
|
|
58146
|
+
className: "llm-chat-error",
|
|
58147
|
+
children: [
|
|
58148
|
+
/* @__PURE__ */ jsxDEV2("span", {
|
|
58149
|
+
className: "llm-chat-error-text",
|
|
58150
|
+
children: error.message
|
|
58151
|
+
}, undefined, false, undefined, this),
|
|
58152
|
+
/* @__PURE__ */ jsxDEV2("button", {
|
|
58153
|
+
className: "llm-chat-error-retry",
|
|
58154
|
+
onClick: reload,
|
|
58155
|
+
children: [
|
|
58156
|
+
/* @__PURE__ */ jsxDEV2(RetryIcon, {}, undefined, false, undefined, this),
|
|
58157
|
+
" Retry"
|
|
58158
|
+
]
|
|
58159
|
+
}, undefined, true, undefined, this)
|
|
58160
|
+
]
|
|
58161
|
+
}, undefined, true, undefined, this),
|
|
58162
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58163
|
+
className: "llm-chat-messages",
|
|
58164
|
+
children: [
|
|
58165
|
+
!isLoading && messages.length === 0 && !error && /* @__PURE__ */ jsxDEV2("div", {
|
|
58166
|
+
className: "llm-chat-welcome",
|
|
58167
|
+
children: [
|
|
58168
|
+
/* @__PURE__ */ jsxDEV2("h3", {
|
|
58169
|
+
children: [
|
|
58170
|
+
"[",
|
|
58171
|
+
welcomeMessage,
|
|
58172
|
+
"]"
|
|
58173
|
+
]
|
|
58174
|
+
}, undefined, true, undefined, this),
|
|
58175
|
+
/* @__PURE__ */ jsxDEV2("p", {
|
|
58176
|
+
children: "Markdown, code blocks, Mermaid diagrams. Paste images with Ctrl+V."
|
|
58177
|
+
}, undefined, false, undefined, this)
|
|
58178
|
+
]
|
|
58179
|
+
}, undefined, true, undefined, this),
|
|
58180
|
+
messages.map((msg, i) => /* @__PURE__ */ jsxDEV2("div", {
|
|
58181
|
+
className: `llm-chat-bubble llm-chat-bubble--${msg.role}`,
|
|
58182
|
+
children: msg.role === "user" ? /* @__PURE__ */ jsxDEV2(Fragment2, {
|
|
58183
|
+
children: [
|
|
58184
|
+
msg.images && msg.images.length > 0 && /* @__PURE__ */ jsxDEV2("div", {
|
|
58185
|
+
className: "llm-chat-msg-images",
|
|
58186
|
+
children: msg.images.map((img) => /* @__PURE__ */ jsxDEV2("img", {
|
|
58187
|
+
src: img.dataUrl,
|
|
58188
|
+
className: "llm-chat-msg-img",
|
|
58189
|
+
alt: "attachment"
|
|
58190
|
+
}, img.id, false, undefined, this))
|
|
58191
|
+
}, undefined, false, undefined, this),
|
|
58192
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58193
|
+
className: "llm-chat-user-content",
|
|
58194
|
+
children: msg.content
|
|
58195
|
+
}, undefined, false, undefined, this)
|
|
58196
|
+
]
|
|
58197
|
+
}, undefined, true, undefined, this) : /* @__PURE__ */ jsxDEV2("div", {
|
|
58198
|
+
className: "llm-chat-assistant-content",
|
|
58199
|
+
children: /* @__PURE__ */ jsxDEV2(Streamdown, {
|
|
58200
|
+
plugins: { code, mermaid },
|
|
58201
|
+
children: msg.content
|
|
58202
|
+
}, undefined, false, undefined, this)
|
|
58203
|
+
}, undefined, false, undefined, this)
|
|
58204
|
+
}, i, false, undefined, this)),
|
|
58205
|
+
streamingText && /* @__PURE__ */ jsxDEV2("div", {
|
|
58206
|
+
className: "llm-chat-bubble llm-chat-bubble--assistant",
|
|
58207
|
+
children: /* @__PURE__ */ jsxDEV2("div", {
|
|
58208
|
+
className: "llm-chat-assistant-content",
|
|
58209
|
+
children: /* @__PURE__ */ jsxDEV2(Streamdown, {
|
|
58210
|
+
plugins: { code, mermaid },
|
|
58211
|
+
children: streamingText
|
|
58212
|
+
}, undefined, false, undefined, this)
|
|
58213
|
+
}, undefined, false, undefined, this)
|
|
58214
|
+
}, undefined, false, undefined, this),
|
|
58215
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58216
|
+
ref: messagesEndRef
|
|
58217
|
+
}, undefined, false, undefined, this)
|
|
58218
|
+
]
|
|
58219
|
+
}, undefined, true, undefined, this),
|
|
58220
|
+
/* @__PURE__ */ jsxDEV2("div", {
|
|
58221
|
+
className: "llm-chat-input-area",
|
|
58222
|
+
children: /* @__PURE__ */ jsxDEV2(ChatInput, {
|
|
58223
|
+
value: input,
|
|
58224
|
+
onChange: setInput,
|
|
58225
|
+
onSend: handleSend,
|
|
58226
|
+
onStop: handleStop,
|
|
58227
|
+
disabled: !isReady && !isLoading,
|
|
58228
|
+
isGenerating,
|
|
58229
|
+
placeholder: isLoading ? "Model is loading..." : placeholder,
|
|
58230
|
+
theme,
|
|
58231
|
+
actions: inputActions,
|
|
58232
|
+
images,
|
|
58233
|
+
onImageAdd: (img) => setImages((prev) => [...prev, img]),
|
|
58234
|
+
onImageRemove: (id2) => setImages((prev) => prev.filter((img) => img.id !== id2))
|
|
58235
|
+
}, undefined, false, undefined, this)
|
|
58236
|
+
}, undefined, false, undefined, this)
|
|
58237
|
+
]
|
|
58238
|
+
}, undefined, true, undefined, this);
|
|
58239
|
+
}
|
|
58240
|
+
function ChatApp({
|
|
58241
|
+
defaultModel = "qwen-2.5-0.5b",
|
|
58242
|
+
defaultBackend = "auto",
|
|
58243
|
+
autoLoad = true,
|
|
58244
|
+
onModelChange,
|
|
58245
|
+
...chatProps
|
|
58246
|
+
}) {
|
|
58247
|
+
const [model, setModel] = useState2(defaultModel);
|
|
58248
|
+
const handleModelChange = (newModel) => {
|
|
58249
|
+
setModel(newModel);
|
|
58250
|
+
onModelChange?.(newModel);
|
|
58251
|
+
};
|
|
58252
|
+
return /* @__PURE__ */ jsxDEV2(LLMProvider, {
|
|
58253
|
+
model,
|
|
58254
|
+
backend: defaultBackend,
|
|
58255
|
+
autoLoad,
|
|
58256
|
+
children: /* @__PURE__ */ jsxDEV2(Chat2, {
|
|
58257
|
+
...chatProps,
|
|
58258
|
+
onModelChange: handleModelChange
|
|
58259
|
+
}, undefined, false, undefined, this)
|
|
58260
|
+
}, model, false, undefined, this);
|
|
58261
|
+
}
|
|
58262
|
+
|
|
58263
|
+
// src/react/index.tsx
|
|
58264
|
+
import { jsxDEV as jsxDEV3, Fragment as Fragment3 } from "react/jsx-dev-runtime";
|
|
57067
58265
|
var LLMContext = createContext(null);
|
|
57068
58266
|
function LLMProvider({
|
|
57069
58267
|
children,
|
|
@@ -57073,14 +58271,14 @@ function LLMProvider({
|
|
|
57073
58271
|
onError,
|
|
57074
58272
|
...config
|
|
57075
58273
|
}) {
|
|
57076
|
-
const [llm, setLLM] =
|
|
57077
|
-
const [isLoading, setIsLoading] =
|
|
57078
|
-
const [loadProgress, setLoadProgress] =
|
|
57079
|
-
const [error, setError] =
|
|
57080
|
-
const hasLoadedRef =
|
|
57081
|
-
const configRef =
|
|
58274
|
+
const [llm, setLLM] = useState3(null);
|
|
58275
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
58276
|
+
const [loadProgress, setLoadProgress] = useState3(null);
|
|
58277
|
+
const [error, setError] = useState3(null);
|
|
58278
|
+
const hasLoadedRef = useRef3(false);
|
|
58279
|
+
const configRef = useRef3(config);
|
|
57082
58280
|
configRef.current = config;
|
|
57083
|
-
const load =
|
|
58281
|
+
const load = useCallback2(async () => {
|
|
57084
58282
|
if (isLoading)
|
|
57085
58283
|
return;
|
|
57086
58284
|
setIsLoading(true);
|
|
@@ -57105,7 +58303,7 @@ function LLMProvider({
|
|
|
57105
58303
|
setIsLoading(false);
|
|
57106
58304
|
}
|
|
57107
58305
|
}, [isLoading, onLoad, onProgress, onError]);
|
|
57108
|
-
const unload =
|
|
58306
|
+
const unload = useCallback2(async () => {
|
|
57109
58307
|
if (llm) {
|
|
57110
58308
|
await llm.unload();
|
|
57111
58309
|
setLLM(null);
|
|
@@ -57113,24 +58311,24 @@ function LLMProvider({
|
|
|
57113
58311
|
hasLoadedRef.current = false;
|
|
57114
58312
|
}
|
|
57115
58313
|
}, [llm]);
|
|
57116
|
-
const reload =
|
|
58314
|
+
const reload = useCallback2(async () => {
|
|
57117
58315
|
await unload();
|
|
57118
58316
|
await load();
|
|
57119
58317
|
}, [unload, load]);
|
|
57120
|
-
|
|
58318
|
+
useEffect3(() => {
|
|
57121
58319
|
if (autoLoad && !hasLoadedRef.current && !llm && !isLoading) {
|
|
57122
58320
|
hasLoadedRef.current = true;
|
|
57123
58321
|
load();
|
|
57124
58322
|
}
|
|
57125
58323
|
}, [autoLoad, llm, isLoading, load]);
|
|
57126
|
-
|
|
58324
|
+
useEffect3(() => {
|
|
57127
58325
|
return () => {
|
|
57128
58326
|
if (llm) {
|
|
57129
58327
|
llm.unload().catch(console.error);
|
|
57130
58328
|
}
|
|
57131
58329
|
};
|
|
57132
58330
|
}, [llm]);
|
|
57133
|
-
const value =
|
|
58331
|
+
const value = useMemo2(() => ({
|
|
57134
58332
|
llm,
|
|
57135
58333
|
isLoading,
|
|
57136
58334
|
isReady: llm?.isReady ?? false,
|
|
@@ -57141,7 +58339,7 @@ function LLMProvider({
|
|
|
57141
58339
|
reload,
|
|
57142
58340
|
unload
|
|
57143
58341
|
}), [llm, isLoading, loadProgress, error, reload, unload]);
|
|
57144
|
-
return /* @__PURE__ */
|
|
58342
|
+
return /* @__PURE__ */ jsxDEV3(LLMContext.Provider, {
|
|
57145
58343
|
value,
|
|
57146
58344
|
children
|
|
57147
58345
|
}, undefined, false, undefined, this);
|
|
@@ -57165,14 +58363,14 @@ function useChat(options = {}) {
|
|
|
57165
58363
|
onFinish,
|
|
57166
58364
|
onError
|
|
57167
58365
|
} = options;
|
|
57168
|
-
const [messages, setMessages] =
|
|
57169
|
-
const [input, setInput] =
|
|
57170
|
-
const [isGenerating, setIsGenerating] =
|
|
57171
|
-
const [streamingText, setStreamingText] =
|
|
57172
|
-
const [pendingMessage, setPendingMessage] =
|
|
57173
|
-
const abortRef =
|
|
57174
|
-
const isProcessingRef =
|
|
57175
|
-
const generateResponse =
|
|
58366
|
+
const [messages, setMessages] = useState3(initialMessages);
|
|
58367
|
+
const [input, setInput] = useState3("");
|
|
58368
|
+
const [isGenerating, setIsGenerating] = useState3(false);
|
|
58369
|
+
const [streamingText, setStreamingText] = useState3("");
|
|
58370
|
+
const [pendingMessage, setPendingMessage] = useState3(null);
|
|
58371
|
+
const abortRef = useRef3(false);
|
|
58372
|
+
const isProcessingRef = useRef3(false);
|
|
58373
|
+
const generateResponse = useCallback2(async (userContent, currentMessages) => {
|
|
57176
58374
|
if (!llm || !isReady || isProcessingRef.current) {
|
|
57177
58375
|
return "";
|
|
57178
58376
|
}
|
|
@@ -57214,14 +58412,14 @@ function useChat(options = {}) {
|
|
|
57214
58412
|
isProcessingRef.current = false;
|
|
57215
58413
|
}
|
|
57216
58414
|
}, [llm, isReady, systemPrompt, generateOptions, onStart, onToken, onFinish, onError]);
|
|
57217
|
-
|
|
58415
|
+
useEffect3(() => {
|
|
57218
58416
|
if (isReady && pendingMessage && !isProcessingRef.current) {
|
|
57219
58417
|
const messageToProcess = pendingMessage;
|
|
57220
58418
|
setPendingMessage(null);
|
|
57221
58419
|
generateResponse(messageToProcess, messages);
|
|
57222
58420
|
}
|
|
57223
58421
|
}, [isReady, pendingMessage, messages, generateResponse]);
|
|
57224
|
-
const send =
|
|
58422
|
+
const send = useCallback2(async (content) => {
|
|
57225
58423
|
const messageContent = content ?? input;
|
|
57226
58424
|
if (!messageContent.trim()) {
|
|
57227
58425
|
return "";
|
|
@@ -57240,7 +58438,7 @@ function useChat(options = {}) {
|
|
|
57240
58438
|
}
|
|
57241
58439
|
return "";
|
|
57242
58440
|
}, [input, llm, isReady, isLoading, queueWhileLoading, messages, generateResponse]);
|
|
57243
|
-
const stop =
|
|
58441
|
+
const stop = useCallback2(() => {
|
|
57244
58442
|
abortRef.current = true;
|
|
57245
58443
|
setIsGenerating(false);
|
|
57246
58444
|
setPendingMessage(null);
|
|
@@ -57252,16 +58450,16 @@ function useChat(options = {}) {
|
|
|
57252
58450
|
setStreamingText("");
|
|
57253
58451
|
}
|
|
57254
58452
|
}, [streamingText]);
|
|
57255
|
-
const clear =
|
|
58453
|
+
const clear = useCallback2(() => {
|
|
57256
58454
|
setMessages(initialMessages);
|
|
57257
58455
|
setStreamingText("");
|
|
57258
58456
|
setInput("");
|
|
57259
58457
|
setPendingMessage(null);
|
|
57260
58458
|
}, [initialMessages]);
|
|
57261
|
-
const append =
|
|
58459
|
+
const append = useCallback2((message) => {
|
|
57262
58460
|
setMessages((prev) => [...prev, message]);
|
|
57263
58461
|
}, []);
|
|
57264
|
-
const reload =
|
|
58462
|
+
const reload = useCallback2(async () => {
|
|
57265
58463
|
if (messages.length === 0)
|
|
57266
58464
|
return "";
|
|
57267
58465
|
const lastUserIndex = messages.findLastIndex((m) => m.role === "user");
|
|
@@ -57291,10 +58489,10 @@ function useChat(options = {}) {
|
|
|
57291
58489
|
function useStream(options = {}) {
|
|
57292
58490
|
const { llm, isReady } = useLLM();
|
|
57293
58491
|
const { generateOptions, onToken, onFinish, onError } = options;
|
|
57294
|
-
const [text, setText] =
|
|
57295
|
-
const [isStreaming, setIsStreaming] =
|
|
57296
|
-
const abortRef =
|
|
57297
|
-
const stream =
|
|
58492
|
+
const [text, setText] = useState3("");
|
|
58493
|
+
const [isStreaming, setIsStreaming] = useState3(false);
|
|
58494
|
+
const abortRef = useRef3(false);
|
|
58495
|
+
const stream = useCallback2(async (input) => {
|
|
57298
58496
|
if (!llm || !isReady) {
|
|
57299
58497
|
return "";
|
|
57300
58498
|
}
|
|
@@ -57318,11 +58516,11 @@ function useStream(options = {}) {
|
|
|
57318
58516
|
setIsStreaming(false);
|
|
57319
58517
|
}
|
|
57320
58518
|
}, [llm, isReady, generateOptions, onToken, onFinish, onError]);
|
|
57321
|
-
const stop =
|
|
58519
|
+
const stop = useCallback2(() => {
|
|
57322
58520
|
abortRef.current = true;
|
|
57323
58521
|
setIsStreaming(false);
|
|
57324
58522
|
}, []);
|
|
57325
|
-
const clear =
|
|
58523
|
+
const clear = useCallback2(() => {
|
|
57326
58524
|
setText("");
|
|
57327
58525
|
}, []);
|
|
57328
58526
|
return {
|
|
@@ -57336,9 +58534,9 @@ function useStream(options = {}) {
|
|
|
57336
58534
|
function useCompletion(options = {}) {
|
|
57337
58535
|
const { llm, isReady } = useLLM();
|
|
57338
58536
|
const { generateOptions } = options;
|
|
57339
|
-
const [completion, setCompletion] =
|
|
57340
|
-
const [isLoading, setIsLoading] =
|
|
57341
|
-
const complete =
|
|
58537
|
+
const [completion, setCompletion] = useState3("");
|
|
58538
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
58539
|
+
const complete = useCallback2(async (prompt) => {
|
|
57342
58540
|
if (!llm || !isReady) {
|
|
57343
58541
|
return "";
|
|
57344
58542
|
}
|
|
@@ -57354,7 +58552,7 @@ function useCompletion(options = {}) {
|
|
|
57354
58552
|
setIsLoading(false);
|
|
57355
58553
|
}
|
|
57356
58554
|
}, [llm, isReady, generateOptions]);
|
|
57357
|
-
const clear =
|
|
58555
|
+
const clear = useCallback2(() => {
|
|
57358
58556
|
setCompletion("");
|
|
57359
58557
|
}, []);
|
|
57360
58558
|
return {
|
|
@@ -57369,22 +58567,22 @@ function LLMLoading({ children, className }) {
|
|
|
57369
58567
|
if (!isLoading)
|
|
57370
58568
|
return null;
|
|
57371
58569
|
if (children) {
|
|
57372
|
-
return /* @__PURE__ */
|
|
58570
|
+
return /* @__PURE__ */ jsxDEV3("div", {
|
|
57373
58571
|
className,
|
|
57374
58572
|
children
|
|
57375
58573
|
}, undefined, false, undefined, this);
|
|
57376
58574
|
}
|
|
57377
|
-
return /* @__PURE__ */
|
|
58575
|
+
return /* @__PURE__ */ jsxDEV3("div", {
|
|
57378
58576
|
className,
|
|
57379
58577
|
children: [
|
|
57380
|
-
/* @__PURE__ */
|
|
58578
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
57381
58579
|
children: [
|
|
57382
58580
|
"Loading model... ",
|
|
57383
58581
|
loadProgress?.progress ?? 0,
|
|
57384
58582
|
"%"
|
|
57385
58583
|
]
|
|
57386
58584
|
}, undefined, true, undefined, this),
|
|
57387
|
-
/* @__PURE__ */
|
|
58585
|
+
/* @__PURE__ */ jsxDEV3("p", {
|
|
57388
58586
|
children: loadProgress?.status
|
|
57389
58587
|
}, undefined, false, undefined, this)
|
|
57390
58588
|
]
|
|
@@ -57393,11 +58591,11 @@ function LLMLoading({ children, className }) {
|
|
|
57393
58591
|
function LLMReady({ children, fallback = null }) {
|
|
57394
58592
|
const { isReady, isLoading } = useLLM();
|
|
57395
58593
|
if (isLoading || !isReady) {
|
|
57396
|
-
return /* @__PURE__ */
|
|
58594
|
+
return /* @__PURE__ */ jsxDEV3(Fragment3, {
|
|
57397
58595
|
children: fallback
|
|
57398
58596
|
}, undefined, false, undefined, this);
|
|
57399
58597
|
}
|
|
57400
|
-
return /* @__PURE__ */
|
|
58598
|
+
return /* @__PURE__ */ jsxDEV3(Fragment3, {
|
|
57401
58599
|
children
|
|
57402
58600
|
}, undefined, false, undefined, this);
|
|
57403
58601
|
}
|
|
@@ -57408,5 +58606,8 @@ export {
|
|
|
57408
58606
|
useChat,
|
|
57409
58607
|
LLMReady,
|
|
57410
58608
|
LLMProvider,
|
|
57411
|
-
LLMLoading
|
|
58609
|
+
LLMLoading,
|
|
58610
|
+
ChatInput,
|
|
58611
|
+
ChatApp,
|
|
58612
|
+
Chat2 as Chat
|
|
57412
58613
|
};
|