@gendive/chatllm 0.6.2 → 0.6.4
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 +4 -5
- package/dist/react/index.d.mts +23 -13
- package/dist/react/index.d.ts +23 -13
- package/dist/react/index.js +178 -15
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +178 -15
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -931,12 +931,11 @@ const response = await fetch('http://localhost:11434/api/chat', {
|
|
|
931
931
|
|
|
932
932
|
```typescript
|
|
933
933
|
// DevDive Gateway API
|
|
934
|
-
const response = await fetch(
|
|
935
934
|
`https://prd-gtw.devdive.ai/model/text-generation/v1/${model}`,
|
|
936
935
|
{
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
936
|
+
const response = await fetch(
|
|
937
|
+
headers: {
|
|
938
|
+
'Content-Type': 'application/json',
|
|
940
939
|
'X-API-KEY': apiKey,
|
|
941
940
|
},
|
|
942
941
|
body: JSON.stringify({
|
|
@@ -948,5 +947,5 @@ const response = await fetch(
|
|
|
948
947
|
}
|
|
949
948
|
)
|
|
950
949
|
```
|
|
951
|
-
|
|
950
|
+
method: 'POST',
|
|
952
951
|
---
|
package/dist/react/index.d.mts
CHANGED
|
@@ -48,6 +48,26 @@ interface PersonalizationConfig {
|
|
|
48
48
|
language: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @description 마크다운 렌더러 컴포넌트
|
|
53
|
+
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
interface ChoiceOption {
|
|
57
|
+
number: number;
|
|
58
|
+
text: string;
|
|
59
|
+
fullText: string;
|
|
60
|
+
}
|
|
61
|
+
interface MarkdownRendererProps {
|
|
62
|
+
/** 마크다운 텍스트 */
|
|
63
|
+
content: string;
|
|
64
|
+
/** 커스텀 클래스 */
|
|
65
|
+
className?: string;
|
|
66
|
+
/** 선택지 클릭 핸들러 */
|
|
67
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
68
|
+
}
|
|
69
|
+
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
70
|
+
|
|
51
71
|
/**
|
|
52
72
|
* @description React UI 컴포넌트 타입 정의
|
|
53
73
|
*/
|
|
@@ -211,6 +231,8 @@ interface MessageListProps {
|
|
|
211
231
|
models?: ModelConfig[];
|
|
212
232
|
copiedId: string | null;
|
|
213
233
|
editingId: string | null;
|
|
234
|
+
/** 선택지 클릭 핸들러 */
|
|
235
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
214
236
|
}
|
|
215
237
|
interface MessageBubbleProps {
|
|
216
238
|
message: ChatMessage;
|
|
@@ -227,6 +249,7 @@ interface MessageBubbleProps {
|
|
|
227
249
|
activeAlternativeIndex?: number;
|
|
228
250
|
models?: ModelConfig[];
|
|
229
251
|
alternatives?: AlternativeResponse[];
|
|
252
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
230
253
|
}
|
|
231
254
|
interface InputProps {
|
|
232
255
|
value: string;
|
|
@@ -454,19 +477,6 @@ interface MemoryPanelProps {
|
|
|
454
477
|
}
|
|
455
478
|
declare const MemoryPanel: React$1.FC<MemoryPanelProps>;
|
|
456
479
|
|
|
457
|
-
/**
|
|
458
|
-
* @description 마크다운 렌더러 컴포넌트
|
|
459
|
-
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
460
|
-
*/
|
|
461
|
-
|
|
462
|
-
interface MarkdownRendererProps {
|
|
463
|
-
/** 마크다운 텍스트 */
|
|
464
|
-
content: string;
|
|
465
|
-
/** 커스텀 클래스 */
|
|
466
|
-
className?: string;
|
|
467
|
-
}
|
|
468
|
-
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
469
|
-
|
|
470
480
|
/**
|
|
471
481
|
* @description 링크 칩 컴포넌트
|
|
472
482
|
* 출처 링크를 칩 형태로 표시
|
package/dist/react/index.d.ts
CHANGED
|
@@ -48,6 +48,26 @@ interface PersonalizationConfig {
|
|
|
48
48
|
language: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* @description 마크다운 렌더러 컴포넌트
|
|
53
|
+
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
interface ChoiceOption {
|
|
57
|
+
number: number;
|
|
58
|
+
text: string;
|
|
59
|
+
fullText: string;
|
|
60
|
+
}
|
|
61
|
+
interface MarkdownRendererProps {
|
|
62
|
+
/** 마크다운 텍스트 */
|
|
63
|
+
content: string;
|
|
64
|
+
/** 커스텀 클래스 */
|
|
65
|
+
className?: string;
|
|
66
|
+
/** 선택지 클릭 핸들러 */
|
|
67
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
68
|
+
}
|
|
69
|
+
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
70
|
+
|
|
51
71
|
/**
|
|
52
72
|
* @description React UI 컴포넌트 타입 정의
|
|
53
73
|
*/
|
|
@@ -211,6 +231,8 @@ interface MessageListProps {
|
|
|
211
231
|
models?: ModelConfig[];
|
|
212
232
|
copiedId: string | null;
|
|
213
233
|
editingId: string | null;
|
|
234
|
+
/** 선택지 클릭 핸들러 */
|
|
235
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
214
236
|
}
|
|
215
237
|
interface MessageBubbleProps {
|
|
216
238
|
message: ChatMessage;
|
|
@@ -227,6 +249,7 @@ interface MessageBubbleProps {
|
|
|
227
249
|
activeAlternativeIndex?: number;
|
|
228
250
|
models?: ModelConfig[];
|
|
229
251
|
alternatives?: AlternativeResponse[];
|
|
252
|
+
onChoiceClick?: (choice: ChoiceOption) => void;
|
|
230
253
|
}
|
|
231
254
|
interface InputProps {
|
|
232
255
|
value: string;
|
|
@@ -454,19 +477,6 @@ interface MemoryPanelProps {
|
|
|
454
477
|
}
|
|
455
478
|
declare const MemoryPanel: React$1.FC<MemoryPanelProps>;
|
|
456
479
|
|
|
457
|
-
/**
|
|
458
|
-
* @description 마크다운 렌더러 컴포넌트
|
|
459
|
-
* 외부 의존성 없이 기본 마크다운 파싱 지원
|
|
460
|
-
*/
|
|
461
|
-
|
|
462
|
-
interface MarkdownRendererProps {
|
|
463
|
-
/** 마크다운 텍스트 */
|
|
464
|
-
content: string;
|
|
465
|
-
/** 커스텀 클래스 */
|
|
466
|
-
className?: string;
|
|
467
|
-
}
|
|
468
|
-
declare const MarkdownRenderer: React$1.FC<MarkdownRendererProps>;
|
|
469
|
-
|
|
470
480
|
/**
|
|
471
481
|
* @description 링크 칩 컴포넌트
|
|
472
482
|
* 출처 링크를 칩 형태로 표시
|
package/dist/react/index.js
CHANGED
|
@@ -1819,8 +1819,9 @@ var LinkChip = ({
|
|
|
1819
1819
|
|
|
1820
1820
|
// src/react/components/MarkdownRenderer.tsx
|
|
1821
1821
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1822
|
-
var
|
|
1823
|
-
var
|
|
1822
|
+
var IMAGE_REGEX = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
|
1823
|
+
var LINK_REGEX = /(?<!!)\[([^\]]+)\]\(([^)]+)\)/g;
|
|
1824
|
+
var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((?:(?<!!)\[`?[^\]]+`?\]\([^)]+\)\s*)+)/gi;
|
|
1824
1825
|
var CODE_BLOCK_REGEX = /```(\w*)\n?([\s\S]*?)```/g;
|
|
1825
1826
|
var INLINE_CODE_REGEX = /`([^`]+)`/g;
|
|
1826
1827
|
var BOLD_REGEX = /\*\*([^*]+)\*\*/g;
|
|
@@ -1847,8 +1848,9 @@ var parseInlineElements = (text, key) => {
|
|
|
1847
1848
|
currentText = currentText.replace(INLINE_CODE_REGEX, "\xA7CODE\xA7$1\xA7/CODE\xA7");
|
|
1848
1849
|
currentText = currentText.replace(BOLD_REGEX, "\xA7BOLD\xA7$1\xA7/BOLD\xA7");
|
|
1849
1850
|
currentText = currentText.replace(ITALIC_REGEX, "\xA7ITALIC\xA7$1\xA7/ITALIC\xA7");
|
|
1851
|
+
currentText = currentText.replace(IMAGE_REGEX, "\xA7IMAGE\xA7$1\xA7URL\xA7$2\xA7/IMAGE\xA7");
|
|
1850
1852
|
currentText = currentText.replace(LINK_REGEX, "\xA7LINK\xA7$1\xA7URL\xA7$2\xA7/LINK\xA7");
|
|
1851
|
-
const parts = currentText.split(/(§CODE§.*?§\/CODE§|§BOLD§.*?§\/BOLD§|§ITALIC§.*?§\/ITALIC§|§LINK§.*?§\/LINK§)/);
|
|
1853
|
+
const parts = currentText.split(/(§CODE§.*?§\/CODE§|§BOLD§.*?§\/BOLD§|§ITALIC§.*?§\/ITALIC§|§IMAGE§.*?§\/IMAGE§|§LINK§.*?§\/LINK§)/);
|
|
1852
1854
|
parts.forEach((part, index) => {
|
|
1853
1855
|
if (part.startsWith("\xA7CODE\xA7")) {
|
|
1854
1856
|
const content = part.replace("\xA7CODE\xA7", "").replace("\xA7/CODE\xA7", "");
|
|
@@ -1875,6 +1877,28 @@ var parseInlineElements = (text, key) => {
|
|
|
1875
1877
|
} else if (part.startsWith("\xA7ITALIC\xA7")) {
|
|
1876
1878
|
const content = part.replace("\xA7ITALIC\xA7", "").replace("\xA7/ITALIC\xA7", "");
|
|
1877
1879
|
elements.push(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("em", { children: content }, `${key}-italic-${index}`));
|
|
1880
|
+
} else if (part.startsWith("\xA7IMAGE\xA7")) {
|
|
1881
|
+
const match = part.match(/§IMAGE§(.*)§URL§(.+?)§\/IMAGE§/);
|
|
1882
|
+
if (match) {
|
|
1883
|
+
elements.push(
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1885
|
+
"img",
|
|
1886
|
+
{
|
|
1887
|
+
src: match[2],
|
|
1888
|
+
alt: match[1] || "",
|
|
1889
|
+
className: "chatllm-image",
|
|
1890
|
+
style: {
|
|
1891
|
+
maxWidth: "100%",
|
|
1892
|
+
borderRadius: "8px",
|
|
1893
|
+
margin: "8px 0",
|
|
1894
|
+
display: "block"
|
|
1895
|
+
},
|
|
1896
|
+
loading: "lazy"
|
|
1897
|
+
},
|
|
1898
|
+
`${key}-image-${index}`
|
|
1899
|
+
)
|
|
1900
|
+
);
|
|
1901
|
+
}
|
|
1878
1902
|
} else if (part.startsWith("\xA7LINK\xA7")) {
|
|
1879
1903
|
const match = part.match(/§LINK§(.+?)§URL§(.+?)§\/LINK§/);
|
|
1880
1904
|
if (match) {
|
|
@@ -2042,6 +2066,96 @@ var CodeBlock = ({ language, code }) => {
|
|
|
2042
2066
|
}
|
|
2043
2067
|
);
|
|
2044
2068
|
};
|
|
2069
|
+
var ChoiceButtons = ({ choices, onChoiceClick }) => {
|
|
2070
|
+
const [hoveredIndex, setHoveredIndex] = import_react5.default.useState(null);
|
|
2071
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2072
|
+
"div",
|
|
2073
|
+
{
|
|
2074
|
+
className: "chatllm-choices",
|
|
2075
|
+
style: {
|
|
2076
|
+
display: "flex",
|
|
2077
|
+
flexDirection: "column",
|
|
2078
|
+
gap: "8px",
|
|
2079
|
+
margin: "16px 0",
|
|
2080
|
+
padding: "12px",
|
|
2081
|
+
backgroundColor: "var(--chatllm-bg-secondary, #f9fafb)",
|
|
2082
|
+
borderRadius: "12px",
|
|
2083
|
+
border: "1px solid var(--chatllm-border-light, #e5e7eb)"
|
|
2084
|
+
},
|
|
2085
|
+
children: [
|
|
2086
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2087
|
+
"div",
|
|
2088
|
+
{
|
|
2089
|
+
style: {
|
|
2090
|
+
fontSize: "12px",
|
|
2091
|
+
fontWeight: 600,
|
|
2092
|
+
color: "var(--chatllm-text-muted, #6b7280)",
|
|
2093
|
+
marginBottom: "4px",
|
|
2094
|
+
textTransform: "uppercase",
|
|
2095
|
+
letterSpacing: "0.5px"
|
|
2096
|
+
},
|
|
2097
|
+
children: "\uC120\uD0DD\uD558\uC138\uC694"
|
|
2098
|
+
}
|
|
2099
|
+
),
|
|
2100
|
+
choices.map((choice, index) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2101
|
+
"button",
|
|
2102
|
+
{
|
|
2103
|
+
onClick: () => onChoiceClick?.(choice),
|
|
2104
|
+
onMouseEnter: () => setHoveredIndex(index),
|
|
2105
|
+
onMouseLeave: () => setHoveredIndex(null),
|
|
2106
|
+
style: {
|
|
2107
|
+
display: "flex",
|
|
2108
|
+
alignItems: "center",
|
|
2109
|
+
gap: "12px",
|
|
2110
|
+
padding: "12px 16px",
|
|
2111
|
+
backgroundColor: hoveredIndex === index ? "var(--chatllm-primary-light, #dbeafe)" : "var(--chatllm-bg, #ffffff)",
|
|
2112
|
+
border: "1px solid var(--chatllm-border, #e5e7eb)",
|
|
2113
|
+
borderRadius: "8px",
|
|
2114
|
+
cursor: "pointer",
|
|
2115
|
+
textAlign: "left",
|
|
2116
|
+
transition: "all 0.2s ease",
|
|
2117
|
+
transform: hoveredIndex === index ? "translateX(4px)" : "translateX(0)"
|
|
2118
|
+
},
|
|
2119
|
+
children: [
|
|
2120
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2121
|
+
"span",
|
|
2122
|
+
{
|
|
2123
|
+
style: {
|
|
2124
|
+
display: "flex",
|
|
2125
|
+
alignItems: "center",
|
|
2126
|
+
justifyContent: "center",
|
|
2127
|
+
width: "28px",
|
|
2128
|
+
height: "28px",
|
|
2129
|
+
borderRadius: "50%",
|
|
2130
|
+
backgroundColor: hoveredIndex === index ? "var(--chatllm-primary, #3b82f6)" : "var(--chatllm-bg-tertiary, #f3f4f6)",
|
|
2131
|
+
color: hoveredIndex === index ? "#ffffff" : "var(--chatllm-text, #374151)",
|
|
2132
|
+
fontSize: "14px",
|
|
2133
|
+
fontWeight: 600,
|
|
2134
|
+
flexShrink: 0,
|
|
2135
|
+
transition: "all 0.2s ease"
|
|
2136
|
+
},
|
|
2137
|
+
children: choice.number
|
|
2138
|
+
}
|
|
2139
|
+
),
|
|
2140
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2141
|
+
"span",
|
|
2142
|
+
{
|
|
2143
|
+
style: {
|
|
2144
|
+
fontSize: "14px",
|
|
2145
|
+
color: "var(--chatllm-text, #374151)",
|
|
2146
|
+
lineHeight: "1.5"
|
|
2147
|
+
},
|
|
2148
|
+
children: choice.text
|
|
2149
|
+
}
|
|
2150
|
+
)
|
|
2151
|
+
]
|
|
2152
|
+
},
|
|
2153
|
+
choice.number
|
|
2154
|
+
))
|
|
2155
|
+
]
|
|
2156
|
+
}
|
|
2157
|
+
);
|
|
2158
|
+
};
|
|
2045
2159
|
var SourceLinksSection = ({ links, label }) => {
|
|
2046
2160
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2047
2161
|
"div",
|
|
@@ -2075,7 +2189,7 @@ var SourceLinksSection = ({ links, label }) => {
|
|
|
2075
2189
|
}
|
|
2076
2190
|
);
|
|
2077
2191
|
};
|
|
2078
|
-
var MarkdownRenderer = ({ content, className }) => {
|
|
2192
|
+
var MarkdownRenderer = ({ content, className, onChoiceClick }) => {
|
|
2079
2193
|
const rendered = (0, import_react5.useMemo)(() => {
|
|
2080
2194
|
const elements = [];
|
|
2081
2195
|
let processedContent = content;
|
|
@@ -2097,6 +2211,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2097
2211
|
let currentList = null;
|
|
2098
2212
|
let blockquoteLines = [];
|
|
2099
2213
|
let tableLines = [];
|
|
2214
|
+
let choiceItems = [];
|
|
2100
2215
|
const flushTable = () => {
|
|
2101
2216
|
if (tableLines.length >= 2) {
|
|
2102
2217
|
const headerLine = tableLines[0];
|
|
@@ -2125,6 +2240,24 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2125
2240
|
}
|
|
2126
2241
|
tableLines = [];
|
|
2127
2242
|
};
|
|
2243
|
+
const flushChoices = () => {
|
|
2244
|
+
if (choiceItems.length >= 2 && onChoiceClick) {
|
|
2245
|
+
elements.push(
|
|
2246
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2247
|
+
ChoiceButtons,
|
|
2248
|
+
{
|
|
2249
|
+
choices: choiceItems,
|
|
2250
|
+
onChoiceClick
|
|
2251
|
+
},
|
|
2252
|
+
`choices-${elements.length}`
|
|
2253
|
+
)
|
|
2254
|
+
);
|
|
2255
|
+
choiceItems = [];
|
|
2256
|
+
return true;
|
|
2257
|
+
}
|
|
2258
|
+
choiceItems = [];
|
|
2259
|
+
return false;
|
|
2260
|
+
};
|
|
2128
2261
|
const flushList = () => {
|
|
2129
2262
|
if (currentList) {
|
|
2130
2263
|
if (currentList.type === "ul") {
|
|
@@ -2132,9 +2265,11 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2132
2265
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ul-${elements.length}`)
|
|
2133
2266
|
);
|
|
2134
2267
|
} else {
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2268
|
+
if (!flushChoices()) {
|
|
2269
|
+
elements.push(
|
|
2270
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ol", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ol-${elements.length}`)
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2138
2273
|
}
|
|
2139
2274
|
currentList = null;
|
|
2140
2275
|
}
|
|
@@ -2263,15 +2398,24 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2263
2398
|
);
|
|
2264
2399
|
return;
|
|
2265
2400
|
}
|
|
2266
|
-
const olMatch = line.match(/^(\d+)
|
|
2401
|
+
const olMatch = line.match(/^(\d+)[.)]\s+(.+)$/);
|
|
2267
2402
|
if (olMatch) {
|
|
2268
2403
|
flushBlockquote();
|
|
2269
2404
|
if (!currentList || currentList.type !== "ol") {
|
|
2270
2405
|
flushList();
|
|
2271
2406
|
currentList = { type: "ol", items: [] };
|
|
2272
2407
|
}
|
|
2408
|
+
const itemNumber = parseInt(olMatch[1]);
|
|
2409
|
+
const itemText = olMatch[2];
|
|
2410
|
+
if (itemText.length <= 100) {
|
|
2411
|
+
choiceItems.push({
|
|
2412
|
+
number: itemNumber,
|
|
2413
|
+
text: itemText,
|
|
2414
|
+
fullText: line
|
|
2415
|
+
});
|
|
2416
|
+
}
|
|
2273
2417
|
currentList.items.push(
|
|
2274
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { style: { margin: "4px 0" }, children: parseInlineElements(
|
|
2418
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("li", { style: { margin: "4px 0" }, children: parseInlineElements(itemText, `li-${lineIndex}`) }, `li-${lineIndex}`)
|
|
2275
2419
|
);
|
|
2276
2420
|
return;
|
|
2277
2421
|
}
|
|
@@ -2288,7 +2432,7 @@ var MarkdownRenderer = ({ content, className }) => {
|
|
|
2288
2432
|
flushBlockquote();
|
|
2289
2433
|
flushTable();
|
|
2290
2434
|
return elements;
|
|
2291
|
-
}, [content]);
|
|
2435
|
+
}, [content, onChoiceClick]);
|
|
2292
2436
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2293
2437
|
"div",
|
|
2294
2438
|
{
|
|
@@ -2319,7 +2463,8 @@ var MessageBubble = ({
|
|
|
2319
2463
|
alternatives,
|
|
2320
2464
|
activeAlternativeIndex = 0,
|
|
2321
2465
|
onAlternativeChange,
|
|
2322
|
-
nextAssistantMessage
|
|
2466
|
+
nextAssistantMessage,
|
|
2467
|
+
onChoiceClick
|
|
2323
2468
|
}) => {
|
|
2324
2469
|
const [showActions, setShowActions] = (0, import_react6.useState)(false);
|
|
2325
2470
|
const [showModelMenu, setShowModelMenu] = (0, import_react6.useState)(false);
|
|
@@ -2423,7 +2568,7 @@ var MessageBubble = ({
|
|
|
2423
2568
|
children: [
|
|
2424
2569
|
isAssistant ? (
|
|
2425
2570
|
// AI 메시지는 마크다운 렌더링
|
|
2426
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: displayContent })
|
|
2571
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MarkdownRenderer, { content: displayContent, onChoiceClick })
|
|
2427
2572
|
) : (
|
|
2428
2573
|
// 사용자 메시지는 일반 텍스트
|
|
2429
2574
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
@@ -2712,7 +2857,8 @@ var MessageList = ({
|
|
|
2712
2857
|
activeAlternatives = {},
|
|
2713
2858
|
models,
|
|
2714
2859
|
copiedId,
|
|
2715
|
-
editingId
|
|
2860
|
+
editingId,
|
|
2861
|
+
onChoiceClick
|
|
2716
2862
|
}) => {
|
|
2717
2863
|
const messagesEndRef = (0, import_react7.useRef)(null);
|
|
2718
2864
|
const containerRef = (0, import_react7.useRef)(null);
|
|
@@ -2784,7 +2930,8 @@ var MessageList = ({
|
|
|
2784
2930
|
onAskOtherModel: message.role === "user" && assistantForAlts && onAskOtherModel ? (targetModel) => onAskOtherModel(message.id, assistantForAlts.id, targetModel) : void 0,
|
|
2785
2931
|
onAlternativeChange: message.role === "user" && assistantForAlts && onSetActiveAlternative ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx) : message.role === "assistant" && onSetActiveAlternative ? (idx) => onSetActiveAlternative(message.id, idx) : void 0,
|
|
2786
2932
|
models,
|
|
2787
|
-
alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives
|
|
2933
|
+
alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives,
|
|
2934
|
+
onChoiceClick: message.role === "assistant" ? onChoiceClick : void 0
|
|
2788
2935
|
},
|
|
2789
2936
|
message.id
|
|
2790
2937
|
);
|
|
@@ -4036,6 +4183,18 @@ var injectStyles = () => {
|
|
|
4036
4183
|
.chatllm-table tr:hover {
|
|
4037
4184
|
background-color: var(--chatllm-bg-hover, #f3f4f6);
|
|
4038
4185
|
}
|
|
4186
|
+
|
|
4187
|
+
.chatllm-image {
|
|
4188
|
+
max-width: 100%;
|
|
4189
|
+
border-radius: 8px;
|
|
4190
|
+
margin: 8px 0;
|
|
4191
|
+
display: block;
|
|
4192
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
4193
|
+
}
|
|
4194
|
+
|
|
4195
|
+
.chatllm-image:hover {
|
|
4196
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
4197
|
+
}
|
|
4039
4198
|
`;
|
|
4040
4199
|
document.head.appendChild(style);
|
|
4041
4200
|
};
|
|
@@ -4125,6 +4284,9 @@ var ChatUI = ({
|
|
|
4125
4284
|
const handleSubmit = () => {
|
|
4126
4285
|
sendMessage();
|
|
4127
4286
|
};
|
|
4287
|
+
const handleChoiceClick = (choice) => {
|
|
4288
|
+
setInput(choice.text);
|
|
4289
|
+
};
|
|
4128
4290
|
const [memoryPanelOpen, setMemoryPanelOpen] = (0, import_react10.useState)(false);
|
|
4129
4291
|
const memoryItems = import_react10.default.useMemo(() => {
|
|
4130
4292
|
const items = [];
|
|
@@ -4236,7 +4398,8 @@ var ChatUI = ({
|
|
|
4236
4398
|
activeAlternatives,
|
|
4237
4399
|
models: hookModels,
|
|
4238
4400
|
copiedId: copiedMessageId,
|
|
4239
|
-
editingId: editingMessageId
|
|
4401
|
+
editingId: editingMessageId,
|
|
4402
|
+
onChoiceClick: handleChoiceClick
|
|
4240
4403
|
}
|
|
4241
4404
|
),
|
|
4242
4405
|
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|