@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.d.mts
CHANGED
|
@@ -57,6 +57,14 @@ interface AlternativeResponse {
|
|
|
57
57
|
model: string;
|
|
58
58
|
content: string;
|
|
59
59
|
timestamp: number;
|
|
60
|
+
sources?: SourceItem[];
|
|
61
|
+
}
|
|
62
|
+
interface SourceItem {
|
|
63
|
+
id: string;
|
|
64
|
+
title: string;
|
|
65
|
+
url: string;
|
|
66
|
+
snippet?: string;
|
|
67
|
+
favicon?: string;
|
|
60
68
|
}
|
|
61
69
|
interface ChatMessage {
|
|
62
70
|
id: string;
|
|
@@ -65,6 +73,7 @@ interface ChatMessage {
|
|
|
65
73
|
model?: string;
|
|
66
74
|
timestamp: number;
|
|
67
75
|
alternatives?: AlternativeResponse[];
|
|
76
|
+
sources?: SourceItem[];
|
|
68
77
|
}
|
|
69
78
|
interface ChatSession {
|
|
70
79
|
id: string;
|
|
@@ -139,7 +148,7 @@ interface ChatUIProps {
|
|
|
139
148
|
/** CSS 클래스 */
|
|
140
149
|
className?: string;
|
|
141
150
|
/** 메시지 전송 핸들러 (커스텀 API 사용 시) */
|
|
142
|
-
onSendMessage?: (params: SendMessageParams) => Promise<
|
|
151
|
+
onSendMessage?: (params: SendMessageParams) => Promise<SendMessageResponse>;
|
|
143
152
|
/** 세션 변경 핸들러 */
|
|
144
153
|
onSessionChange?: (session: ChatSession | null) => void;
|
|
145
154
|
/** 에러 핸들러 */
|
|
@@ -155,6 +164,11 @@ interface SendMessageParams {
|
|
|
155
164
|
apiKey?: string;
|
|
156
165
|
systemPrompt?: string;
|
|
157
166
|
}
|
|
167
|
+
/** onSendMessage 반환 타입 */
|
|
168
|
+
type SendMessageResponse = ReadableStream<Uint8Array> | string | {
|
|
169
|
+
content: string;
|
|
170
|
+
sources?: SourceItem[];
|
|
171
|
+
};
|
|
158
172
|
interface ChatUIComponents {
|
|
159
173
|
/** 사이드바 컴포넌트 */
|
|
160
174
|
Sidebar?: React.ComponentType<SidebarProps>;
|
|
@@ -191,6 +205,8 @@ interface MessageListProps {
|
|
|
191
205
|
onEdit: (message: ChatMessage) => void;
|
|
192
206
|
onRegenerate: (id: string) => void;
|
|
193
207
|
onQuote: (text: string) => void;
|
|
208
|
+
onAskOtherModel?: (messageId: string, targetModel: string) => void;
|
|
209
|
+
models?: ModelConfig[];
|
|
194
210
|
copiedId: string | null;
|
|
195
211
|
editingId: string | null;
|
|
196
212
|
}
|
|
@@ -203,6 +219,8 @@ interface MessageBubbleProps {
|
|
|
203
219
|
onEdit: () => void;
|
|
204
220
|
onRegenerate?: () => void;
|
|
205
221
|
onQuote?: (text: string) => void;
|
|
222
|
+
onAskOtherModel?: (targetModel: string) => void;
|
|
223
|
+
models?: ModelConfig[];
|
|
206
224
|
alternatives?: AlternativeResponse[];
|
|
207
225
|
activeAlternativeIndex?: number;
|
|
208
226
|
onAlternativeChange?: (index: number) => void;
|
|
@@ -281,7 +299,9 @@ interface UseChatUIReturn {
|
|
|
281
299
|
cancelEdit: () => void;
|
|
282
300
|
saveEdit: (content: string) => Promise<void>;
|
|
283
301
|
regenerate: (messageId: string) => Promise<void>;
|
|
302
|
+
askOtherModel: (messageId: string, targetModel: string) => Promise<void>;
|
|
284
303
|
updatePersonalization: (config: Partial<PersonalizationConfig>) => void;
|
|
304
|
+
models: ModelConfig[];
|
|
285
305
|
}
|
|
286
306
|
|
|
287
307
|
/**
|
|
@@ -316,7 +336,7 @@ interface UseChatUIOptions {
|
|
|
316
336
|
/** 압축 후 유지할 메시지 수 */
|
|
317
337
|
keepRecentMessages?: number;
|
|
318
338
|
/** 커스텀 메시지 전송 핸들러 */
|
|
319
|
-
onSendMessage?: (params: SendMessageParams) => Promise<
|
|
339
|
+
onSendMessage?: (params: SendMessageParams) => Promise<SendMessageResponse>;
|
|
320
340
|
/** 세션 변경 핸들러 */
|
|
321
341
|
onSessionChange?: (session: ChatSession | null) => void;
|
|
322
342
|
/** 에러 핸들러 */
|
|
@@ -487,4 +507,4 @@ interface SettingsModalProps {
|
|
|
487
507
|
}
|
|
488
508
|
declare const SettingsModal: React$1.FC<SettingsModalProps>;
|
|
489
509
|
|
|
490
|
-
export { type ActionItem, type ActionMenuProps, type AlternativeResponse, ChatHeader, ChatInput, type ChatMessage, type ChatSession, ChatSidebar, ChatUI, type ChatUIComponents, type ChatUIProps, EmptyState, type EmptyStateProps, type HeaderProps, Icon, type IconName, type IconProps, IconSvg, type InputProps, LinkChip, type LinkChipProps, MarkdownRenderer, type MarkdownRendererProps, type MemoryItem, MemoryPanel, type MemoryPanelProps, MessageBubble, type MessageBubbleProps, MessageList, type MessageListProps, type ModelConfig, type ModelSelectorProps, type PersonalizationConfig, type PromptTemplate, type ProviderType, type ResponseStyle, type SendMessageParams, SettingsModal, type SettingsModalProps, type SettingsTab, type SidebarProps, type ThemeConfig, type ThemeMode, type UseChatUIOptions, type UseChatUIReturn, type UserProfile, useChatUI };
|
|
510
|
+
export { type ActionItem, type ActionMenuProps, type AlternativeResponse, ChatHeader, ChatInput, type ChatMessage, type ChatSession, ChatSidebar, ChatUI, type ChatUIComponents, type ChatUIProps, EmptyState, type EmptyStateProps, type HeaderProps, Icon, type IconName, type IconProps, IconSvg, type InputProps, LinkChip, type LinkChipProps, MarkdownRenderer, type MarkdownRendererProps, type MemoryItem, MemoryPanel, type MemoryPanelProps, MessageBubble, type MessageBubbleProps, MessageList, type MessageListProps, type ModelConfig, type ModelSelectorProps, type PersonalizationConfig, type PromptTemplate, type ProviderType, type ResponseStyle, type SendMessageParams, type SendMessageResponse, SettingsModal, type SettingsModalProps, type SettingsTab, type SidebarProps, type SourceItem, type ThemeConfig, type ThemeMode, type UseChatUIOptions, type UseChatUIReturn, type UserProfile, useChatUI };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -57,6 +57,14 @@ interface AlternativeResponse {
|
|
|
57
57
|
model: string;
|
|
58
58
|
content: string;
|
|
59
59
|
timestamp: number;
|
|
60
|
+
sources?: SourceItem[];
|
|
61
|
+
}
|
|
62
|
+
interface SourceItem {
|
|
63
|
+
id: string;
|
|
64
|
+
title: string;
|
|
65
|
+
url: string;
|
|
66
|
+
snippet?: string;
|
|
67
|
+
favicon?: string;
|
|
60
68
|
}
|
|
61
69
|
interface ChatMessage {
|
|
62
70
|
id: string;
|
|
@@ -65,6 +73,7 @@ interface ChatMessage {
|
|
|
65
73
|
model?: string;
|
|
66
74
|
timestamp: number;
|
|
67
75
|
alternatives?: AlternativeResponse[];
|
|
76
|
+
sources?: SourceItem[];
|
|
68
77
|
}
|
|
69
78
|
interface ChatSession {
|
|
70
79
|
id: string;
|
|
@@ -139,7 +148,7 @@ interface ChatUIProps {
|
|
|
139
148
|
/** CSS 클래스 */
|
|
140
149
|
className?: string;
|
|
141
150
|
/** 메시지 전송 핸들러 (커스텀 API 사용 시) */
|
|
142
|
-
onSendMessage?: (params: SendMessageParams) => Promise<
|
|
151
|
+
onSendMessage?: (params: SendMessageParams) => Promise<SendMessageResponse>;
|
|
143
152
|
/** 세션 변경 핸들러 */
|
|
144
153
|
onSessionChange?: (session: ChatSession | null) => void;
|
|
145
154
|
/** 에러 핸들러 */
|
|
@@ -155,6 +164,11 @@ interface SendMessageParams {
|
|
|
155
164
|
apiKey?: string;
|
|
156
165
|
systemPrompt?: string;
|
|
157
166
|
}
|
|
167
|
+
/** onSendMessage 반환 타입 */
|
|
168
|
+
type SendMessageResponse = ReadableStream<Uint8Array> | string | {
|
|
169
|
+
content: string;
|
|
170
|
+
sources?: SourceItem[];
|
|
171
|
+
};
|
|
158
172
|
interface ChatUIComponents {
|
|
159
173
|
/** 사이드바 컴포넌트 */
|
|
160
174
|
Sidebar?: React.ComponentType<SidebarProps>;
|
|
@@ -191,6 +205,8 @@ interface MessageListProps {
|
|
|
191
205
|
onEdit: (message: ChatMessage) => void;
|
|
192
206
|
onRegenerate: (id: string) => void;
|
|
193
207
|
onQuote: (text: string) => void;
|
|
208
|
+
onAskOtherModel?: (messageId: string, targetModel: string) => void;
|
|
209
|
+
models?: ModelConfig[];
|
|
194
210
|
copiedId: string | null;
|
|
195
211
|
editingId: string | null;
|
|
196
212
|
}
|
|
@@ -203,6 +219,8 @@ interface MessageBubbleProps {
|
|
|
203
219
|
onEdit: () => void;
|
|
204
220
|
onRegenerate?: () => void;
|
|
205
221
|
onQuote?: (text: string) => void;
|
|
222
|
+
onAskOtherModel?: (targetModel: string) => void;
|
|
223
|
+
models?: ModelConfig[];
|
|
206
224
|
alternatives?: AlternativeResponse[];
|
|
207
225
|
activeAlternativeIndex?: number;
|
|
208
226
|
onAlternativeChange?: (index: number) => void;
|
|
@@ -281,7 +299,9 @@ interface UseChatUIReturn {
|
|
|
281
299
|
cancelEdit: () => void;
|
|
282
300
|
saveEdit: (content: string) => Promise<void>;
|
|
283
301
|
regenerate: (messageId: string) => Promise<void>;
|
|
302
|
+
askOtherModel: (messageId: string, targetModel: string) => Promise<void>;
|
|
284
303
|
updatePersonalization: (config: Partial<PersonalizationConfig>) => void;
|
|
304
|
+
models: ModelConfig[];
|
|
285
305
|
}
|
|
286
306
|
|
|
287
307
|
/**
|
|
@@ -316,7 +336,7 @@ interface UseChatUIOptions {
|
|
|
316
336
|
/** 압축 후 유지할 메시지 수 */
|
|
317
337
|
keepRecentMessages?: number;
|
|
318
338
|
/** 커스텀 메시지 전송 핸들러 */
|
|
319
|
-
onSendMessage?: (params: SendMessageParams) => Promise<
|
|
339
|
+
onSendMessage?: (params: SendMessageParams) => Promise<SendMessageResponse>;
|
|
320
340
|
/** 세션 변경 핸들러 */
|
|
321
341
|
onSessionChange?: (session: ChatSession | null) => void;
|
|
322
342
|
/** 에러 핸들러 */
|
|
@@ -487,4 +507,4 @@ interface SettingsModalProps {
|
|
|
487
507
|
}
|
|
488
508
|
declare const SettingsModal: React$1.FC<SettingsModalProps>;
|
|
489
509
|
|
|
490
|
-
export { type ActionItem, type ActionMenuProps, type AlternativeResponse, ChatHeader, ChatInput, type ChatMessage, type ChatSession, ChatSidebar, ChatUI, type ChatUIComponents, type ChatUIProps, EmptyState, type EmptyStateProps, type HeaderProps, Icon, type IconName, type IconProps, IconSvg, type InputProps, LinkChip, type LinkChipProps, MarkdownRenderer, type MarkdownRendererProps, type MemoryItem, MemoryPanel, type MemoryPanelProps, MessageBubble, type MessageBubbleProps, MessageList, type MessageListProps, type ModelConfig, type ModelSelectorProps, type PersonalizationConfig, type PromptTemplate, type ProviderType, type ResponseStyle, type SendMessageParams, SettingsModal, type SettingsModalProps, type SettingsTab, type SidebarProps, type ThemeConfig, type ThemeMode, type UseChatUIOptions, type UseChatUIReturn, type UserProfile, useChatUI };
|
|
510
|
+
export { type ActionItem, type ActionMenuProps, type AlternativeResponse, ChatHeader, ChatInput, type ChatMessage, type ChatSession, ChatSidebar, ChatUI, type ChatUIComponents, type ChatUIProps, EmptyState, type EmptyStateProps, type HeaderProps, Icon, type IconName, type IconProps, IconSvg, type InputProps, LinkChip, type LinkChipProps, MarkdownRenderer, type MarkdownRendererProps, type MemoryItem, MemoryPanel, type MemoryPanelProps, MessageBubble, type MessageBubbleProps, MessageList, type MessageListProps, type ModelConfig, type ModelSelectorProps, type PersonalizationConfig, type PromptTemplate, type ProviderType, type ResponseStyle, type SendMessageParams, type SendMessageResponse, SettingsModal, type SettingsModalProps, type SettingsTab, type SidebarProps, type SourceItem, type ThemeConfig, type ThemeMode, type UseChatUIOptions, type UseChatUIReturn, type UserProfile, useChatUI };
|
package/dist/react/index.js
CHANGED
|
@@ -408,6 +408,22 @@ ${contextSummary}` },
|
|
|
408
408
|
);
|
|
409
409
|
return;
|
|
410
410
|
}
|
|
411
|
+
if (typeof result === "object" && "content" in result) {
|
|
412
|
+
setSessions(
|
|
413
|
+
(prev) => prev.map((s) => {
|
|
414
|
+
if (s.id === capturedSessionId) {
|
|
415
|
+
return {
|
|
416
|
+
...s,
|
|
417
|
+
messages: s.messages.map(
|
|
418
|
+
(m) => m.id === assistantMessageId ? { ...m, content: result.content, sources: result.sources } : m
|
|
419
|
+
)
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
return s;
|
|
423
|
+
})
|
|
424
|
+
);
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
411
427
|
response = new Response(result);
|
|
412
428
|
} else {
|
|
413
429
|
response = await fetch(apiEndpoint, {
|
|
@@ -539,6 +555,158 @@ ${contextSummary}` },
|
|
|
539
555
|
setInput(userMessage.content);
|
|
540
556
|
await sendMessage(userMessage.content);
|
|
541
557
|
}, [currentSession, currentSessionId, isLoading, sendMessage]);
|
|
558
|
+
const askOtherModel = (0, import_react.useCallback)(async (messageId, targetModel) => {
|
|
559
|
+
if (!currentSession || !currentSessionId || isLoading) return;
|
|
560
|
+
const assistantIndex = currentSession.messages.findIndex((m) => m.id === messageId);
|
|
561
|
+
if (assistantIndex === -1) return;
|
|
562
|
+
const assistantMessage = currentSession.messages[assistantIndex];
|
|
563
|
+
if (assistantMessage.role !== "assistant") return;
|
|
564
|
+
const userMessage = currentSession.messages[assistantIndex - 1];
|
|
565
|
+
if (!userMessage || userMessage.role !== "user") return;
|
|
566
|
+
setIsLoading(true);
|
|
567
|
+
abortControllerRef.current = new AbortController();
|
|
568
|
+
try {
|
|
569
|
+
const messagesToSend = currentSession.messages.slice(0, assistantIndex);
|
|
570
|
+
let chatMessages;
|
|
571
|
+
if (currentSession.contextSummary) {
|
|
572
|
+
const recentMessages = messagesToSend.slice(-keepRecentMessages);
|
|
573
|
+
chatMessages = [
|
|
574
|
+
{ role: "system", content: `[\uC774\uC804 \uB300\uD654 \uC694\uC57D]
|
|
575
|
+
${currentSession.contextSummary}` },
|
|
576
|
+
...recentMessages.map((m) => ({ role: m.role, content: m.content }))
|
|
577
|
+
];
|
|
578
|
+
} else {
|
|
579
|
+
chatMessages = messagesToSend.map((m) => ({ role: m.role, content: m.content }));
|
|
580
|
+
}
|
|
581
|
+
const baseSystemPrompt = buildSystemPrompt();
|
|
582
|
+
const messagesForApi = baseSystemPrompt ? [{ role: "system", content: baseSystemPrompt }, ...chatMessages] : chatMessages;
|
|
583
|
+
const modelConfig = models.find((m) => m.id === targetModel);
|
|
584
|
+
const provider = modelConfig?.provider || "ollama";
|
|
585
|
+
let responseContent = "";
|
|
586
|
+
let responseSources;
|
|
587
|
+
if (onSendMessage) {
|
|
588
|
+
const result = await onSendMessage({
|
|
589
|
+
messages: messagesForApi,
|
|
590
|
+
model: targetModel,
|
|
591
|
+
provider,
|
|
592
|
+
apiKey,
|
|
593
|
+
systemPrompt: baseSystemPrompt
|
|
594
|
+
});
|
|
595
|
+
if (typeof result === "string") {
|
|
596
|
+
responseContent = result;
|
|
597
|
+
} else if (typeof result === "object" && "content" in result) {
|
|
598
|
+
responseContent = result.content;
|
|
599
|
+
responseSources = result.sources;
|
|
600
|
+
} else {
|
|
601
|
+
const reader = result.getReader();
|
|
602
|
+
const decoder = new TextDecoder();
|
|
603
|
+
let buffer = "";
|
|
604
|
+
while (true) {
|
|
605
|
+
const { done, value } = await reader.read();
|
|
606
|
+
if (done) break;
|
|
607
|
+
buffer += decoder.decode(value, { stream: true });
|
|
608
|
+
const lines = buffer.split("\n");
|
|
609
|
+
buffer = lines.pop() || "";
|
|
610
|
+
for (const line of lines) {
|
|
611
|
+
if (line.startsWith("data: ")) {
|
|
612
|
+
const data = line.slice(6);
|
|
613
|
+
if (data === "[DONE]") continue;
|
|
614
|
+
try {
|
|
615
|
+
const parsed = JSON.parse(data);
|
|
616
|
+
if (parsed.content) responseContent += parsed.content;
|
|
617
|
+
} catch {
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
} else {
|
|
624
|
+
const response = await fetch(apiEndpoint, {
|
|
625
|
+
method: "POST",
|
|
626
|
+
headers: { "Content-Type": "application/json" },
|
|
627
|
+
body: JSON.stringify({
|
|
628
|
+
messages: messagesForApi,
|
|
629
|
+
model: targetModel,
|
|
630
|
+
provider,
|
|
631
|
+
apiKey: provider === "devdive" ? apiKey : void 0
|
|
632
|
+
}),
|
|
633
|
+
signal: abortControllerRef.current.signal
|
|
634
|
+
});
|
|
635
|
+
if (!response.ok) throw new Error("API error");
|
|
636
|
+
const reader = response.body?.getReader();
|
|
637
|
+
if (!reader) throw new Error("No reader");
|
|
638
|
+
const decoder = new TextDecoder();
|
|
639
|
+
let buffer = "";
|
|
640
|
+
while (true) {
|
|
641
|
+
const { done, value } = await reader.read();
|
|
642
|
+
if (done) break;
|
|
643
|
+
buffer += decoder.decode(value, { stream: true });
|
|
644
|
+
const lines = buffer.split("\n");
|
|
645
|
+
buffer = lines.pop() || "";
|
|
646
|
+
for (const line of lines) {
|
|
647
|
+
if (line.startsWith("data: ")) {
|
|
648
|
+
const data = line.slice(6);
|
|
649
|
+
if (data === "[DONE]") continue;
|
|
650
|
+
try {
|
|
651
|
+
const parsed = JSON.parse(data);
|
|
652
|
+
if (parsed.content) responseContent += parsed.content;
|
|
653
|
+
} catch {
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
const alternative = {
|
|
660
|
+
id: generateId("alt"),
|
|
661
|
+
model: targetModel,
|
|
662
|
+
content: responseContent,
|
|
663
|
+
timestamp: Date.now(),
|
|
664
|
+
sources: responseSources
|
|
665
|
+
};
|
|
666
|
+
const capturedSessionId = currentSessionId;
|
|
667
|
+
setSessions(
|
|
668
|
+
(prev) => prev.map((s) => {
|
|
669
|
+
if (s.id === capturedSessionId) {
|
|
670
|
+
return {
|
|
671
|
+
...s,
|
|
672
|
+
messages: s.messages.map((m) => {
|
|
673
|
+
if (m.id === messageId) {
|
|
674
|
+
const existingAlts = m.alternatives || [];
|
|
675
|
+
return {
|
|
676
|
+
...m,
|
|
677
|
+
alternatives: [...existingAlts, alternative]
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
return m;
|
|
681
|
+
}),
|
|
682
|
+
updatedAt: Date.now()
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
return s;
|
|
686
|
+
})
|
|
687
|
+
);
|
|
688
|
+
} catch (error) {
|
|
689
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
const err = error instanceof Error ? error : new Error("Unknown error");
|
|
693
|
+
onError?.(err);
|
|
694
|
+
} finally {
|
|
695
|
+
setIsLoading(false);
|
|
696
|
+
abortControllerRef.current = null;
|
|
697
|
+
}
|
|
698
|
+
}, [
|
|
699
|
+
currentSession,
|
|
700
|
+
currentSessionId,
|
|
701
|
+
isLoading,
|
|
702
|
+
keepRecentMessages,
|
|
703
|
+
buildSystemPrompt,
|
|
704
|
+
models,
|
|
705
|
+
apiEndpoint,
|
|
706
|
+
apiKey,
|
|
707
|
+
onSendMessage,
|
|
708
|
+
onError
|
|
709
|
+
]);
|
|
542
710
|
return {
|
|
543
711
|
// State
|
|
544
712
|
sessions,
|
|
@@ -573,7 +741,9 @@ ${contextSummary}` },
|
|
|
573
741
|
cancelEdit,
|
|
574
742
|
saveEdit,
|
|
575
743
|
regenerate,
|
|
576
|
-
|
|
744
|
+
askOtherModel,
|
|
745
|
+
updatePersonalization,
|
|
746
|
+
models
|
|
577
747
|
};
|
|
578
748
|
};
|
|
579
749
|
|
|
@@ -2033,15 +2203,20 @@ var MessageBubble = ({
|
|
|
2033
2203
|
onEdit,
|
|
2034
2204
|
onRegenerate,
|
|
2035
2205
|
onQuote,
|
|
2206
|
+
onAskOtherModel,
|
|
2207
|
+
models,
|
|
2036
2208
|
alternatives,
|
|
2037
2209
|
activeAlternativeIndex = 0,
|
|
2038
2210
|
onAlternativeChange
|
|
2039
2211
|
}) => {
|
|
2040
2212
|
const [showActions, setShowActions] = (0, import_react6.useState)(false);
|
|
2213
|
+
const [showModelMenu, setShowModelMenu] = (0, import_react6.useState)(false);
|
|
2041
2214
|
const isUser = message.role === "user";
|
|
2042
2215
|
const isAssistant = message.role === "assistant";
|
|
2216
|
+
const otherModels = models?.filter((m) => m.id !== message.model) || [];
|
|
2043
2217
|
const displayContent = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.content || message.content : message.content;
|
|
2044
2218
|
const displayModel = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.model : message.model;
|
|
2219
|
+
const displaySources = alternatives && alternatives.length > 0 && activeAlternativeIndex > 0 ? alternatives[activeAlternativeIndex - 1]?.sources : message.sources;
|
|
2045
2220
|
const handleMouseUp = () => {
|
|
2046
2221
|
if (!onQuote) return;
|
|
2047
2222
|
const selection = window.getSelection();
|
|
@@ -2166,6 +2341,43 @@ var MessageBubble = ({
|
|
|
2166
2341
|
]
|
|
2167
2342
|
}
|
|
2168
2343
|
),
|
|
2344
|
+
displaySources && displaySources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2345
|
+
"div",
|
|
2346
|
+
{
|
|
2347
|
+
style: {
|
|
2348
|
+
display: "flex",
|
|
2349
|
+
flexWrap: "wrap",
|
|
2350
|
+
gap: "8px",
|
|
2351
|
+
marginTop: "12px",
|
|
2352
|
+
paddingTop: "12px",
|
|
2353
|
+
borderTop: "1px solid var(--chatllm-border-light, #f3f4f6)"
|
|
2354
|
+
},
|
|
2355
|
+
children: [
|
|
2356
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2357
|
+
"span",
|
|
2358
|
+
{
|
|
2359
|
+
style: {
|
|
2360
|
+
fontSize: "12px",
|
|
2361
|
+
fontWeight: 500,
|
|
2362
|
+
color: "var(--chatllm-text-muted, #9ca3af)",
|
|
2363
|
+
marginRight: "4px"
|
|
2364
|
+
},
|
|
2365
|
+
children: "\uCD9C\uCC98:"
|
|
2366
|
+
}
|
|
2367
|
+
),
|
|
2368
|
+
displaySources.map((source, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2369
|
+
LinkChip,
|
|
2370
|
+
{
|
|
2371
|
+
text: source.title,
|
|
2372
|
+
url: source.url,
|
|
2373
|
+
index: index + 1,
|
|
2374
|
+
showFavicon: true
|
|
2375
|
+
},
|
|
2376
|
+
source.id
|
|
2377
|
+
))
|
|
2378
|
+
]
|
|
2379
|
+
}
|
|
2380
|
+
),
|
|
2169
2381
|
alternatives && alternatives.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2170
2382
|
"div",
|
|
2171
2383
|
{
|
|
@@ -2230,7 +2442,110 @@ var MessageBubble = ({
|
|
|
2230
2442
|
}
|
|
2231
2443
|
) }),
|
|
2232
2444
|
isUser && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onEdit, style: actionButtonStyle, title: "\uC218\uC815", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconSvg, { name: "edit-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
|
|
2233
|
-
isAssistant && onRegenerate && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onRegenerate, style: actionButtonStyle, title: "\uB2E4\uC2DC \uC0DD\uC131", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconSvg, { name: "refresh-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) })
|
|
2445
|
+
isAssistant && onRegenerate && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { onClick: onRegenerate, style: actionButtonStyle, title: "\uB2E4\uC2DC \uC0DD\uC131", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconSvg, { name: "refresh-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }) }),
|
|
2446
|
+
isAssistant && onAskOtherModel && otherModels.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { position: "relative" }, children: [
|
|
2447
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2448
|
+
"button",
|
|
2449
|
+
{
|
|
2450
|
+
onClick: () => setShowModelMenu(!showModelMenu),
|
|
2451
|
+
style: actionButtonStyle,
|
|
2452
|
+
title: "\uB2E4\uB978 \uBAA8\uB378\uC5D0\uAC8C \uC9C8\uBB38",
|
|
2453
|
+
children: [
|
|
2454
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconSvg, { name: "robot-line", size: 16, color: "var(--chatllm-text-muted, #9ca3af)" }),
|
|
2455
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2456
|
+
IconSvg,
|
|
2457
|
+
{
|
|
2458
|
+
name: "arrow-down-s-line",
|
|
2459
|
+
size: 12,
|
|
2460
|
+
color: "var(--chatllm-text-muted, #9ca3af)",
|
|
2461
|
+
style: { marginLeft: "2px" }
|
|
2462
|
+
}
|
|
2463
|
+
)
|
|
2464
|
+
]
|
|
2465
|
+
}
|
|
2466
|
+
),
|
|
2467
|
+
showModelMenu && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2468
|
+
"div",
|
|
2469
|
+
{
|
|
2470
|
+
style: {
|
|
2471
|
+
position: "absolute",
|
|
2472
|
+
bottom: "100%",
|
|
2473
|
+
left: 0,
|
|
2474
|
+
marginBottom: "4px",
|
|
2475
|
+
backgroundColor: "var(--chatllm-bg, #ffffff)",
|
|
2476
|
+
border: "1px solid var(--chatllm-border, #e5e7eb)",
|
|
2477
|
+
borderRadius: "8px",
|
|
2478
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.1)",
|
|
2479
|
+
minWidth: "160px",
|
|
2480
|
+
zIndex: 100,
|
|
2481
|
+
overflow: "hidden"
|
|
2482
|
+
},
|
|
2483
|
+
onMouseLeave: () => setShowModelMenu(false),
|
|
2484
|
+
children: [
|
|
2485
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2486
|
+
"div",
|
|
2487
|
+
{
|
|
2488
|
+
style: {
|
|
2489
|
+
padding: "8px 12px",
|
|
2490
|
+
fontSize: "11px",
|
|
2491
|
+
fontWeight: 600,
|
|
2492
|
+
color: "var(--chatllm-text-muted, #9ca3af)",
|
|
2493
|
+
textTransform: "uppercase",
|
|
2494
|
+
borderBottom: "1px solid var(--chatllm-border-light, #f3f4f6)"
|
|
2495
|
+
},
|
|
2496
|
+
children: "\uB2E4\uB978 \uBAA8\uB378\uC5D0\uAC8C \uC9C8\uBB38"
|
|
2497
|
+
}
|
|
2498
|
+
),
|
|
2499
|
+
otherModels.map((model) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
2500
|
+
"button",
|
|
2501
|
+
{
|
|
2502
|
+
onClick: () => {
|
|
2503
|
+
onAskOtherModel(model.id);
|
|
2504
|
+
setShowModelMenu(false);
|
|
2505
|
+
},
|
|
2506
|
+
style: {
|
|
2507
|
+
width: "100%",
|
|
2508
|
+
padding: "10px 12px",
|
|
2509
|
+
display: "flex",
|
|
2510
|
+
alignItems: "center",
|
|
2511
|
+
gap: "8px",
|
|
2512
|
+
backgroundColor: "transparent",
|
|
2513
|
+
border: "none",
|
|
2514
|
+
cursor: "pointer",
|
|
2515
|
+
fontSize: "13px",
|
|
2516
|
+
color: "var(--chatllm-text, #1f2937)",
|
|
2517
|
+
textAlign: "left"
|
|
2518
|
+
},
|
|
2519
|
+
onMouseEnter: (e) => {
|
|
2520
|
+
e.currentTarget.style.backgroundColor = "var(--chatllm-bg-hover, #f3f4f6)";
|
|
2521
|
+
},
|
|
2522
|
+
onMouseLeave: (e) => {
|
|
2523
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
2524
|
+
},
|
|
2525
|
+
children: [
|
|
2526
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(IconSvg, { name: "robot-line", size: 14, color: "var(--chatllm-primary, #3b82f6)" }),
|
|
2527
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { flex: 1 }, children: model.name }),
|
|
2528
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2529
|
+
"span",
|
|
2530
|
+
{
|
|
2531
|
+
style: {
|
|
2532
|
+
fontSize: "10px",
|
|
2533
|
+
padding: "2px 6px",
|
|
2534
|
+
backgroundColor: "var(--chatllm-bg-tertiary, #f3f4f6)",
|
|
2535
|
+
borderRadius: "4px",
|
|
2536
|
+
color: "var(--chatllm-text-muted, #9ca3af)"
|
|
2537
|
+
},
|
|
2538
|
+
children: model.provider
|
|
2539
|
+
}
|
|
2540
|
+
)
|
|
2541
|
+
]
|
|
2542
|
+
},
|
|
2543
|
+
model.id
|
|
2544
|
+
))
|
|
2545
|
+
]
|
|
2546
|
+
}
|
|
2547
|
+
)
|
|
2548
|
+
] })
|
|
2234
2549
|
]
|
|
2235
2550
|
}
|
|
2236
2551
|
)
|
|
@@ -2277,6 +2592,8 @@ var MessageList = ({
|
|
|
2277
2592
|
onEdit,
|
|
2278
2593
|
onRegenerate,
|
|
2279
2594
|
onQuote,
|
|
2595
|
+
onAskOtherModel,
|
|
2596
|
+
models,
|
|
2280
2597
|
copiedId,
|
|
2281
2598
|
editingId
|
|
2282
2599
|
}) => {
|
|
@@ -2341,6 +2658,8 @@ var MessageList = ({
|
|
|
2341
2658
|
onEdit: () => onEdit(message),
|
|
2342
2659
|
onRegenerate: message.role === "assistant" ? () => onRegenerate(message.id) : void 0,
|
|
2343
2660
|
onQuote,
|
|
2661
|
+
onAskOtherModel: message.role === "assistant" && onAskOtherModel ? (targetModel) => onAskOtherModel(message.id, targetModel) : void 0,
|
|
2662
|
+
models,
|
|
2344
2663
|
alternatives: message.alternatives
|
|
2345
2664
|
},
|
|
2346
2665
|
message.id
|
|
@@ -3644,7 +3963,9 @@ var ChatUI = ({
|
|
|
3644
3963
|
cancelEdit,
|
|
3645
3964
|
saveEdit,
|
|
3646
3965
|
regenerate,
|
|
3647
|
-
|
|
3966
|
+
askOtherModel,
|
|
3967
|
+
updatePersonalization,
|
|
3968
|
+
models: hookModels
|
|
3648
3969
|
} = useChatUI(hookOptions);
|
|
3649
3970
|
const greeting = currentPersonalization.userProfile.nickname ? `\uC548\uB155\uD558\uC138\uC694, ${currentPersonalization.userProfile.nickname}\uB2D8` : "\uC548\uB155\uD558\uC138\uC694";
|
|
3650
3971
|
const handleTemplateClick = (template) => {
|
|
@@ -3762,6 +4083,8 @@ var ChatUI = ({
|
|
|
3762
4083
|
onEdit: startEdit,
|
|
3763
4084
|
onRegenerate: regenerate,
|
|
3764
4085
|
onQuote: setQuotedText,
|
|
4086
|
+
onAskOtherModel: askOtherModel,
|
|
4087
|
+
models: hookModels,
|
|
3765
4088
|
copiedId: copiedMessageId,
|
|
3766
4089
|
editingId: editingMessageId
|
|
3767
4090
|
}
|