@gendive/chatllm 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react/index.d.mts +23 -3
- package/dist/react/index.d.ts +23 -3
- package/dist/react/index.js +326 -3
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +326 -3
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -359,6 +359,22 @@ ${contextSummary}` },
|
|
|
359
359
|
);
|
|
360
360
|
return;
|
|
361
361
|
}
|
|
362
|
+
if (typeof result === "object" && "content" in result) {
|
|
363
|
+
setSessions(
|
|
364
|
+
(prev) => prev.map((s) => {
|
|
365
|
+
if (s.id === capturedSessionId) {
|
|
366
|
+
return {
|
|
367
|
+
...s,
|
|
368
|
+
messages: s.messages.map(
|
|
369
|
+
(m) => m.id === assistantMessageId ? { ...m, content: result.content, sources: result.sources } : m
|
|
370
|
+
)
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
return s;
|
|
374
|
+
})
|
|
375
|
+
);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
362
378
|
response = new Response(result);
|
|
363
379
|
} else {
|
|
364
380
|
response = await fetch(apiEndpoint, {
|
|
@@ -490,6 +506,158 @@ ${contextSummary}` },
|
|
|
490
506
|
setInput(userMessage.content);
|
|
491
507
|
await sendMessage(userMessage.content);
|
|
492
508
|
}, [currentSession, currentSessionId, isLoading, sendMessage]);
|
|
509
|
+
const askOtherModel = useCallback(async (messageId, targetModel) => {
|
|
510
|
+
if (!currentSession || !currentSessionId || isLoading) return;
|
|
511
|
+
const assistantIndex = currentSession.messages.findIndex((m) => m.id === messageId);
|
|
512
|
+
if (assistantIndex === -1) return;
|
|
513
|
+
const assistantMessage = currentSession.messages[assistantIndex];
|
|
514
|
+
if (assistantMessage.role !== "assistant") return;
|
|
515
|
+
const userMessage = currentSession.messages[assistantIndex - 1];
|
|
516
|
+
if (!userMessage || userMessage.role !== "user") return;
|
|
517
|
+
setIsLoading(true);
|
|
518
|
+
abortControllerRef.current = new AbortController();
|
|
519
|
+
try {
|
|
520
|
+
const messagesToSend = currentSession.messages.slice(0, assistantIndex);
|
|
521
|
+
let chatMessages;
|
|
522
|
+
if (currentSession.contextSummary) {
|
|
523
|
+
const recentMessages = messagesToSend.slice(-keepRecentMessages);
|
|
524
|
+
chatMessages = [
|
|
525
|
+
{ role: "system", content: `[\uC774\uC804 \uB300\uD654 \uC694\uC57D]
|
|
526
|
+
${currentSession.contextSummary}` },
|
|
527
|
+
...recentMessages.map((m) => ({ role: m.role, content: m.content }))
|
|
528
|
+
];
|
|
529
|
+
} else {
|
|
530
|
+
chatMessages = messagesToSend.map((m) => ({ role: m.role, content: m.content }));
|
|
531
|
+
}
|
|
532
|
+
const baseSystemPrompt = buildSystemPrompt();
|
|
533
|
+
const messagesForApi = baseSystemPrompt ? [{ role: "system", content: baseSystemPrompt }, ...chatMessages] : chatMessages;
|
|
534
|
+
const modelConfig = models.find((m) => m.id === targetModel);
|
|
535
|
+
const provider = modelConfig?.provider || "ollama";
|
|
536
|
+
let responseContent = "";
|
|
537
|
+
let responseSources;
|
|
538
|
+
if (onSendMessage) {
|
|
539
|
+
const result = await onSendMessage({
|
|
540
|
+
messages: messagesForApi,
|
|
541
|
+
model: targetModel,
|
|
542
|
+
provider,
|
|
543
|
+
apiKey,
|
|
544
|
+
systemPrompt: baseSystemPrompt
|
|
545
|
+
});
|
|
546
|
+
if (typeof result === "string") {
|
|
547
|
+
responseContent = result;
|
|
548
|
+
} else if (typeof result === "object" && "content" in result) {
|
|
549
|
+
responseContent = result.content;
|
|
550
|
+
responseSources = result.sources;
|
|
551
|
+
} else {
|
|
552
|
+
const reader = result.getReader();
|
|
553
|
+
const decoder = new TextDecoder();
|
|
554
|
+
let buffer = "";
|
|
555
|
+
while (true) {
|
|
556
|
+
const { done, value } = await reader.read();
|
|
557
|
+
if (done) break;
|
|
558
|
+
buffer += decoder.decode(value, { stream: true });
|
|
559
|
+
const lines = buffer.split("\n");
|
|
560
|
+
buffer = lines.pop() || "";
|
|
561
|
+
for (const line of lines) {
|
|
562
|
+
if (line.startsWith("data: ")) {
|
|
563
|
+
const data = line.slice(6);
|
|
564
|
+
if (data === "[DONE]") continue;
|
|
565
|
+
try {
|
|
566
|
+
const parsed = JSON.parse(data);
|
|
567
|
+
if (parsed.content) responseContent += parsed.content;
|
|
568
|
+
} catch {
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
} else {
|
|
575
|
+
const response = await fetch(apiEndpoint, {
|
|
576
|
+
method: "POST",
|
|
577
|
+
headers: { "Content-Type": "application/json" },
|
|
578
|
+
body: JSON.stringify({
|
|
579
|
+
messages: messagesForApi,
|
|
580
|
+
model: targetModel,
|
|
581
|
+
provider,
|
|
582
|
+
apiKey: provider === "devdive" ? apiKey : void 0
|
|
583
|
+
}),
|
|
584
|
+
signal: abortControllerRef.current.signal
|
|
585
|
+
});
|
|
586
|
+
if (!response.ok) throw new Error("API error");
|
|
587
|
+
const reader = response.body?.getReader();
|
|
588
|
+
if (!reader) throw new Error("No reader");
|
|
589
|
+
const decoder = new TextDecoder();
|
|
590
|
+
let buffer = "";
|
|
591
|
+
while (true) {
|
|
592
|
+
const { done, value } = await reader.read();
|
|
593
|
+
if (done) break;
|
|
594
|
+
buffer += decoder.decode(value, { stream: true });
|
|
595
|
+
const lines = buffer.split("\n");
|
|
596
|
+
buffer = lines.pop() || "";
|
|
597
|
+
for (const line of lines) {
|
|
598
|
+
if (line.startsWith("data: ")) {
|
|
599
|
+
const data = line.slice(6);
|
|
600
|
+
if (data === "[DONE]") continue;
|
|
601
|
+
try {
|
|
602
|
+
const parsed = JSON.parse(data);
|
|
603
|
+
if (parsed.content) responseContent += parsed.content;
|
|
604
|
+
} catch {
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const alternative = {
|
|
611
|
+
id: generateId("alt"),
|
|
612
|
+
model: targetModel,
|
|
613
|
+
content: responseContent,
|
|
614
|
+
timestamp: Date.now(),
|
|
615
|
+
sources: responseSources
|
|
616
|
+
};
|
|
617
|
+
const capturedSessionId = currentSessionId;
|
|
618
|
+
setSessions(
|
|
619
|
+
(prev) => prev.map((s) => {
|
|
620
|
+
if (s.id === capturedSessionId) {
|
|
621
|
+
return {
|
|
622
|
+
...s,
|
|
623
|
+
messages: s.messages.map((m) => {
|
|
624
|
+
if (m.id === messageId) {
|
|
625
|
+
const existingAlts = m.alternatives || [];
|
|
626
|
+
return {
|
|
627
|
+
...m,
|
|
628
|
+
alternatives: [...existingAlts, alternative]
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
return m;
|
|
632
|
+
}),
|
|
633
|
+
updatedAt: Date.now()
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
return s;
|
|
637
|
+
})
|
|
638
|
+
);
|
|
639
|
+
} catch (error) {
|
|
640
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
644
|
+
onError?.(err);
|
|
645
|
+
} finally {
|
|
646
|
+
setIsLoading(false);
|
|
647
|
+
abortControllerRef.current = null;
|
|
648
|
+
}
|
|
649
|
+
}, [
|
|
650
|
+
currentSession,
|
|
651
|
+
currentSessionId,
|
|
652
|
+
isLoading,
|
|
653
|
+
keepRecentMessages,
|
|
654
|
+
buildSystemPrompt,
|
|
655
|
+
models,
|
|
656
|
+
apiEndpoint,
|
|
657
|
+
apiKey,
|
|
658
|
+
onSendMessage,
|
|
659
|
+
onError
|
|
660
|
+
]);
|
|
493
661
|
return {
|
|
494
662
|
// State
|
|
495
663
|
sessions,
|
|
@@ -524,7 +692,9 @@ ${contextSummary}` },
|
|
|
524
692
|
cancelEdit,
|
|
525
693
|
saveEdit,
|
|
526
694
|
regenerate,
|
|
527
|
-
|
|
695
|
+
askOtherModel,
|
|
696
|
+
updatePersonalization,
|
|
697
|
+
models
|
|
528
698
|
};
|
|
529
699
|
};
|
|
530
700
|
|
|
@@ -1984,15 +2154,20 @@ var MessageBubble = ({
|
|
|
1984
2154
|
onEdit,
|
|
1985
2155
|
onRegenerate,
|
|
1986
2156
|
onQuote,
|
|
2157
|
+
onAskOtherModel,
|
|
2158
|
+
models,
|
|
1987
2159
|
alternatives,
|
|
1988
2160
|
activeAlternativeIndex = 0,
|
|
1989
2161
|
onAlternativeChange
|
|
1990
2162
|
}) => {
|
|
1991
2163
|
const [showActions, setShowActions] = useState5(false);
|
|
2164
|
+
const [showModelMenu, setShowModelMenu] = useState5(false);
|
|
1992
2165
|
const isUser = message.role === "user";
|
|
1993
2166
|
const isAssistant = message.role === "assistant";
|
|
2167
|
+
const otherModels = models?.filter((m) => m.id !== message.model) || [];
|
|
1994
2168
|
const displayContent = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.content || message.content : message.content;
|
|
1995
2169
|
const displayModel = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.model : message.model;
|
|
2170
|
+
const displaySources = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.sources : message.sources;
|
|
1996
2171
|
const handleMouseUp = () => {
|
|
1997
2172
|
if (!onQuote) return;
|
|
1998
2173
|
const selection = window.getSelection();
|
|
@@ -2117,6 +2292,43 @@ var MessageBubble = ({
|
|
|
2117
2292
|
]
|
|
2118
2293
|
}
|
|
2119
2294
|
),
|
|
2295
|
+
displaySources && displaySources.length > 0 && /* @__PURE__ */ jsxs6(
|
|
2296
|
+
"div",
|
|
2297
|
+
{
|
|
2298
|
+
style: {
|
|
2299
|
+
display: "flex",
|
|
2300
|
+
flexWrap: "wrap",
|
|
2301
|
+
gap: "8px",
|
|
2302
|
+
marginTop: "12px",
|
|
2303
|
+
paddingTop: "12px",
|
|
2304
|
+
borderTop: "1px solid var(--chatllm-border-light, #f3f4f6)"
|
|
2305
|
+
},
|
|
2306
|
+
children: [
|
|
2307
|
+
/* @__PURE__ */ jsx7(
|
|
2308
|
+
"span",
|
|
2309
|
+
{
|
|
2310
|
+
style: {
|
|
2311
|
+
fontSize: "12px",
|
|
2312
|
+
fontWeight: 500,
|
|
2313
|
+
color: "var(--chatllm-text-muted, #9ca3af)",
|
|
2314
|
+
marginRight: "4px"
|
|
2315
|
+
},
|
|
2316
|
+
children: "\uCD9C\uCC98:"
|
|
2317
|
+
}
|
|
2318
|
+
),
|
|
2319
|
+
displaySources.map((source, index) => /* @__PURE__ */ jsx7(
|
|
2320
|
+
LinkChip,
|
|
2321
|
+
{
|
|
2322
|
+
text: source.title,
|
|
2323
|
+
url: source.url,
|
|
2324
|
+
index: index + 1,
|
|
2325
|
+
showFavicon: true
|
|
2326
|
+
},
|
|
2327
|
+
source.id
|
|
2328
|
+
))
|
|
2329
|
+
]
|
|
2330
|
+
}
|
|
2331
|
+
),
|
|
2120
2332
|
alternatives && alternatives.length > 0 && /* @__PURE__ */ jsxs6(
|
|
2121
2333
|
"div",
|
|
2122
2334
|
{
|
|
@@ -2181,7 +2393,110 @@ var MessageBubble = ({
|
|
|
2181
2393
|
}
|
|
2182
2394
|
) }),
|
|
2183
2395
|
isUser && /* @__PURE__ */ jsx7("button", { onClick: onEdit, style: actionButtonStyle, title: "\uC218\uC815", children: /* @__PURE__ */ jsx7(IconSvg, { name: "edit-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
|
|
2184
|
-
isAssistant && onRegenerate && /* @__PURE__ */ jsx7("button", { onClick: onRegenerate, style: actionButtonStyle, title: "\uB2E4\uC2DC \uC0DD\uC131", children: /* @__PURE__ */ jsx7(IconSvg, { name: "refresh-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) })
|
|
2396
|
+
isAssistant && onRegenerate && /* @__PURE__ */ jsx7("button", { onClick: onRegenerate, style: actionButtonStyle, title: "\uB2E4\uC2DC \uC0DD\uC131", children: /* @__PURE__ */ jsx7(IconSvg, { name: "refresh-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
|
|
2397
|
+
isAssistant && onAskOtherModel && otherModels.length > 0 && /* @__PURE__ */ jsxs6("div", { style: { position: "relative" }, children: [
|
|
2398
|
+
/* @__PURE__ */ jsxs6(
|
|
2399
|
+
"button",
|
|
2400
|
+
{
|
|
2401
|
+
onClick: () => setShowModelMenu(!showModelMenu),
|
|
2402
|
+
style: actionButtonStyle,
|
|
2403
|
+
title: "\uB2E4\uB978 \uBAA8\uB378\uC5D0\uAC8C \uC9C8\uBB38",
|
|
2404
|
+
children: [
|
|
2405
|
+
/* @__PURE__ */ jsx7(IconSvg, { name: "robot-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }),
|
|
2406
|
+
/* @__PURE__ */ jsx7(
|
|
2407
|
+
IconSvg,
|
|
2408
|
+
{
|
|
2409
|
+
name: "arrow-down-s-line",
|
|
2410
|
+
size: 12,
|
|
2411
|
+
color: "var(--chatllm-text-muted, #9ca3af)",
|
|
2412
|
+
style: { marginLeft: "2px" }
|
|
2413
|
+
}
|
|
2414
|
+
)
|
|
2415
|
+
]
|
|
2416
|
+
}
|
|
2417
|
+
),
|
|
2418
|
+
showModelMenu && /* @__PURE__ */ jsxs6(
|
|
2419
|
+
"div",
|
|
2420
|
+
{
|
|
2421
|
+
style: {
|
|
2422
|
+
position: "absolute",
|
|
2423
|
+
bottom: "100%",
|
|
2424
|
+
left: 0,
|
|
2425
|
+
marginBottom: "4px",
|
|
2426
|
+
backgroundColor: "var(--chatllm-bg, #ffffff)",
|
|
2427
|
+
border: "1px solid var(--chatllm-border, #e5e7eb)",
|
|
2428
|
+
borderRadius: "8px",
|
|
2429
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
|
|
2430
|
+
minWidth: "160px",
|
|
2431
|
+
zIndex: 100,
|
|
2432
|
+
overflow: "hidden"
|
|
2433
|
+
},
|
|
2434
|
+
onMouseLeave: () => setShowModelMenu(false),
|
|
2435
|
+
children: [
|
|
2436
|
+
/* @__PURE__ */ jsx7(
|
|
2437
|
+
"div",
|
|
2438
|
+
{
|
|
2439
|
+
style: {
|
|
2440
|
+
padding: "8px 12px",
|
|
2441
|
+
fontSize: "11px",
|
|
2442
|
+
fontWeight: 600,
|
|
2443
|
+
color: "var(--chatllm-text-muted, #9ca3af)",
|
|
2444
|
+
textTransform: "uppercase",
|
|
2445
|
+
borderBottom: "1px solid var(--chatllm-border-light, #f3f4f6)"
|
|
2446
|
+
},
|
|
2447
|
+
children: "\uB2E4\uB978 \uBAA8\uB378\uC5D0\uAC8C \uC9C8\uBB38"
|
|
2448
|
+
}
|
|
2449
|
+
),
|
|
2450
|
+
otherModels.map((model) => /* @__PURE__ */ jsxs6(
|
|
2451
|
+
"button",
|
|
2452
|
+
{
|
|
2453
|
+
onClick: () => {
|
|
2454
|
+
onAskOtherModel(model.id);
|
|
2455
|
+
setShowModelMenu(false);
|
|
2456
|
+
},
|
|
2457
|
+
style: {
|
|
2458
|
+
width: "100%",
|
|
2459
|
+
padding: "10px 12px",
|
|
2460
|
+
display: "flex",
|
|
2461
|
+
alignItems: "center",
|
|
2462
|
+
gap: "8px",
|
|
2463
|
+
backgroundColor: "transparent",
|
|
2464
|
+
border: "none",
|
|
2465
|
+
cursor: "pointer",
|
|
2466
|
+
fontSize: "13px",
|
|
2467
|
+
color: "var(--chatllm-text, #1f2937)",
|
|
2468
|
+
textAlign: "left"
|
|
2469
|
+
},
|
|
2470
|
+
onMouseEnter: (e) => {
|
|
2471
|
+
e.currentTarget.style.backgroundColor = "var(--chatllm-bg-hover, #f3f4f6)";
|
|
2472
|
+
},
|
|
2473
|
+
onMouseLeave: (e) => {
|
|
2474
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
2475
|
+
},
|
|
2476
|
+
children: [
|
|
2477
|
+
/* @__PURE__ */ jsx7(IconSvg, { name: "robot-line", size: 14, color: "var(--chatllm-primary, #3b82f6)" }),
|
|
2478
|
+
/* @__PURE__ */ jsx7("span", { style: { flex: 1 }, children: model.name }),
|
|
2479
|
+
/* @__PURE__ */ jsx7(
|
|
2480
|
+
"span",
|
|
2481
|
+
{
|
|
2482
|
+
style: {
|
|
2483
|
+
fontSize: "10px",
|
|
2484
|
+
padding: "2px 6px",
|
|
2485
|
+
backgroundColor: "var(--chatllm-bg-tertiary, #f3f4f6)",
|
|
2486
|
+
borderRadius: "4px",
|
|
2487
|
+
color: "var(--chatllm-text-muted, #9ca3af)"
|
|
2488
|
+
},
|
|
2489
|
+
children: model.provider
|
|
2490
|
+
}
|
|
2491
|
+
)
|
|
2492
|
+
]
|
|
2493
|
+
},
|
|
2494
|
+
model.id
|
|
2495
|
+
))
|
|
2496
|
+
]
|
|
2497
|
+
}
|
|
2498
|
+
)
|
|
2499
|
+
] })
|
|
2185
2500
|
]
|
|
2186
2501
|
}
|
|
2187
2502
|
)
|
|
@@ -2228,6 +2543,8 @@ var MessageList = ({
|
|
|
2228
2543
|
onEdit,
|
|
2229
2544
|
onRegenerate,
|
|
2230
2545
|
onQuote,
|
|
2546
|
+
onAskOtherModel,
|
|
2547
|
+
models,
|
|
2231
2548
|
copiedId,
|
|
2232
2549
|
editingId
|
|
2233
2550
|
}) => {
|
|
@@ -2292,6 +2609,8 @@ var MessageList = ({
|
|
|
2292
2609
|
onEdit: () => onEdit(message),
|
|
2293
2610
|
onRegenerate: message.role === "assistant" ? () => onRegenerate(message.id) : void 0,
|
|
2294
2611
|
onQuote,
|
|
2612
|
+
onAskOtherModel: message.role === "assistant" && onAskOtherModel ? (targetModel) => onAskOtherModel(message.id, targetModel) : void 0,
|
|
2613
|
+
models,
|
|
2295
2614
|
alternatives: message.alternatives
|
|
2296
2615
|
},
|
|
2297
2616
|
message.id
|
|
@@ -3595,7 +3914,9 @@ var ChatUI = ({
|
|
|
3595
3914
|
cancelEdit,
|
|
3596
3915
|
saveEdit,
|
|
3597
3916
|
regenerate,
|
|
3598
|
-
|
|
3917
|
+
askOtherModel,
|
|
3918
|
+
updatePersonalization,
|
|
3919
|
+
models: hookModels
|
|
3599
3920
|
} = useChatUI(hookOptions);
|
|
3600
3921
|
const greeting = currentPersonalization.userProfile.nickname ? `\uC548\uB155\uD558\uC138\uC694, ${currentPersonalization.userProfile.nickname}\uB2D8` : "\uC548\uB155\uD558\uC138\uC694";
|
|
3601
3922
|
const handleTemplateClick = (template) => {
|
|
@@ -3713,6 +4034,8 @@ var ChatUI = ({
|
|
|
3713
4034
|
onEdit: startEdit,
|
|
3714
4035
|
onRegenerate: regenerate,
|
|
3715
4036
|
onQuote: setQuotedText,
|
|
4037
|
+
onAskOtherModel: askOtherModel,
|
|
4038
|
+
models: hookModels,
|
|
3716
4039
|
copiedId: copiedMessageId,
|
|
3717
4040
|
editingId: editingMessageId
|
|
3718
4041
|
}
|