@akropolys/kiku 1.7.3 → 1.7.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/dist/index.js +116 -44
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +116 -44
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +99 -0
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -1130,6 +1130,7 @@ var ArrowUpIcon2 = () => /* @__PURE__ */ jsxs6("svg", { width: "18", height: "18
|
|
|
1130
1130
|
/* @__PURE__ */ jsx7("path", { d: "M12 19V5" })
|
|
1131
1131
|
] });
|
|
1132
1132
|
var StopIcon = () => /* @__PURE__ */ jsx7("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx7("rect", { x: "5", y: "5", width: "14", height: "14", rx: "2" }) });
|
|
1133
|
+
var ContinueIcon = () => /* @__PURE__ */ jsx7("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "currentColor", children: /* @__PURE__ */ jsx7("path", { d: "M8 5v14l11-7z" }) });
|
|
1133
1134
|
var CloseIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
1134
1135
|
/* @__PURE__ */ jsx7("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
1135
1136
|
/* @__PURE__ */ jsx7("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
@@ -1159,12 +1160,22 @@ var MicOffIcon = () => /* @__PURE__ */ jsxs6("svg", { width: "16", height: "16",
|
|
|
1159
1160
|
/* @__PURE__ */ jsx7("path", { d: "M9 9v3a3 3 0 0 0 5.12 2.12" }),
|
|
1160
1161
|
/* @__PURE__ */ jsx7("line", { x1: "12", y1: "19", x2: "12", y2: "22" })
|
|
1161
1162
|
] });
|
|
1162
|
-
var DEFAULT_CHIPS = [
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
"
|
|
1166
|
-
|
|
1167
|
-
];
|
|
1163
|
+
var DEFAULT_CHIPS = [];
|
|
1164
|
+
function extractName(raw) {
|
|
1165
|
+
let s = raw.trim();
|
|
1166
|
+
if (!s || s.length > 40 || s.includes("?")) return null;
|
|
1167
|
+
s = s.replace(/^(hi|hey|hello|yo)[,!.\s]+/i, "");
|
|
1168
|
+
s = s.replace(/^(i['’]?m|im|my name is|call me|it['’]?s|this is|name['’]?s)\s+/i, "");
|
|
1169
|
+
s = s.trim().replace(/[.!,]+$/, "");
|
|
1170
|
+
const words = s.split(/\s+/);
|
|
1171
|
+
if (words.length === 0 || words.length > 3) return null;
|
|
1172
|
+
if (!/^[\p{L}][\p{L}\-'’ ]{0,30}$/u.test(s)) return null;
|
|
1173
|
+
const q = s.toLowerCase();
|
|
1174
|
+
const queryish = ["phone", "laptop", "tv", "cheap", "best", "under", "buy", "search", "find", "show", "need", "want", "price", "sofa", "shoe", "headphone", "camera", "gift", "help"];
|
|
1175
|
+
if (queryish.some((w) => q.includes(w))) return null;
|
|
1176
|
+
const name = words[0];
|
|
1177
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
1178
|
+
}
|
|
1168
1179
|
function parseAtKiku(raw) {
|
|
1169
1180
|
const trimmed = raw.trim();
|
|
1170
1181
|
if (!/^@kiku\b/i.test(trimmed)) return null;
|
|
@@ -1624,15 +1635,9 @@ function ThinkingBlock({ text, isComplete }) {
|
|
|
1624
1635
|
}, children: text })
|
|
1625
1636
|
] });
|
|
1626
1637
|
}
|
|
1627
|
-
var PROPERTY_CHIPS = [
|
|
1628
|
-
"3 bedroom apartments",
|
|
1629
|
-
"Houses under KSh 5,000,000",
|
|
1630
|
-
"Properties in Palm Beach",
|
|
1631
|
-
"Studio apartments with pool"
|
|
1632
|
-
];
|
|
1633
1638
|
function ChatModal({
|
|
1634
1639
|
title = "kiku",
|
|
1635
|
-
placeholder = "Ask me anything
|
|
1640
|
+
placeholder = "Ask me anything\u2026",
|
|
1636
1641
|
backdropColor,
|
|
1637
1642
|
backdropBlur,
|
|
1638
1643
|
onClose,
|
|
@@ -1647,8 +1652,17 @@ function ChatModal({
|
|
|
1647
1652
|
visionCategoryHint
|
|
1648
1653
|
}) {
|
|
1649
1654
|
const client = useAkropolysContext3();
|
|
1650
|
-
const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, stop, reset, referencedIds } = useKiku2();
|
|
1655
|
+
const { messages, sources, loading, streaming, error, lastAction, lastIntent, send, stop, stopped, continueGenerating, reset, referencedIds } = useKiku2();
|
|
1651
1656
|
const [input, setInput] = useState5("");
|
|
1657
|
+
const [shopperName, setShopperNameState] = useState5(() => {
|
|
1658
|
+
try {
|
|
1659
|
+
return client.getShopperName?.() ?? "";
|
|
1660
|
+
} catch {
|
|
1661
|
+
return "";
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
const [nameSkipped, setNameSkipped] = useState5(false);
|
|
1665
|
+
const awaitingName = messages.length === 0 && !shopperName && !nameSkipped;
|
|
1652
1666
|
const [attachments, setAttachments] = useState5([]);
|
|
1653
1667
|
const imageInputRef = useRef5(null);
|
|
1654
1668
|
const handleImageFiles = (files) => {
|
|
@@ -1717,10 +1731,9 @@ function ChatModal({
|
|
|
1717
1731
|
useEffect3(() => {
|
|
1718
1732
|
return () => recognitionRef.current?.abort();
|
|
1719
1733
|
}, []);
|
|
1720
|
-
const
|
|
1721
|
-
const activeChips = chips === DEFAULT_CHIPS && isProperty ? PROPERTY_CHIPS : chips;
|
|
1734
|
+
const activeChips = chips;
|
|
1722
1735
|
const activeTitle = title;
|
|
1723
|
-
const activePlaceholder =
|
|
1736
|
+
const activePlaceholder = awaitingName ? "Type your name\u2026" : placeholder;
|
|
1724
1737
|
const [selectedProduct, setSelectedProduct] = useState5(null);
|
|
1725
1738
|
const [lightboxSrc, setLightboxSrc] = useState5(null);
|
|
1726
1739
|
const bottomRef = useRef5(null);
|
|
@@ -1728,6 +1741,7 @@ function ChatModal({
|
|
|
1728
1741
|
const [keyInput, setKeyInput] = useState5("");
|
|
1729
1742
|
const [keyPhase, setKeyPhase] = useState5("idle");
|
|
1730
1743
|
const [mintedKey, setMintedKey] = useState5(null);
|
|
1744
|
+
const [mintedPub, setMintedPub] = useState5(null);
|
|
1731
1745
|
const [keyCountdown, setKeyCountdown] = useState5(KIKU_KEY_REVEAL_SECONDS);
|
|
1732
1746
|
const [minting, setMinting] = useState5(false);
|
|
1733
1747
|
const [showKikuPicker, setShowKikuPicker] = useState5(false);
|
|
@@ -1746,6 +1760,7 @@ function ChatModal({
|
|
|
1746
1760
|
if (s <= 1) {
|
|
1747
1761
|
clearInterval(t);
|
|
1748
1762
|
setMintedKey(null);
|
|
1763
|
+
setMintedPub(null);
|
|
1749
1764
|
return 0;
|
|
1750
1765
|
}
|
|
1751
1766
|
return s - 1;
|
|
@@ -1767,9 +1782,9 @@ function ChatModal({
|
|
|
1767
1782
|
if (lastUserMsg) await handleSend(lastUserMsg.content);
|
|
1768
1783
|
};
|
|
1769
1784
|
const handleUseExistingKey = async () => {
|
|
1770
|
-
const
|
|
1771
|
-
if (!
|
|
1772
|
-
client.
|
|
1785
|
+
const pub = keyInput.trim();
|
|
1786
|
+
if (!pub) return;
|
|
1787
|
+
client.setKikuPub(pub);
|
|
1773
1788
|
setKeyInput("");
|
|
1774
1789
|
setKeyPhase("idle");
|
|
1775
1790
|
await retryLastMessage();
|
|
@@ -1778,8 +1793,9 @@ function ChatModal({
|
|
|
1778
1793
|
if (minting) return;
|
|
1779
1794
|
setMinting(true);
|
|
1780
1795
|
try {
|
|
1781
|
-
const
|
|
1782
|
-
setMintedKey(
|
|
1796
|
+
const { secret, publicId } = await client.mintKikuKey();
|
|
1797
|
+
setMintedKey(secret);
|
|
1798
|
+
setMintedPub(publicId);
|
|
1783
1799
|
setKeyPhase("idle");
|
|
1784
1800
|
await retryLastMessage();
|
|
1785
1801
|
} catch {
|
|
@@ -1828,12 +1844,31 @@ function ChatModal({
|
|
|
1828
1844
|
const handleSourceClick = (src) => {
|
|
1829
1845
|
setSelectedProduct(src);
|
|
1830
1846
|
onSelectSource?.(src);
|
|
1847
|
+
const lastAssistant = [...messages].reverse().find((m) => m.role === "assistant");
|
|
1848
|
+
if (lastAssistant && lastAssistant.content.trim().endsWith("?")) {
|
|
1849
|
+
send(`The ${src.name}`);
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1831
1852
|
const q = `Tell me more about the ${src.name}${src.price ? ` (${src.currency ?? defaultCurrency} ${src.price})` : ""} \u2014 what are its key specs, who is it best for, and is it worth buying?`;
|
|
1832
1853
|
send(q);
|
|
1833
1854
|
};
|
|
1834
1855
|
const handleSend = async (text, extraAttachments, forcedIntent, captureTargets) => {
|
|
1835
1856
|
const raw = (text ?? input).trim();
|
|
1836
1857
|
if (!raw || loading) return;
|
|
1858
|
+
if (awaitingName) {
|
|
1859
|
+
const name = extractName(raw);
|
|
1860
|
+
if (name) {
|
|
1861
|
+
try {
|
|
1862
|
+
client.setShopperName?.(name);
|
|
1863
|
+
} catch {
|
|
1864
|
+
}
|
|
1865
|
+
setShopperNameState(name);
|
|
1866
|
+
setInput("");
|
|
1867
|
+
if (textareaRef.current) textareaRef.current.style.height = "auto";
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
setNameSkipped(true);
|
|
1871
|
+
}
|
|
1837
1872
|
const kiku = parseAtKiku(raw);
|
|
1838
1873
|
const q = kiku ? kiku.cleanQuery : raw;
|
|
1839
1874
|
const resolvedForcedIntent = forcedIntent ?? kiku?.intent;
|
|
@@ -1916,7 +1951,7 @@ function ChatModal({
|
|
|
1916
1951
|
setInput(val);
|
|
1917
1952
|
const trimmed = val.trim();
|
|
1918
1953
|
setShowAtPicker(trimmed === "@");
|
|
1919
|
-
setShowKikuPicker(/^@kiku\
|
|
1954
|
+
setShowKikuPicker(/^@kiku\s*$/i.test(trimmed));
|
|
1920
1955
|
const t = e.target;
|
|
1921
1956
|
t.style.height = "auto";
|
|
1922
1957
|
t.style.height = `${Math.min(t.scrollHeight, 140)}px`;
|
|
@@ -1979,9 +2014,23 @@ function ChatModal({
|
|
|
1979
2014
|
] }),
|
|
1980
2015
|
/* @__PURE__ */ jsxs6("div", { className: "hsk-cb-msgs", ref: msgsContainerRef, children: [
|
|
1981
2016
|
displayMessages.length === 0 ? /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-empty", children: [
|
|
1982
|
-
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-
|
|
1983
|
-
/* @__PURE__ */
|
|
1984
|
-
|
|
2017
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-logo", "aria-hidden": "true", children: /* @__PURE__ */ jsx7("svg", { viewBox: "0 0 100 100", className: "hsk-brand-mark", children: /* @__PURE__ */ jsx7("path", { d: "M39.4 10.4 Q44 0 48.6 10.4 L86.1 95.8 Q88 100 83.4 100 L4.6 100 Q0 100 1.9 95.8 Z M24 100 L24 65 Q24 60 27.4 56.3 Q44 38 60.6 56.3 Q64 60 64 65 L64 100 Z", transform: "translate(22.7 19) scale(0.62)", fillRule: "evenodd" }) }) }),
|
|
2018
|
+
awaitingName ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
2019
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-title hsk-cb-onboard-title", children: "My name is Kiku" }),
|
|
2020
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-sub", children: "Ask me to search, visualize, or capture anything for you \u2014 on this site or any other." }),
|
|
2021
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-onboard-ask", children: "What should I call you?" }),
|
|
2022
|
+
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-onboard-skip", onClick: () => setNameSkipped(true), children: "Skip" })
|
|
2023
|
+
] }) : shopperName ? /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
2024
|
+
/* @__PURE__ */ jsxs6("div", { className: "hsk-cb-empty-title", children: [
|
|
2025
|
+
"Hey, ",
|
|
2026
|
+
shopperName
|
|
2027
|
+
] }),
|
|
2028
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-sub", children: "What can I find for you today?" })
|
|
2029
|
+
] }) : /* @__PURE__ */ jsxs6(Fragment3, { children: [
|
|
2030
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-title", children: "Hey, I'm kiku" }),
|
|
2031
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-empty-sub", children: "Ask me to search, visualize, or capture anything \u2014 I look across the whole site in real time." })
|
|
2032
|
+
] }),
|
|
2033
|
+
!awaitingName && activeChips.length > 0 && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-chips", children: activeChips.map((chip) => /* @__PURE__ */ jsx7(
|
|
1985
2034
|
"button",
|
|
1986
2035
|
{
|
|
1987
2036
|
className: "hsk-cb-chip",
|
|
@@ -2103,17 +2152,24 @@ function ChatModal({
|
|
|
2103
2152
|
] }),
|
|
2104
2153
|
/* @__PURE__ */ jsx7("span", { className: "hsk-cb-thinking-text", children: "Thinking\u2026" })
|
|
2105
2154
|
] }),
|
|
2155
|
+
stopped && !loading && !streaming && messages[messages.length - 1]?.role === "assistant" && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-stopped", children: [
|
|
2156
|
+
/* @__PURE__ */ jsx7("span", { className: "hsk-cb-stopped-label", children: "You stopped this response." }),
|
|
2157
|
+
/* @__PURE__ */ jsxs6("button", { className: "hsk-cb-continue", onClick: continueGenerating, children: [
|
|
2158
|
+
/* @__PURE__ */ jsx7(ContinueIcon, {}),
|
|
2159
|
+
"Continue generating"
|
|
2160
|
+
] })
|
|
2161
|
+
] }),
|
|
2106
2162
|
error && /* @__PURE__ */ jsx7("div", { className: "hsk-cb-error", children: getFriendlyError(error) }),
|
|
2107
2163
|
keyPhase === "prompt_key" && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
|
|
2108
2164
|
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
|
|
2109
2165
|
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-phone-form", children: [
|
|
2110
|
-
/* @__PURE__ */ jsx7("label", { className: "hsk-cb-phone-label", children: "Paste your
|
|
2166
|
+
/* @__PURE__ */ jsx7("label", { className: "hsk-cb-phone-label", children: "Paste your public id \u2014 or create one" }),
|
|
2111
2167
|
/* @__PURE__ */ jsx7(
|
|
2112
2168
|
"input",
|
|
2113
2169
|
{
|
|
2114
2170
|
type: "text",
|
|
2115
2171
|
className: "hsk-cb-phone-input",
|
|
2116
|
-
placeholder: "
|
|
2172
|
+
placeholder: "your public id\u2026",
|
|
2117
2173
|
value: keyInput,
|
|
2118
2174
|
onChange: (e) => setKeyInput(e.target.value),
|
|
2119
2175
|
onKeyDown: (e) => e.key === "Enter" && handleUseExistingKey(),
|
|
@@ -2121,28 +2177,44 @@ function ChatModal({
|
|
|
2121
2177
|
}
|
|
2122
2178
|
),
|
|
2123
2179
|
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8 }, children: [
|
|
2124
|
-
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleUseExistingKey, disabled: !keyInput.trim(), children: "Use my
|
|
2125
|
-
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleCreateKey, disabled: minting, children: minting ? "Creating\u2026" : "I'm new \u2014 create
|
|
2180
|
+
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleUseExistingKey, disabled: !keyInput.trim(), children: "Use my id" }),
|
|
2181
|
+
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", onClick: handleCreateKey, disabled: minting, children: minting ? "Creating\u2026" : "I'm new \u2014 create one" })
|
|
2126
2182
|
] })
|
|
2127
2183
|
] }) }) })
|
|
2128
2184
|
] }),
|
|
2129
2185
|
mintedKey && /* @__PURE__ */ jsxs6("div", { className: "hsk-cb-ai-msg", children: [
|
|
2130
2186
|
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-icon", style: { display: "flex", alignItems: "center" }, children: /* @__PURE__ */ jsx7(SparkleIcon2, {}) }),
|
|
2131
|
-
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { style: { padding: "
|
|
2132
|
-
/* @__PURE__ */
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
/* @__PURE__ */
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
"
|
|
2143
|
-
keyCountdown,
|
|
2144
|
-
"s. Save it like a password \u2014 if lost, the memory it opens is lost with it."
|
|
2187
|
+
/* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-body", children: /* @__PURE__ */ jsx7("div", { className: "hsk-cb-ai-text", children: /* @__PURE__ */ jsxs6("div", { style: { padding: "12px 14px", border: "1px solid var(--hsk-border, #e5e5e5)", borderRadius: "var(--hsk-border-radius, 0px)", display: "flex", flexDirection: "column", gap: 12 }, children: [
|
|
2188
|
+
/* @__PURE__ */ jsxs6("div", { children: [
|
|
2189
|
+
/* @__PURE__ */ jsx7("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "Your secret \u2014 shown only once" }),
|
|
2190
|
+
/* @__PURE__ */ jsx7("code", { style: { display: "block", fontSize: 14, fontWeight: 700, marginBottom: 6, wordBreak: "break-all" }, children: mintedKey }),
|
|
2191
|
+
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
2192
|
+
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", style: { padding: "4px 10px" }, onClick: () => {
|
|
2193
|
+
try {
|
|
2194
|
+
navigator.clipboard?.writeText(mintedKey);
|
|
2195
|
+
} catch {
|
|
2196
|
+
}
|
|
2197
|
+
}, children: "Copy secret" }),
|
|
2198
|
+
/* @__PURE__ */ jsx7("span", { style: { fontSize: 11, opacity: 0.7 }, children: "Keep it private \u2014 use it to unlock your memory at mimi.akropolys.cloud. If lost, the memory is lost with it." })
|
|
2145
2199
|
] })
|
|
2200
|
+
] }),
|
|
2201
|
+
mintedPub && /* @__PURE__ */ jsxs6("div", { children: [
|
|
2202
|
+
/* @__PURE__ */ jsx7("div", { style: { fontSize: 12, fontWeight: 600, marginBottom: 4 }, children: "Your public id" }),
|
|
2203
|
+
/* @__PURE__ */ jsx7("code", { style: { display: "block", fontSize: 13, fontWeight: 600, marginBottom: 6, wordBreak: "break-all", opacity: 0.85 }, children: mintedPub }),
|
|
2204
|
+
/* @__PURE__ */ jsxs6("div", { style: { display: "flex", gap: 8, alignItems: "center" }, children: [
|
|
2205
|
+
/* @__PURE__ */ jsx7("button", { className: "hsk-cb-phone-submit", style: { padding: "4px 10px" }, onClick: () => {
|
|
2206
|
+
try {
|
|
2207
|
+
navigator.clipboard?.writeText(mintedPub);
|
|
2208
|
+
} catch {
|
|
2209
|
+
}
|
|
2210
|
+
}, children: "Copy id" }),
|
|
2211
|
+
/* @__PURE__ */ jsx7("span", { style: { fontSize: 11, opacity: 0.7 }, children: "Paste this on any site to keep saving to the same memory." })
|
|
2212
|
+
] })
|
|
2213
|
+
] }),
|
|
2214
|
+
/* @__PURE__ */ jsxs6("div", { style: { fontSize: 11, opacity: 0.6 }, children: [
|
|
2215
|
+
"Hidden in ",
|
|
2216
|
+
keyCountdown,
|
|
2217
|
+
"s."
|
|
2146
2218
|
] })
|
|
2147
2219
|
] }) }) })
|
|
2148
2220
|
] }),
|