@gendive/chatllm 0.6.3 → 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.
@@ -1772,7 +1772,7 @@ var LinkChip = ({
1772
1772
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1773
1773
  var IMAGE_REGEX = /!\[([^\]]*)\]\(([^)]+)\)/g;
1774
1774
  var LINK_REGEX = /(?<!!)\[([^\]]+)\]\(([^)]+)\)/g;
1775
- var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((?:\[`?[^\]]+`?\]\([^)]+\)\s*)+)/gi;
1775
+ var SOURCE_LINKS_REGEX = /(\*{0,2}출처:?\*{0,2}\s*)?((?:(?<!!)\[`?[^\]]+`?\]\([^)]+\)\s*)+)/gi;
1776
1776
  var CODE_BLOCK_REGEX = /```(\w*)\n?([\s\S]*?)```/g;
1777
1777
  var INLINE_CODE_REGEX = /`([^`]+)`/g;
1778
1778
  var BOLD_REGEX = /\*\*([^*]+)\*\*/g;
@@ -2017,6 +2017,96 @@ var CodeBlock = ({ language, code }) => {
2017
2017
  }
2018
2018
  );
2019
2019
  };
2020
+ var ChoiceButtons = ({ choices, onChoiceClick }) => {
2021
+ const [hoveredIndex, setHoveredIndex] = React4.useState(null);
2022
+ return /* @__PURE__ */ jsxs5(
2023
+ "div",
2024
+ {
2025
+ className: "chatllm-choices",
2026
+ style: {
2027
+ display: "flex",
2028
+ flexDirection: "column",
2029
+ gap: "8px",
2030
+ margin: "16px 0",
2031
+ padding: "12px",
2032
+ backgroundColor: "var(--chatllm-bg-secondary, #f9fafb)",
2033
+ borderRadius: "12px",
2034
+ border: "1px solid var(--chatllm-border-light, #e5e7eb)"
2035
+ },
2036
+ children: [
2037
+ /* @__PURE__ */ jsx6(
2038
+ "div",
2039
+ {
2040
+ style: {
2041
+ fontSize: "12px",
2042
+ fontWeight: 600,
2043
+ color: "var(--chatllm-text-muted, #6b7280)",
2044
+ marginBottom: "4px",
2045
+ textTransform: "uppercase",
2046
+ letterSpacing: "0.5px"
2047
+ },
2048
+ children: "\uC120\uD0DD\uD558\uC138\uC694"
2049
+ }
2050
+ ),
2051
+ choices.map((choice, index) => /* @__PURE__ */ jsxs5(
2052
+ "button",
2053
+ {
2054
+ onClick: () => onChoiceClick?.(choice),
2055
+ onMouseEnter: () => setHoveredIndex(index),
2056
+ onMouseLeave: () => setHoveredIndex(null),
2057
+ style: {
2058
+ display: "flex",
2059
+ alignItems: "center",
2060
+ gap: "12px",
2061
+ padding: "12px 16px",
2062
+ backgroundColor: hoveredIndex === index ? "var(--chatllm-primary-light, #dbeafe)" : "var(--chatllm-bg, #ffffff)",
2063
+ border: "1px solid var(--chatllm-border, #e5e7eb)",
2064
+ borderRadius: "8px",
2065
+ cursor: "pointer",
2066
+ textAlign: "left",
2067
+ transition: "all 0.2s ease",
2068
+ transform: hoveredIndex === index ? "translateX(4px)" : "translateX(0)"
2069
+ },
2070
+ children: [
2071
+ /* @__PURE__ */ jsx6(
2072
+ "span",
2073
+ {
2074
+ style: {
2075
+ display: "flex",
2076
+ alignItems: "center",
2077
+ justifyContent: "center",
2078
+ width: "28px",
2079
+ height: "28px",
2080
+ borderRadius: "50%",
2081
+ backgroundColor: hoveredIndex === index ? "var(--chatllm-primary, #3b82f6)" : "var(--chatllm-bg-tertiary, #f3f4f6)",
2082
+ color: hoveredIndex === index ? "#ffffff" : "var(--chatllm-text, #374151)",
2083
+ fontSize: "14px",
2084
+ fontWeight: 600,
2085
+ flexShrink: 0,
2086
+ transition: "all 0.2s ease"
2087
+ },
2088
+ children: choice.number
2089
+ }
2090
+ ),
2091
+ /* @__PURE__ */ jsx6(
2092
+ "span",
2093
+ {
2094
+ style: {
2095
+ fontSize: "14px",
2096
+ color: "var(--chatllm-text, #374151)",
2097
+ lineHeight: "1.5"
2098
+ },
2099
+ children: choice.text
2100
+ }
2101
+ )
2102
+ ]
2103
+ },
2104
+ choice.number
2105
+ ))
2106
+ ]
2107
+ }
2108
+ );
2109
+ };
2020
2110
  var SourceLinksSection = ({ links, label }) => {
2021
2111
  return /* @__PURE__ */ jsxs5(
2022
2112
  "div",
@@ -2050,7 +2140,7 @@ var SourceLinksSection = ({ links, label }) => {
2050
2140
  }
2051
2141
  );
2052
2142
  };
2053
- var MarkdownRenderer = ({ content, className }) => {
2143
+ var MarkdownRenderer = ({ content, className, onChoiceClick }) => {
2054
2144
  const rendered = useMemo(() => {
2055
2145
  const elements = [];
2056
2146
  let processedContent = content;
@@ -2072,6 +2162,7 @@ var MarkdownRenderer = ({ content, className }) => {
2072
2162
  let currentList = null;
2073
2163
  let blockquoteLines = [];
2074
2164
  let tableLines = [];
2165
+ let choiceItems = [];
2075
2166
  const flushTable = () => {
2076
2167
  if (tableLines.length >= 2) {
2077
2168
  const headerLine = tableLines[0];
@@ -2100,6 +2191,24 @@ var MarkdownRenderer = ({ content, className }) => {
2100
2191
  }
2101
2192
  tableLines = [];
2102
2193
  };
2194
+ const flushChoices = () => {
2195
+ if (choiceItems.length >= 2 && onChoiceClick) {
2196
+ elements.push(
2197
+ /* @__PURE__ */ jsx6(
2198
+ ChoiceButtons,
2199
+ {
2200
+ choices: choiceItems,
2201
+ onChoiceClick
2202
+ },
2203
+ `choices-${elements.length}`
2204
+ )
2205
+ );
2206
+ choiceItems = [];
2207
+ return true;
2208
+ }
2209
+ choiceItems = [];
2210
+ return false;
2211
+ };
2103
2212
  const flushList = () => {
2104
2213
  if (currentList) {
2105
2214
  if (currentList.type === "ul") {
@@ -2107,9 +2216,11 @@ var MarkdownRenderer = ({ content, className }) => {
2107
2216
  /* @__PURE__ */ jsx6("ul", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ul-${elements.length}`)
2108
2217
  );
2109
2218
  } else {
2110
- elements.push(
2111
- /* @__PURE__ */ jsx6("ol", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ol-${elements.length}`)
2112
- );
2219
+ if (!flushChoices()) {
2220
+ elements.push(
2221
+ /* @__PURE__ */ jsx6("ol", { style: { margin: "8px 0", paddingLeft: "24px" }, children: currentList.items }, `ol-${elements.length}`)
2222
+ );
2223
+ }
2113
2224
  }
2114
2225
  currentList = null;
2115
2226
  }
@@ -2238,15 +2349,24 @@ var MarkdownRenderer = ({ content, className }) => {
2238
2349
  );
2239
2350
  return;
2240
2351
  }
2241
- const olMatch = line.match(/^(\d+)\.\s+(.+)$/);
2352
+ const olMatch = line.match(/^(\d+)[.)]\s+(.+)$/);
2242
2353
  if (olMatch) {
2243
2354
  flushBlockquote();
2244
2355
  if (!currentList || currentList.type !== "ol") {
2245
2356
  flushList();
2246
2357
  currentList = { type: "ol", items: [] };
2247
2358
  }
2359
+ const itemNumber = parseInt(olMatch[1]);
2360
+ const itemText = olMatch[2];
2361
+ if (itemText.length <= 100) {
2362
+ choiceItems.push({
2363
+ number: itemNumber,
2364
+ text: itemText,
2365
+ fullText: line
2366
+ });
2367
+ }
2248
2368
  currentList.items.push(
2249
- /* @__PURE__ */ jsx6("li", { style: { margin: "4px 0" }, children: parseInlineElements(olMatch[2], `li-${lineIndex}`) }, `li-${lineIndex}`)
2369
+ /* @__PURE__ */ jsx6("li", { style: { margin: "4px 0" }, children: parseInlineElements(itemText, `li-${lineIndex}`) }, `li-${lineIndex}`)
2250
2370
  );
2251
2371
  return;
2252
2372
  }
@@ -2263,7 +2383,7 @@ var MarkdownRenderer = ({ content, className }) => {
2263
2383
  flushBlockquote();
2264
2384
  flushTable();
2265
2385
  return elements;
2266
- }, [content]);
2386
+ }, [content, onChoiceClick]);
2267
2387
  return /* @__PURE__ */ jsx6(
2268
2388
  "div",
2269
2389
  {
@@ -2294,7 +2414,8 @@ var MessageBubble = ({
2294
2414
  alternatives,
2295
2415
  activeAlternativeIndex = 0,
2296
2416
  onAlternativeChange,
2297
- nextAssistantMessage
2417
+ nextAssistantMessage,
2418
+ onChoiceClick
2298
2419
  }) => {
2299
2420
  const [showActions, setShowActions] = useState5(false);
2300
2421
  const [showModelMenu, setShowModelMenu] = useState5(false);
@@ -2398,7 +2519,7 @@ var MessageBubble = ({
2398
2519
  children: [
2399
2520
  isAssistant ? (
2400
2521
  // AI 메시지는 마크다운 렌더링
2401
- /* @__PURE__ */ jsx7(MarkdownRenderer, { content: displayContent })
2522
+ /* @__PURE__ */ jsx7(MarkdownRenderer, { content: displayContent, onChoiceClick })
2402
2523
  ) : (
2403
2524
  // 사용자 메시지는 일반 텍스트
2404
2525
  /* @__PURE__ */ jsx7(
@@ -2687,7 +2808,8 @@ var MessageList = ({
2687
2808
  activeAlternatives = {},
2688
2809
  models,
2689
2810
  copiedId,
2690
- editingId
2811
+ editingId,
2812
+ onChoiceClick
2691
2813
  }) => {
2692
2814
  const messagesEndRef = useRef3(null);
2693
2815
  const containerRef = useRef3(null);
@@ -2759,7 +2881,8 @@ var MessageList = ({
2759
2881
  onAskOtherModel: message.role === "user" && assistantForAlts && onAskOtherModel ? (targetModel) => onAskOtherModel(message.id, assistantForAlts.id, targetModel) : void 0,
2760
2882
  onAlternativeChange: message.role === "user" && assistantForAlts && onSetActiveAlternative ? (idx) => onSetActiveAlternative(assistantForAlts.id, idx) : message.role === "assistant" && onSetActiveAlternative ? (idx) => onSetActiveAlternative(message.id, idx) : void 0,
2761
2883
  models,
2762
- alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives
2884
+ alternatives: message.role === "assistant" ? message.alternatives : assistantForAlts?.alternatives,
2885
+ onChoiceClick: message.role === "assistant" ? onChoiceClick : void 0
2763
2886
  },
2764
2887
  message.id
2765
2888
  );
@@ -4112,6 +4235,9 @@ var ChatUI = ({
4112
4235
  const handleSubmit = () => {
4113
4236
  sendMessage();
4114
4237
  };
4238
+ const handleChoiceClick = (choice) => {
4239
+ setInput(choice.text);
4240
+ };
4115
4241
  const [memoryPanelOpen, setMemoryPanelOpen] = useState9(false);
4116
4242
  const memoryItems = React9.useMemo(() => {
4117
4243
  const items = [];
@@ -4223,7 +4349,8 @@ var ChatUI = ({
4223
4349
  activeAlternatives,
4224
4350
  models: hookModels,
4225
4351
  copiedId: copiedMessageId,
4226
- editingId: editingMessageId
4352
+ editingId: editingMessageId,
4353
+ onChoiceClick: handleChoiceClick
4227
4354
  }
4228
4355
  ),
4229
4356
  /* @__PURE__ */ jsx12(