@akropolys/kiku 1.5.0 → 1.5.3
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.js +179 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +179 -61
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +59 -0
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -205,7 +205,7 @@ var import_sdk3 = require("@akropolys/sdk");
|
|
|
205
205
|
// src/utils/markdown.tsx
|
|
206
206
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
207
207
|
var parseInline = (text, keyPrefix) => {
|
|
208
|
-
const tokenRegex = /(\[[^\]]+\]\([^)]+\)|\*\*[^*]+\*\*|`[^`]+`)/g;
|
|
208
|
+
const tokenRegex = /(!\[[^\]]*\]\([^)]+\)|\[[^\]]+\]\([^)]+\)|\*\*[^*]+\*\*|`[^`]+`)/g;
|
|
209
209
|
const parts = text.split(tokenRegex);
|
|
210
210
|
return parts.map((part, index) => {
|
|
211
211
|
if (!part) return null;
|
|
@@ -216,6 +216,28 @@ var parseInline = (text, keyPrefix) => {
|
|
|
216
216
|
if (part.startsWith("**") && part.endsWith("**")) {
|
|
217
217
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: parseInline(part.slice(2, -2), key) }, key);
|
|
218
218
|
}
|
|
219
|
+
const imageMatch = part.match(/^!\[([^\]]*)\]\(([^)]+)\)$/);
|
|
220
|
+
if (imageMatch) {
|
|
221
|
+
const alt = imageMatch[1];
|
|
222
|
+
const url = imageMatch[2];
|
|
223
|
+
const isSafeUrl = /^(https?|data:image):/i.test(url);
|
|
224
|
+
if (isSafeUrl) {
|
|
225
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
226
|
+
"img",
|
|
227
|
+
{
|
|
228
|
+
src: url,
|
|
229
|
+
alt: alt || "Product image",
|
|
230
|
+
className: "hsk-markdown-img",
|
|
231
|
+
loading: "lazy",
|
|
232
|
+
onError: (e) => {
|
|
233
|
+
e.target.style.display = "none";
|
|
234
|
+
}
|
|
235
|
+
},
|
|
236
|
+
key
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
219
241
|
const linkMatch = part.match(/^\[([^\]]+)\]\(([^)]+)\)$/);
|
|
220
242
|
if (linkMatch) {
|
|
221
243
|
const url = linkMatch[2];
|
|
@@ -239,6 +261,30 @@ function renderMarkdown(content) {
|
|
|
239
261
|
i++;
|
|
240
262
|
continue;
|
|
241
263
|
}
|
|
264
|
+
const standaloneImageMatch = line.trim().match(/^!\[([^\]]*)\]\(([^)]+)\)$/);
|
|
265
|
+
if (standaloneImageMatch) {
|
|
266
|
+
const alt = standaloneImageMatch[1];
|
|
267
|
+
const url = standaloneImageMatch[2];
|
|
268
|
+
const isSafeUrl = /^(https?|data:image):/i.test(url);
|
|
269
|
+
if (isSafeUrl) {
|
|
270
|
+
elements.push(
|
|
271
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "hsk-markdown-img-block", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
272
|
+
"img",
|
|
273
|
+
{
|
|
274
|
+
src: url,
|
|
275
|
+
alt: alt || "Product image",
|
|
276
|
+
className: "hsk-markdown-img",
|
|
277
|
+
loading: "lazy",
|
|
278
|
+
onError: (e) => {
|
|
279
|
+
e.target.style.display = "none";
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
) }, key)
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
i++;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
242
288
|
const headerMatch = line.match(/^(#{1,3})\s+(.*)/);
|
|
243
289
|
if (headerMatch) {
|
|
244
290
|
const level = headerMatch[1].length;
|
|
@@ -426,18 +472,31 @@ var ArrowUpIcon = () => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { w
|
|
|
426
472
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "m5 12 7-7 7 7" }),
|
|
427
473
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12 19V5" })
|
|
428
474
|
] });
|
|
429
|
-
function SourceCard({
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
475
|
+
function SourceCard({
|
|
476
|
+
source,
|
|
477
|
+
defaultCurrency,
|
|
478
|
+
onSelect,
|
|
479
|
+
isReferenced
|
|
480
|
+
}) {
|
|
481
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
482
|
+
"div",
|
|
483
|
+
{
|
|
484
|
+
className: cn("hsk-source-card", isReferenced && "hsk-source-card--referenced"),
|
|
485
|
+
onClick: () => onSelect?.(source),
|
|
486
|
+
children: [
|
|
487
|
+
source.image && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("img", { src: source.image, alt: source.name, className: "hsk-source-img" }),
|
|
488
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { flex: 1, minWidth: 0, position: "relative" }, children: [
|
|
489
|
+
isReferenced && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-cb-source-ref-badge", title: "Featured in response", style: { top: "0", right: "0" }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon, {}) }),
|
|
490
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-source-name", style: { paddingRight: isReferenced ? "20px" : void 0 }, children: source.name }),
|
|
491
|
+
source.price && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-source-price", children: [
|
|
492
|
+
source.currency ?? defaultCurrency,
|
|
493
|
+
" ",
|
|
494
|
+
source.price
|
|
495
|
+
] })
|
|
496
|
+
] })
|
|
497
|
+
]
|
|
498
|
+
}
|
|
499
|
+
);
|
|
441
500
|
}
|
|
442
501
|
function ChatWidget({
|
|
443
502
|
title = "AI Shopping Assistant",
|
|
@@ -453,7 +512,7 @@ function ChatWidget({
|
|
|
453
512
|
enableVision = false,
|
|
454
513
|
visionCategoryHint
|
|
455
514
|
}) {
|
|
456
|
-
const { messages, sources, loading: chatLoading, error, send, reset } = (0, import_sdk3.useKiku)();
|
|
515
|
+
const { messages, sources, referencedIds, loading: chatLoading, streaming, error, send, reset } = (0, import_sdk3.useKiku)();
|
|
457
516
|
const [input, setInput] = (0, import_react4.useState)("");
|
|
458
517
|
const [visualLoading, setVisualLoading] = (0, import_react4.useState)(false);
|
|
459
518
|
const bottomRef = (0, import_react4.useRef)(null);
|
|
@@ -611,7 +670,54 @@ I couldn't find any matching products in the store.`;
|
|
|
611
670
|
] })
|
|
612
671
|
] }),
|
|
613
672
|
msg.role === "assistant" && msg.visualSources && msg.visualSources.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-container", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: msg.visualSources.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SourceCard, { source: src, defaultCurrency, onSelect: onSelectSource }, si)) }) }),
|
|
614
|
-
msg.role === "assistant" && idx === chatHistory.length - 1 && !msg.visualSources && sources.length > 0 &&
|
|
673
|
+
msg.role === "assistant" && idx === chatHistory.length - 1 && !msg.visualSources && sources.length > 0 && (() => {
|
|
674
|
+
const isStreamingActive = chatLoading || streaming;
|
|
675
|
+
if (isStreamingActive) {
|
|
676
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-container", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: sources.map((src, si) => {
|
|
677
|
+
const isReferenced = !!(src.id && referencedIds.includes(src.id));
|
|
678
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
679
|
+
SourceCard,
|
|
680
|
+
{
|
|
681
|
+
source: src,
|
|
682
|
+
defaultCurrency,
|
|
683
|
+
onSelect: onSelectSource,
|
|
684
|
+
isReferenced
|
|
685
|
+
},
|
|
686
|
+
si
|
|
687
|
+
);
|
|
688
|
+
}) }) });
|
|
689
|
+
}
|
|
690
|
+
const featured = sources.filter((src) => src.id && referencedIds.includes(src.id));
|
|
691
|
+
const general = sources.filter((src) => !src.id || !referencedIds.includes(src.id));
|
|
692
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-sources-container", children: [
|
|
693
|
+
featured.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-sources-group", style: { marginBottom: "10px" }, children: [
|
|
694
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-group-title", children: "\u2B50 Featured in response" }),
|
|
695
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: featured.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
696
|
+
SourceCard,
|
|
697
|
+
{
|
|
698
|
+
source: src,
|
|
699
|
+
defaultCurrency,
|
|
700
|
+
onSelect: onSelectSource,
|
|
701
|
+
isReferenced: true
|
|
702
|
+
},
|
|
703
|
+
`feat-${si}`
|
|
704
|
+
)) })
|
|
705
|
+
] }),
|
|
706
|
+
general.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-sources-group", children: [
|
|
707
|
+
featured.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources-group-title", children: "All matches" }),
|
|
708
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-sources", children: general.map((src, si) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
709
|
+
SourceCard,
|
|
710
|
+
{
|
|
711
|
+
source: src,
|
|
712
|
+
defaultCurrency,
|
|
713
|
+
onSelect: onSelectSource,
|
|
714
|
+
isReferenced: false
|
|
715
|
+
},
|
|
716
|
+
`gen-${si}`
|
|
717
|
+
)) })
|
|
718
|
+
] })
|
|
719
|
+
] });
|
|
720
|
+
})()
|
|
615
721
|
] }, idx)),
|
|
616
722
|
loading && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "hsk-msg-row", children: [
|
|
617
723
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "hsk-msg-avatar ai", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SparkleIcon, {}) }),
|
|
@@ -1141,8 +1247,10 @@ function ActionPills({ cart, actionType, onSend, loading }) {
|
|
|
1141
1247
|
const pills = [];
|
|
1142
1248
|
if (hasItems && lastItem) {
|
|
1143
1249
|
if (actionType === "add_to_cart") {
|
|
1144
|
-
|
|
1145
|
-
|
|
1250
|
+
const name = lastItem.name || "item";
|
|
1251
|
+
const shortName = name.split(" ")[0] || "item";
|
|
1252
|
+
pills.push({ emoji: "\u2795", label: "Add 1 more", query: `Add one more ${name} to my cart` });
|
|
1253
|
+
pills.push({ emoji: "\u{1F5D1}\uFE0F", label: `Remove ${shortName}`, query: `Remove the ${name} from my cart` });
|
|
1146
1254
|
}
|
|
1147
1255
|
if (cart.items.length > 1) {
|
|
1148
1256
|
pills.push({ emoji: "\u{1F6D2}", label: "View cart", query: "Show me my cart" });
|
|
@@ -1173,7 +1281,7 @@ function ActionPills({ cart, actionType, onSend, loading }) {
|
|
|
1173
1281
|
pill.query
|
|
1174
1282
|
)) });
|
|
1175
1283
|
}
|
|
1176
|
-
function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
|
|
1284
|
+
function SourcesCarousel({ sources, defaultCurrency, onSelectSource, referencedIds = [] }) {
|
|
1177
1285
|
const client = (0, import_sdk6.useAkropolysContext)();
|
|
1178
1286
|
const isProperty = client?.vertical === "property";
|
|
1179
1287
|
const railRef = (0, import_react5.useRef)(null);
|
|
@@ -1200,44 +1308,51 @@ function SourcesCarousel({ sources, defaultCurrency, onSelectSource }) {
|
|
|
1200
1308
|
railRef.current?.scrollBy({ left: 170, behavior: "smooth" });
|
|
1201
1309
|
};
|
|
1202
1310
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-sources-wrap", children: [
|
|
1203
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-sources", ref: railRef, children: sources.map((src, si) =>
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
" ",
|
|
1234
|
-
|
|
1311
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-sources", ref: railRef, children: sources.map((src, si) => {
|
|
1312
|
+
const isReferenced = !!(src.id && referencedIds.includes(src.id));
|
|
1313
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1314
|
+
"div",
|
|
1315
|
+
{
|
|
1316
|
+
className: cn("hsk-cb-source", isReferenced && "hsk-cb-source--referenced"),
|
|
1317
|
+
style: { animationDelay: `${si * 50}ms` },
|
|
1318
|
+
onClick: () => onSelectSource?.(src),
|
|
1319
|
+
children: [
|
|
1320
|
+
src.image ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-imgwrap", style: { position: "relative" }, children: [
|
|
1321
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("img", { src: src.image, alt: src.name, loading: "lazy" }),
|
|
1322
|
+
isReferenced && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-source-ref-badge", title: "Featured in response", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, { size: 10 }) }),
|
|
1323
|
+
isProperty && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: {
|
|
1324
|
+
position: "absolute",
|
|
1325
|
+
top: "6px",
|
|
1326
|
+
right: "6px",
|
|
1327
|
+
background: "rgba(14, 14, 15, 0.75)",
|
|
1328
|
+
backdropFilter: "blur(4px)",
|
|
1329
|
+
borderRadius: "50%",
|
|
1330
|
+
width: "24px",
|
|
1331
|
+
height: "24px",
|
|
1332
|
+
display: "flex",
|
|
1333
|
+
alignItems: "center",
|
|
1334
|
+
justifyContent: "center",
|
|
1335
|
+
color: "#fbbf24",
|
|
1336
|
+
// Gold sparkle badge
|
|
1337
|
+
boxShadow: "0 2px 4px rgba(0,0,0,0.2)"
|
|
1338
|
+
}, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, { size: 12 }) })
|
|
1339
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-imgwrap-empty", style: { position: "relative" }, children: [
|
|
1340
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, {}),
|
|
1341
|
+
isReferenced && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-source-ref-badge", title: "Featured in response", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SparkleIcon2, { size: 10 }) })
|
|
1342
|
+
] }),
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-info", children: [
|
|
1344
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "hsk-cb-src-name", children: src.name }),
|
|
1345
|
+
src.price && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "hsk-cb-src-price", children: [
|
|
1346
|
+
src.currency ?? defaultCurrency,
|
|
1347
|
+
" ",
|
|
1348
|
+
parseFloat(String(src.price).replace(/[^0-9.]/g, "") || "0").toLocaleString()
|
|
1349
|
+
] })
|
|
1235
1350
|
] })
|
|
1236
|
-
]
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
)
|
|
1351
|
+
]
|
|
1352
|
+
},
|
|
1353
|
+
si
|
|
1354
|
+
);
|
|
1355
|
+
}) }),
|
|
1241
1356
|
showNext && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
1242
1357
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
1243
1358
|
"div",
|
|
@@ -1285,11 +1400,12 @@ function SmartContextPills({
|
|
|
1285
1400
|
});
|
|
1286
1401
|
}
|
|
1287
1402
|
if (cheapest && !isProperty) {
|
|
1288
|
-
const
|
|
1403
|
+
const name = cheapest.name || "";
|
|
1404
|
+
const short = name.split(" ").slice(0, 3).join(" ");
|
|
1289
1405
|
pills.push({
|
|
1290
1406
|
emoji: "\u{1F6D2}",
|
|
1291
1407
|
label: `Add ${short}`,
|
|
1292
|
-
query: `Add the ${
|
|
1408
|
+
query: `Add the ${name} to my cart`
|
|
1293
1409
|
});
|
|
1294
1410
|
}
|
|
1295
1411
|
if (isProperty) {
|
|
@@ -1299,11 +1415,12 @@ function SmartContextPills({
|
|
|
1299
1415
|
}
|
|
1300
1416
|
} else if (intent === "compare" && sources.length > 0) {
|
|
1301
1417
|
if (cheapest && !isProperty) {
|
|
1302
|
-
const
|
|
1418
|
+
const name = cheapest.name || "";
|
|
1419
|
+
const short = name.split(" ").slice(0, 3).join(" ");
|
|
1303
1420
|
pills.push({
|
|
1304
1421
|
emoji: "\u{1F6D2}",
|
|
1305
1422
|
label: `Add ${short}`,
|
|
1306
|
-
query: `Add the ${
|
|
1423
|
+
query: `Add the ${name} to my cart`
|
|
1307
1424
|
});
|
|
1308
1425
|
}
|
|
1309
1426
|
if (firstName) {
|
|
@@ -1406,7 +1523,7 @@ function ChatModal({
|
|
|
1406
1523
|
visionCategoryHint
|
|
1407
1524
|
}) {
|
|
1408
1525
|
const client = (0, import_sdk6.useAkropolysContext)();
|
|
1409
|
-
const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, reset } = (0, import_sdk4.useKiku)();
|
|
1526
|
+
const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, reset, referencedIds } = (0, import_sdk4.useKiku)();
|
|
1410
1527
|
const [input, setInput] = (0, import_react5.useState)("");
|
|
1411
1528
|
const [loadingMessageIndex, setLoadingMessageIndex] = (0, import_react5.useState)(0);
|
|
1412
1529
|
const [attachments, setAttachments] = (0, import_react5.useState)([]);
|
|
@@ -1751,7 +1868,8 @@ function ChatModal({
|
|
|
1751
1868
|
{
|
|
1752
1869
|
sources,
|
|
1753
1870
|
defaultCurrency,
|
|
1754
|
-
onSelectSource: handleSourceClick
|
|
1871
|
+
onSelectSource: handleSourceClick,
|
|
1872
|
+
referencedIds
|
|
1755
1873
|
}
|
|
1756
1874
|
),
|
|
1757
1875
|
msg.cartSnapshot && msg.cartSnapshot.items?.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|