@xbrain-swe/nova-chat-widget 0.1.9 β 0.1.10
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/index.cjs +229 -69
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +229 -69
- package/dist/index.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -116,11 +116,15 @@ type ClientResults = Record<string, {
|
|
|
116
116
|
output: unknown;
|
|
117
117
|
}>;
|
|
118
118
|
type XbNovaFeedbackRating = "up" | "down" | null;
|
|
119
|
+
/** π μ¬μ μΉ©μ μ½λ. */
|
|
120
|
+
type XbNovaFeedbackReason = "inaccurate" | "irrelevant" | "too_long" | "unclear";
|
|
119
121
|
/** λ΅λ³ λ§μ‘±λ μ μ₯ μ±κ³΅ ν νΈμ€νΈλ‘ μ λ¬λλ μ΄λ²€νΈ. `rating: null`μ νκ° μ·¨μ. */
|
|
120
122
|
type XbNovaFeedbackEvent = {
|
|
121
123
|
conversationId: string;
|
|
122
124
|
messageId: string;
|
|
123
125
|
rating: XbNovaFeedbackRating;
|
|
126
|
+
/** πμΌ λ μ¬μ©μκ° κ³ λ₯Έ μ¬μ μ½λ(μμΌλ©΄ undefined). */
|
|
127
|
+
reason?: XbNovaFeedbackReason;
|
|
124
128
|
};
|
|
125
129
|
type XbNovaOnboarding = {
|
|
126
130
|
conversation_id: string;
|
|
@@ -143,7 +147,7 @@ type UseXbNovaChatResult = {
|
|
|
143
147
|
/** messageId β νμ¬ νκ°. νκ° μ ν λ©μμ§λ ν€κ° μλ€. */
|
|
144
148
|
feedback: Record<string, XbNovaFeedbackRating>;
|
|
145
149
|
/** λκ΄μ μΌλ‘ λ°μνκ³ μλ²μ μ μ₯νλ€. μ€ν¨νλ©΄ λλλ¦°λ€. */
|
|
146
|
-
setFeedback: (messageId: string, rating: XbNovaFeedbackRating) => Promise<void>;
|
|
150
|
+
setFeedback: (messageId: string, rating: XbNovaFeedbackRating, reason?: XbNovaFeedbackReason) => Promise<void>;
|
|
147
151
|
};
|
|
148
152
|
/** `botId`λ₯Ό λκΈ°λ©΄ Providerμ κΈ°λ³Έ λ΄ λμ κ·Έ λ΄μΌλ‘ μ λνλ₯Ό μ°λ€ β λμ§ handoffκ° μ΄λ€.
|
|
149
153
|
* `nudgeNodeId`λ₯Ό λκΈ°λ©΄ μ΄ λνκ° κ·Έ λμ§μμ μμλλ€κ³ μλ²μ νμνλ€ β λμ§ μ ν
|
|
@@ -270,4 +274,4 @@ declare function useXbNovaSettings(): {
|
|
|
270
274
|
showBar: () => void;
|
|
271
275
|
};
|
|
272
276
|
|
|
273
|
-
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
|
277
|
+
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaFeedbackReason, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
package/dist/index.d.ts
CHANGED
|
@@ -116,11 +116,15 @@ type ClientResults = Record<string, {
|
|
|
116
116
|
output: unknown;
|
|
117
117
|
}>;
|
|
118
118
|
type XbNovaFeedbackRating = "up" | "down" | null;
|
|
119
|
+
/** π μ¬μ μΉ©μ μ½λ. */
|
|
120
|
+
type XbNovaFeedbackReason = "inaccurate" | "irrelevant" | "too_long" | "unclear";
|
|
119
121
|
/** λ΅λ³ λ§μ‘±λ μ μ₯ μ±κ³΅ ν νΈμ€νΈλ‘ μ λ¬λλ μ΄λ²€νΈ. `rating: null`μ νκ° μ·¨μ. */
|
|
120
122
|
type XbNovaFeedbackEvent = {
|
|
121
123
|
conversationId: string;
|
|
122
124
|
messageId: string;
|
|
123
125
|
rating: XbNovaFeedbackRating;
|
|
126
|
+
/** πμΌ λ μ¬μ©μκ° κ³ λ₯Έ μ¬μ μ½λ(μμΌλ©΄ undefined). */
|
|
127
|
+
reason?: XbNovaFeedbackReason;
|
|
124
128
|
};
|
|
125
129
|
type XbNovaOnboarding = {
|
|
126
130
|
conversation_id: string;
|
|
@@ -143,7 +147,7 @@ type UseXbNovaChatResult = {
|
|
|
143
147
|
/** messageId β νμ¬ νκ°. νκ° μ ν λ©μμ§λ ν€κ° μλ€. */
|
|
144
148
|
feedback: Record<string, XbNovaFeedbackRating>;
|
|
145
149
|
/** λκ΄μ μΌλ‘ λ°μνκ³ μλ²μ μ μ₯νλ€. μ€ν¨νλ©΄ λλλ¦°λ€. */
|
|
146
|
-
setFeedback: (messageId: string, rating: XbNovaFeedbackRating) => Promise<void>;
|
|
150
|
+
setFeedback: (messageId: string, rating: XbNovaFeedbackRating, reason?: XbNovaFeedbackReason) => Promise<void>;
|
|
147
151
|
};
|
|
148
152
|
/** `botId`λ₯Ό λκΈ°λ©΄ Providerμ κΈ°λ³Έ λ΄ λμ κ·Έ λ΄μΌλ‘ μ λνλ₯Ό μ°λ€ β λμ§ handoffκ° μ΄λ€.
|
|
149
153
|
* `nudgeNodeId`λ₯Ό λκΈ°λ©΄ μ΄ λνκ° κ·Έ λμ§μμ μμλλ€κ³ μλ²μ νμνλ€ β λμ§ μ ν
|
|
@@ -270,4 +274,4 @@ declare function useXbNovaSettings(): {
|
|
|
270
274
|
showBar: () => void;
|
|
271
275
|
};
|
|
272
276
|
|
|
273
|
-
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
|
277
|
+
export { type ChatMessage, type FactValue, type MessagePart, type ProductItem, type TextPart, type ToolPart, type UseXbNovaChatResult, type VerdictAction, type VerdictOutput, type ViewKind, type ViewRenderer, type ViewRendererMap, XbNovaChat, type XbNovaClientAction, type XbNovaClientActionResult, type XbNovaClientActions, XbNovaFact, XbNovaFacts, type XbNovaFeedbackEvent, type XbNovaFeedbackRating, type XbNovaFeedbackReason, type XbNovaOnboarding, XbNovaProvider, type XbNovaTheme, XbNovaTrack, trackXbNovaEvent, useXbNovaChat, useXbNovaFact, useXbNovaFacts, useXbNovaSettings, useXbNovaTrack, useXbNovaVisitor };
|
package/dist/index.js
CHANGED
|
@@ -1128,7 +1128,7 @@ function useXbNovaChat(options) {
|
|
|
1128
1128
|
next[next.length - 1] = { ...next[next.length - 1], id };
|
|
1129
1129
|
return next;
|
|
1130
1130
|
});
|
|
1131
|
-
async function setFeedback(messageId, rating) {
|
|
1131
|
+
async function setFeedback(messageId, rating, reason) {
|
|
1132
1132
|
const conversationId = onboarding?.conversation_id;
|
|
1133
1133
|
if (!conversationId || !messageId) return;
|
|
1134
1134
|
const prevRating = feedbackRef.current[messageId] ?? null;
|
|
@@ -1145,11 +1145,11 @@ function useXbNovaChat(options) {
|
|
|
1145
1145
|
{
|
|
1146
1146
|
method: "PUT",
|
|
1147
1147
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
|
|
1148
|
-
body: JSON.stringify({ rating, visitor_id: visitorId })
|
|
1148
|
+
body: JSON.stringify({ rating, visitor_id: visitorId, reason: rating === "down" ? reason ?? null : null })
|
|
1149
1149
|
}
|
|
1150
1150
|
);
|
|
1151
1151
|
if (!res.ok) throw new Error(`${res.status}`);
|
|
1152
|
-
options?.onFeedback?.({ conversationId, messageId, rating });
|
|
1152
|
+
options?.onFeedback?.({ conversationId, messageId, rating, reason });
|
|
1153
1153
|
} catch (e) {
|
|
1154
1154
|
console.warn("[xbnova] \uD53C\uB4DC\uBC31 \uC800\uC7A5 \uC2E4\uD328", e);
|
|
1155
1155
|
apply(prevRating);
|
|
@@ -1776,38 +1776,41 @@ function XbNovaChat({
|
|
|
1776
1776
|
/* @__PURE__ */ jsxs3("div", { className: "flex-1 space-y-3 overflow-y-auto p-4", children: [
|
|
1777
1777
|
showDisclosure ? /* @__PURE__ */ jsx7("div", { className: "rounded-lg bg-neutral-50 px-3 py-2 text-[11px] text-neutral-400 dark:bg-neutral-800", children: "\uC9C0\uAE08 \uBCF4\uACE0 \uACC4\uC2E0 \uD654\uBA74\uACFC \uB9E4\uBB3C \uC815\uBCF4\uB97C \uAE30\uC900\uC73C\uB85C \uC548\uB0B4\uD574 \uB4DC\uB824\uC694." }) : null,
|
|
1778
1778
|
firstBubble ? /* @__PURE__ */ jsx7(Bubble, { role: "assistant", children: /* @__PURE__ */ jsx7(AssistantMarkdown, { text: firstBubble }) }) : null,
|
|
1779
|
-
messages.map((message, i) => /* @__PURE__ */ jsx7("div", { children: message.role === "user" ? /* @__PURE__ */ jsx7(Bubble, { role: "user", children: message.parts.map((p) => p.kind === "text" ? p.text : "").join("") }) : /* @__PURE__ */ jsxs3(
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1779
|
+
messages.map((message, i) => /* @__PURE__ */ jsx7("div", { children: message.role === "user" ? /* @__PURE__ */ jsx7(Bubble, { role: "user", children: message.parts.map((p) => p.kind === "text" ? p.text : "").join("") }) : /* @__PURE__ */ jsxs3(
|
|
1780
|
+
AnswerActionsFrame,
|
|
1781
|
+
{
|
|
1782
|
+
enabled: feedbackEnabled && !busy && !!message.id && message.parts.some((p) => p.kind === "text" && p.text.trim()),
|
|
1783
|
+
text: message.parts.filter((p) => p.kind === "text").map((p) => p.kind === "text" ? p.text : "").join("\n\n"),
|
|
1784
|
+
rating: message.id ? feedback[message.id] ?? null : null,
|
|
1785
|
+
isLast: i === messages.length - 1,
|
|
1786
|
+
onRate: (r, reason) => void setFeedback(message.id, r, reason),
|
|
1787
|
+
children: [
|
|
1788
|
+
message.parts.map((part, j) => {
|
|
1789
|
+
if (part.kind === "text") {
|
|
1790
|
+
return /* @__PURE__ */ jsx7(Bubble, { role: "assistant", children: /* @__PURE__ */ jsx7(AssistantMarkdown, { text: part.text }) }, j);
|
|
1791
|
+
}
|
|
1792
|
+
if (clientActionHandlers.has(part.toolName)) {
|
|
1793
|
+
const result = clientResults[part.toolCallId];
|
|
1794
|
+
if (result) {
|
|
1795
|
+
return /* @__PURE__ */ jsx7(
|
|
1796
|
+
ToolView,
|
|
1797
|
+
{
|
|
1798
|
+
part: { ...part, state: "output", view: result.view, output: result.output },
|
|
1799
|
+
viewRenderers,
|
|
1800
|
+
onVerdictAction
|
|
1801
|
+
},
|
|
1802
|
+
j
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
const spec = clientActionHandlers.get(part.toolName);
|
|
1806
|
+
return spec?.render ? /* @__PURE__ */ jsx7("div", { children: spec.render(part.input) }, j) : null;
|
|
1807
|
+
}
|
|
1808
|
+
return /* @__PURE__ */ jsx7(ToolView, { part, viewRenderers, onVerdictAction }, j);
|
|
1809
|
+
}),
|
|
1810
|
+
!hasVisiblePart(message.parts, clientActionHandlers, clientResults) && busy ? /* @__PURE__ */ jsx7(Bubble, { role: "assistant", children: /* @__PURE__ */ jsx7("span", { className: "text-neutral-400", children: "\uC0DD\uAC01\uD558\uB294 \uC911\u2026" }) }) : null
|
|
1811
|
+
]
|
|
1812
|
+
}
|
|
1813
|
+
) }, i)),
|
|
1811
1814
|
error ? /* @__PURE__ */ jsx7("div", { className: "rounded-lg bg-red-50 px-3 py-2 text-xs text-red-700 dark:bg-red-950 dark:text-red-300", children: error }) : null,
|
|
1812
1815
|
/* @__PURE__ */ jsx7("div", { ref: bottomRef })
|
|
1813
1816
|
] }),
|
|
@@ -1910,44 +1913,193 @@ function Avatar({
|
|
|
1910
1913
|
}
|
|
1911
1914
|
var THUMB_UP_PATH = "M7 10v12M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z";
|
|
1912
1915
|
var THUMB_DOWN_PATH = "M17 14V2M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z";
|
|
1913
|
-
|
|
1916
|
+
var COPY_PATH = "M9 9h11v11H9zM5 15H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1";
|
|
1917
|
+
var CHECK_PATH = "m5 12 5 5L20 7";
|
|
1918
|
+
var FEEDBACK_REASONS = [
|
|
1919
|
+
{ code: "inaccurate", label: "\uC815\uD655\uD558\uC9C0 \uC54A\uC544\uC694" },
|
|
1920
|
+
{ code: "irrelevant", label: "\uC9C8\uBB38\uACFC \uB2EC\uB77C\uC694" },
|
|
1921
|
+
{ code: "too_long", label: "\uB108\uBB34 \uAE38\uC5B4\uC694" },
|
|
1922
|
+
{ code: "unclear", label: "\uC774\uD574\uD558\uAE30 \uC5B4\uB824\uC6CC\uC694" }
|
|
1923
|
+
];
|
|
1924
|
+
var LONG_PRESS_MS = 420;
|
|
1925
|
+
function ActionIcon({ path, filled }) {
|
|
1926
|
+
return /* @__PURE__ */ jsx7(
|
|
1927
|
+
"svg",
|
|
1928
|
+
{
|
|
1929
|
+
width: "16",
|
|
1930
|
+
height: "16",
|
|
1931
|
+
viewBox: "0 0 24 24",
|
|
1932
|
+
fill: filled ? "currentColor" : "none",
|
|
1933
|
+
stroke: "currentColor",
|
|
1934
|
+
strokeWidth: "2",
|
|
1935
|
+
strokeLinecap: "round",
|
|
1936
|
+
strokeLinejoin: "round",
|
|
1937
|
+
"aria-hidden": "true",
|
|
1938
|
+
children: /* @__PURE__ */ jsx7("path", { d: path })
|
|
1939
|
+
}
|
|
1940
|
+
);
|
|
1941
|
+
}
|
|
1942
|
+
async function copyText(text) {
|
|
1943
|
+
try {
|
|
1944
|
+
await navigator.clipboard.writeText(text);
|
|
1945
|
+
return true;
|
|
1946
|
+
} catch {
|
|
1947
|
+
try {
|
|
1948
|
+
const ta = document.createElement("textarea");
|
|
1949
|
+
ta.value = text;
|
|
1950
|
+
ta.style.position = "fixed";
|
|
1951
|
+
ta.style.opacity = "0";
|
|
1952
|
+
document.body.appendChild(ta);
|
|
1953
|
+
ta.select();
|
|
1954
|
+
const ok = document.execCommand("copy");
|
|
1955
|
+
ta.remove();
|
|
1956
|
+
return ok;
|
|
1957
|
+
} catch {
|
|
1958
|
+
return false;
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
function AnswerActions({
|
|
1963
|
+
text,
|
|
1914
1964
|
rating,
|
|
1915
|
-
|
|
1965
|
+
isLast,
|
|
1966
|
+
onRate,
|
|
1967
|
+
children
|
|
1916
1968
|
}) {
|
|
1917
|
-
const
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1969
|
+
const rootRef = useRef8(null);
|
|
1970
|
+
const timerRef = useRef8(null);
|
|
1971
|
+
const [menuOpen, setMenuOpen] = useState4(false);
|
|
1972
|
+
const [reasonOpen, setReasonOpen] = useState4(false);
|
|
1973
|
+
const [copied, setCopied] = useState4(false);
|
|
1974
|
+
const [entered, setEntered] = useState4(false);
|
|
1975
|
+
const clearTimer = () => {
|
|
1976
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
1977
|
+
timerRef.current = null;
|
|
1978
|
+
};
|
|
1979
|
+
useEffect8(() => clearTimer, []);
|
|
1980
|
+
useEffect8(() => {
|
|
1981
|
+
if (!menuOpen) {
|
|
1982
|
+
setEntered(false);
|
|
1983
|
+
return;
|
|
1984
|
+
}
|
|
1985
|
+
const raf = requestAnimationFrame(() => setEntered(true));
|
|
1986
|
+
const onDown = (e) => {
|
|
1987
|
+
if (!e.composedPath().includes(rootRef.current)) setMenuOpen(false);
|
|
1988
|
+
};
|
|
1989
|
+
document.addEventListener("pointerdown", onDown, true);
|
|
1990
|
+
return () => {
|
|
1991
|
+
cancelAnimationFrame(raf);
|
|
1992
|
+
document.removeEventListener("pointerdown", onDown, true);
|
|
1993
|
+
};
|
|
1994
|
+
}, [menuOpen]);
|
|
1995
|
+
const startPress = (e) => {
|
|
1996
|
+
if (e.pointerType === "mouse" || isLast) return;
|
|
1997
|
+
clearTimer();
|
|
1998
|
+
timerRef.current = setTimeout(() => {
|
|
1999
|
+
setMenuOpen(true);
|
|
2000
|
+
if (typeof navigator.vibrate === "function") navigator.vibrate(10);
|
|
2001
|
+
}, LONG_PRESS_MS);
|
|
2002
|
+
};
|
|
2003
|
+
const handleCopy = async () => {
|
|
2004
|
+
if (await copyText(text)) {
|
|
2005
|
+
setCopied(true);
|
|
2006
|
+
setTimeout(() => setCopied(false), 1400);
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
const handleRate = (kind) => {
|
|
2010
|
+
if (rating === kind) {
|
|
2011
|
+
onRate(null);
|
|
2012
|
+
setReasonOpen(false);
|
|
2013
|
+
return;
|
|
2014
|
+
}
|
|
2015
|
+
onRate(kind);
|
|
2016
|
+
setReasonOpen(kind === "down");
|
|
2017
|
+
if (kind === "up") setMenuOpen(false);
|
|
2018
|
+
};
|
|
2019
|
+
const barVisible = isLast || menuOpen;
|
|
2020
|
+
const floating = menuOpen && !isLast;
|
|
2021
|
+
const btn = (label, onClick, selected, color, icon) => /* @__PURE__ */ jsxs3(
|
|
2022
|
+
"button",
|
|
2023
|
+
{
|
|
2024
|
+
type: "button",
|
|
2025
|
+
"aria-label": label,
|
|
2026
|
+
"aria-pressed": selected,
|
|
2027
|
+
onClick,
|
|
2028
|
+
className: `flex items-center justify-center gap-1 rounded-full text-neutral-400 transition-colors hover:text-neutral-600 dark:text-neutral-500 dark:hover:text-neutral-300 ${floating ? "h-9 px-3 text-xs font-semibold" : "h-7 w-7"}`,
|
|
2029
|
+
style: color ? { color } : void 0,
|
|
2030
|
+
children: [
|
|
2031
|
+
icon,
|
|
2032
|
+
floating ? /* @__PURE__ */ jsx7("span", { children: label }) : null
|
|
2033
|
+
]
|
|
2034
|
+
}
|
|
2035
|
+
);
|
|
2036
|
+
return /* @__PURE__ */ jsxs3(
|
|
2037
|
+
"div",
|
|
2038
|
+
{
|
|
2039
|
+
ref: rootRef,
|
|
2040
|
+
className: "group space-y-1",
|
|
2041
|
+
onPointerDown: startPress,
|
|
2042
|
+
onPointerUp: clearTimer,
|
|
2043
|
+
onPointerCancel: clearTimer,
|
|
2044
|
+
onPointerLeave: clearTimer,
|
|
2045
|
+
onPointerMove: (e) => {
|
|
2046
|
+
if (Math.abs(e.movementX) + Math.abs(e.movementY) > 6) clearTimer();
|
|
2047
|
+
},
|
|
2048
|
+
onContextMenu: (e) => {
|
|
2049
|
+
if (!isLast && e.nativeEvent.pointerType !== "mouse") e.preventDefault();
|
|
2050
|
+
},
|
|
2051
|
+
children: [
|
|
2052
|
+
children,
|
|
2053
|
+
/* @__PURE__ */ jsx7(
|
|
2054
|
+
"div",
|
|
1931
2055
|
{
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2056
|
+
className: `flex pl-1 ${barVisible ? "" : "hidden md:group-hover:flex"}`,
|
|
2057
|
+
style: { transition: "opacity 140ms, transform 140ms", opacity: floating && !entered ? 0 : 1, transform: floating && !entered ? "scale(0.94)" : "none" },
|
|
2058
|
+
children: /* @__PURE__ */ jsxs3(
|
|
2059
|
+
"div",
|
|
2060
|
+
{
|
|
2061
|
+
className: `flex items-center ${floating ? "gap-0.5 rounded-full border border-neutral-200 bg-white p-1 shadow-lg dark:border-neutral-700 dark:bg-neutral-800" : "gap-0.5"}`,
|
|
2062
|
+
children: [
|
|
2063
|
+
btn(copied ? "\uBCF5\uC0AC\uB428" : "\uBCF5\uC0AC", handleCopy, false, copied ? "var(--xbnova-accent-1, #4f46e5)" : void 0, /* @__PURE__ */ jsx7(ActionIcon, { path: copied ? CHECK_PATH : COPY_PATH })),
|
|
2064
|
+
btn(
|
|
2065
|
+
"\uC88B\uC544\uC694",
|
|
2066
|
+
() => handleRate("up"),
|
|
2067
|
+
rating === "up",
|
|
2068
|
+
rating === "up" ? "var(--xbnova-accent-1, #4f46e5)" : void 0,
|
|
2069
|
+
/* @__PURE__ */ jsx7(ActionIcon, { path: THUMB_UP_PATH, filled: rating === "up" })
|
|
2070
|
+
),
|
|
2071
|
+
btn(
|
|
2072
|
+
"\uBCC4\uB85C\uC608\uC694",
|
|
2073
|
+
() => handleRate("down"),
|
|
2074
|
+
rating === "down",
|
|
2075
|
+
rating === "down" ? "#dc2626" : void 0,
|
|
2076
|
+
/* @__PURE__ */ jsx7(ActionIcon, { path: THUMB_DOWN_PATH, filled: rating === "down" })
|
|
2077
|
+
)
|
|
2078
|
+
]
|
|
2079
|
+
}
|
|
2080
|
+
)
|
|
1942
2081
|
}
|
|
1943
|
-
)
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
2082
|
+
),
|
|
2083
|
+
rating === "down" && reasonOpen ? /* @__PURE__ */ jsxs3("div", { className: "flex flex-wrap items-center gap-1.5 pl-1 pt-0.5", children: [
|
|
2084
|
+
/* @__PURE__ */ jsx7("span", { className: "text-[11px] text-neutral-400", children: "\uC5B4\uB5A4 \uC810\uC774 \uC544\uC26C\uC6E0\uB098\uC694?" }),
|
|
2085
|
+
FEEDBACK_REASONS.map((r) => /* @__PURE__ */ jsx7(
|
|
2086
|
+
"button",
|
|
2087
|
+
{
|
|
2088
|
+
type: "button",
|
|
2089
|
+
onClick: () => {
|
|
2090
|
+
onRate("down", r.code);
|
|
2091
|
+
setReasonOpen(false);
|
|
2092
|
+
setMenuOpen(false);
|
|
2093
|
+
},
|
|
2094
|
+
className: "xbnova-chip rounded-full border px-2.5 py-1 text-[11px] font-semibold transition",
|
|
2095
|
+
children: r.label
|
|
2096
|
+
},
|
|
2097
|
+
r.code
|
|
2098
|
+
))
|
|
2099
|
+
] }) : null
|
|
2100
|
+
]
|
|
2101
|
+
}
|
|
2102
|
+
);
|
|
1951
2103
|
}
|
|
1952
2104
|
function Bubble({ role, children }) {
|
|
1953
2105
|
const mine = role === "user";
|
|
@@ -1962,6 +2114,14 @@ function Bubble({ role, children }) {
|
|
|
1962
2114
|
function AssistantMarkdown({ text }) {
|
|
1963
2115
|
return /* @__PURE__ */ jsx7("div", { className: "space-y-1.5 text-sm leading-relaxed [&_ol]:list-decimal [&_ul]:list-disc [&_ol]:pl-5 [&_ul]:pl-5 [&_li]:pl-0.5 [&_strong]:font-semibold [&_a]:underline [&_code]:rounded [&_code]:bg-black/10 [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-[0.85em] [&_p]:mb-1.5 last:[&_p]:mb-0", children: /* @__PURE__ */ jsx7(ReactMarkdown, { remarkPlugins: [remarkGfm, remarkBreaks], children: text }) });
|
|
1964
2116
|
}
|
|
2117
|
+
function AnswerActionsFrame({
|
|
2118
|
+
enabled,
|
|
2119
|
+
children,
|
|
2120
|
+
...rest
|
|
2121
|
+
}) {
|
|
2122
|
+
if (!enabled) return /* @__PURE__ */ jsx7("div", { className: "space-y-1", children });
|
|
2123
|
+
return /* @__PURE__ */ jsx7(AnswerActions, { ...rest, children });
|
|
2124
|
+
}
|
|
1965
2125
|
|
|
1966
2126
|
// src/facts.ts
|
|
1967
2127
|
import { useEffect as useEffect9, useRef as useRef9 } from "react";
|