@informedai/react 0.4.14 → 0.4.16

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.mjs CHANGED
@@ -1271,19 +1271,1008 @@ function LoadingSpinner({ size = 20 }) {
1271
1271
  );
1272
1272
  }
1273
1273
 
1274
+ // src/components/AdminChatbot.tsx
1275
+ import { useState as useState3, useRef as useRef3, useEffect as useEffect3 } from "react";
1276
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1277
+ var defaultTheme2 = {
1278
+ primaryColor: "#3b82f6",
1279
+ // Blue (different from widget's amber)
1280
+ backgroundColor: "#ffffff",
1281
+ textColor: "#1c1917",
1282
+ borderRadius: "12px",
1283
+ fontFamily: "system-ui, -apple-system, sans-serif"
1284
+ };
1285
+ function AdminChatbot({ className, ...config }) {
1286
+ const theme = { ...defaultTheme2, ...config.theme };
1287
+ const apiUrl = config.apiUrl || "https://api.informedai.app/api/v1";
1288
+ const [messages, setMessages] = useState3([]);
1289
+ const [inputValue, setInputValue] = useState3("");
1290
+ const [systemPrompt, setSystemPrompt] = useState3(config.systemPrompt || "");
1291
+ const [showSystemPromptEditor, setShowSystemPromptEditor] = useState3(false);
1292
+ const [isStreaming, setIsStreaming] = useState3(false);
1293
+ const [streamingContent, setStreamingContent] = useState3("");
1294
+ const [error, setError] = useState3(null);
1295
+ const [isCollapsed, setIsCollapsed] = useState3(config.defaultCollapsed ?? false);
1296
+ const messagesEndRef = useRef3(null);
1297
+ const inputRef = useRef3(null);
1298
+ useEffect3(() => {
1299
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1300
+ }, [messages, streamingContent]);
1301
+ const sendMessage = async (message) => {
1302
+ if (!message.trim() || isStreaming) return;
1303
+ setError(null);
1304
+ setIsStreaming(true);
1305
+ setStreamingContent("");
1306
+ const newMessages = [...messages, { role: "user", content: message }];
1307
+ setMessages(newMessages);
1308
+ try {
1309
+ const response = await fetch(`${apiUrl}/admin-chatbot/message`, {
1310
+ method: "POST",
1311
+ headers: {
1312
+ "Content-Type": "application/json",
1313
+ Authorization: `Bearer ${config.apiKey}`
1314
+ },
1315
+ body: JSON.stringify({
1316
+ message,
1317
+ history: messages,
1318
+ // Send previous messages (not including current)
1319
+ systemPrompt: systemPrompt || void 0
1320
+ })
1321
+ });
1322
+ if (!response.ok) {
1323
+ const err = await response.json().catch(() => ({ error: "Request failed" }));
1324
+ throw new Error(err.error || `HTTP ${response.status}`);
1325
+ }
1326
+ const reader = response.body?.getReader();
1327
+ if (!reader) throw new Error("No response body");
1328
+ const decoder = new TextDecoder();
1329
+ let buffer = "";
1330
+ let fullContent = "";
1331
+ while (true) {
1332
+ const { done, value } = await reader.read();
1333
+ if (done) break;
1334
+ buffer += decoder.decode(value, { stream: true });
1335
+ const lines = buffer.split("\n");
1336
+ buffer = lines.pop() || "";
1337
+ for (const line of lines) {
1338
+ if (line.startsWith("event:")) continue;
1339
+ if (line.startsWith("data:")) {
1340
+ const data = line.slice(5).trim();
1341
+ try {
1342
+ const parsed = JSON.parse(data);
1343
+ if (parsed.content) {
1344
+ fullContent += parsed.content;
1345
+ setStreamingContent(fullContent);
1346
+ }
1347
+ if (parsed.fullContent) {
1348
+ fullContent = parsed.fullContent;
1349
+ }
1350
+ } catch {
1351
+ }
1352
+ }
1353
+ }
1354
+ }
1355
+ setMessages([...newMessages, { role: "assistant", content: fullContent }]);
1356
+ setStreamingContent("");
1357
+ } catch (err) {
1358
+ setError(err instanceof Error ? err.message : "Failed to send message");
1359
+ } finally {
1360
+ setIsStreaming(false);
1361
+ }
1362
+ };
1363
+ const handleSubmit = (e) => {
1364
+ e.preventDefault();
1365
+ if (!inputValue.trim() || isStreaming) return;
1366
+ const message = inputValue.trim();
1367
+ setInputValue("");
1368
+ sendMessage(message);
1369
+ };
1370
+ const clearConversation = () => {
1371
+ setMessages([]);
1372
+ setStreamingContent("");
1373
+ setError(null);
1374
+ };
1375
+ const cssVars = {
1376
+ "--ac-primary": theme.primaryColor,
1377
+ "--ac-bg": theme.backgroundColor,
1378
+ "--ac-text": theme.textColor,
1379
+ "--ac-radius": theme.borderRadius,
1380
+ "--ac-font": theme.fontFamily
1381
+ };
1382
+ const positionStyles = config.position === "inline" ? {} : {
1383
+ position: "fixed",
1384
+ [config.position === "bottom-left" ? "left" : "right"]: "20px",
1385
+ bottom: "20px",
1386
+ zIndex: 9999
1387
+ };
1388
+ if (isCollapsed && config.position !== "inline") {
1389
+ return /* @__PURE__ */ jsx3(
1390
+ "button",
1391
+ {
1392
+ onClick: () => setIsCollapsed(false),
1393
+ className,
1394
+ style: {
1395
+ ...cssVars,
1396
+ ...positionStyles,
1397
+ width: "56px",
1398
+ height: "56px",
1399
+ borderRadius: "50%",
1400
+ backgroundColor: "var(--ac-primary)",
1401
+ color: "white",
1402
+ border: "none",
1403
+ cursor: "pointer",
1404
+ display: "flex",
1405
+ alignItems: "center",
1406
+ justifyContent: "center",
1407
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
1408
+ fontFamily: "var(--ac-font)"
1409
+ },
1410
+ children: /* @__PURE__ */ jsx3("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
1411
+ }
1412
+ );
1413
+ }
1414
+ return /* @__PURE__ */ jsxs2(
1415
+ "div",
1416
+ {
1417
+ className,
1418
+ style: {
1419
+ ...cssVars,
1420
+ ...positionStyles,
1421
+ width: config.position === "inline" ? "100%" : "400px",
1422
+ maxHeight: config.position === "inline" ? "600px" : "80vh",
1423
+ backgroundColor: "var(--ac-bg)",
1424
+ borderRadius: "var(--ac-radius)",
1425
+ border: "1px solid #e5e5e5",
1426
+ fontFamily: "var(--ac-font)",
1427
+ display: "flex",
1428
+ flexDirection: "column",
1429
+ boxShadow: config.position === "inline" ? "none" : "0 4px 20px rgba(0,0,0,0.15)",
1430
+ overflow: "hidden"
1431
+ },
1432
+ children: [
1433
+ /* @__PURE__ */ jsxs2(
1434
+ "div",
1435
+ {
1436
+ style: {
1437
+ padding: "16px",
1438
+ borderBottom: "1px solid #e5e5e5",
1439
+ display: "flex",
1440
+ alignItems: "center",
1441
+ justifyContent: "space-between",
1442
+ backgroundColor: "var(--ac-primary)",
1443
+ color: "white"
1444
+ },
1445
+ children: [
1446
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
1447
+ /* @__PURE__ */ jsxs2("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1448
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10" }),
1449
+ /* @__PURE__ */ jsx3("path", { d: "M12 16v-4M12 8h.01" })
1450
+ ] }),
1451
+ /* @__PURE__ */ jsx3("span", { style: { fontWeight: 600 }, children: config.title || "Knowledge Library" })
1452
+ ] }),
1453
+ /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
1454
+ config.allowEditSystemPrompt && /* @__PURE__ */ jsx3(
1455
+ "button",
1456
+ {
1457
+ onClick: () => setShowSystemPromptEditor(!showSystemPromptEditor),
1458
+ style: {
1459
+ background: "rgba(255,255,255,0.2)",
1460
+ border: "none",
1461
+ borderRadius: "4px",
1462
+ padding: "4px 8px",
1463
+ color: "white",
1464
+ cursor: "pointer",
1465
+ fontSize: "12px"
1466
+ },
1467
+ children: showSystemPromptEditor ? "Hide Prompt" : "Edit Prompt"
1468
+ }
1469
+ ),
1470
+ /* @__PURE__ */ jsx3(
1471
+ "button",
1472
+ {
1473
+ onClick: clearConversation,
1474
+ style: {
1475
+ background: "rgba(255,255,255,0.2)",
1476
+ border: "none",
1477
+ borderRadius: "4px",
1478
+ padding: "4px 8px",
1479
+ color: "white",
1480
+ cursor: "pointer",
1481
+ fontSize: "12px"
1482
+ },
1483
+ children: "Clear"
1484
+ }
1485
+ ),
1486
+ config.position !== "inline" && /* @__PURE__ */ jsx3(
1487
+ "button",
1488
+ {
1489
+ onClick: () => setIsCollapsed(true),
1490
+ style: {
1491
+ background: "none",
1492
+ border: "none",
1493
+ color: "white",
1494
+ cursor: "pointer",
1495
+ padding: "4px"
1496
+ },
1497
+ children: /* @__PURE__ */ jsxs2("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1498
+ /* @__PURE__ */ jsx3("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
1499
+ /* @__PURE__ */ jsx3("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
1500
+ ] })
1501
+ }
1502
+ )
1503
+ ] })
1504
+ ]
1505
+ }
1506
+ ),
1507
+ showSystemPromptEditor && /* @__PURE__ */ jsxs2("div", { style: { padding: "12px", borderBottom: "1px solid #e5e5e5", backgroundColor: "#f9fafb" }, children: [
1508
+ /* @__PURE__ */ jsx3("label", { style: { display: "block", fontSize: "12px", fontWeight: 500, marginBottom: "4px", color: "#6b7280" }, children: "System Prompt" }),
1509
+ /* @__PURE__ */ jsx3(
1510
+ "textarea",
1511
+ {
1512
+ value: systemPrompt,
1513
+ onChange: (e) => setSystemPrompt(e.target.value),
1514
+ placeholder: "Enter a system prompt to guide the chatbot's behavior...",
1515
+ style: {
1516
+ width: "100%",
1517
+ minHeight: "80px",
1518
+ padding: "8px",
1519
+ borderRadius: "6px",
1520
+ border: "1px solid #d1d5db",
1521
+ fontSize: "13px",
1522
+ fontFamily: "var(--ac-font)",
1523
+ resize: "vertical"
1524
+ }
1525
+ }
1526
+ )
1527
+ ] }),
1528
+ /* @__PURE__ */ jsxs2(
1529
+ "div",
1530
+ {
1531
+ style: {
1532
+ flex: 1,
1533
+ overflowY: "auto",
1534
+ padding: "16px",
1535
+ display: "flex",
1536
+ flexDirection: "column",
1537
+ gap: "12px",
1538
+ minHeight: "200px"
1539
+ },
1540
+ children: [
1541
+ messages.length === 0 && !streamingContent && /* @__PURE__ */ jsxs2("div", { style: { textAlign: "center", color: "#9ca3af", padding: "40px 20px" }, children: [
1542
+ /* @__PURE__ */ jsx3(
1543
+ "svg",
1544
+ {
1545
+ width: "48",
1546
+ height: "48",
1547
+ viewBox: "0 0 24 24",
1548
+ fill: "none",
1549
+ stroke: "currentColor",
1550
+ strokeWidth: "1.5",
1551
+ style: { margin: "0 auto 16px" },
1552
+ children: /* @__PURE__ */ jsx3("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
1553
+ }
1554
+ ),
1555
+ /* @__PURE__ */ jsx3("p", { style: { margin: 0, fontSize: "14px" }, children: "Ask a question about your knowledge library" })
1556
+ ] }),
1557
+ messages.map((msg, i) => /* @__PURE__ */ jsx3(
1558
+ "div",
1559
+ {
1560
+ style: {
1561
+ alignSelf: msg.role === "user" ? "flex-end" : "flex-start",
1562
+ maxWidth: "85%"
1563
+ },
1564
+ children: /* @__PURE__ */ jsx3(
1565
+ "div",
1566
+ {
1567
+ style: {
1568
+ padding: "10px 14px",
1569
+ borderRadius: "12px",
1570
+ backgroundColor: msg.role === "user" ? "var(--ac-primary)" : "#f3f4f6",
1571
+ color: msg.role === "user" ? "white" : "var(--ac-text)",
1572
+ fontSize: "14px",
1573
+ lineHeight: "1.5",
1574
+ whiteSpace: "pre-wrap"
1575
+ },
1576
+ children: msg.content
1577
+ }
1578
+ )
1579
+ },
1580
+ i
1581
+ )),
1582
+ streamingContent && /* @__PURE__ */ jsx3("div", { style: { alignSelf: "flex-start", maxWidth: "85%" }, children: /* @__PURE__ */ jsxs2(
1583
+ "div",
1584
+ {
1585
+ style: {
1586
+ padding: "10px 14px",
1587
+ borderRadius: "12px",
1588
+ backgroundColor: "#f3f4f6",
1589
+ color: "var(--ac-text)",
1590
+ fontSize: "14px",
1591
+ lineHeight: "1.5",
1592
+ whiteSpace: "pre-wrap"
1593
+ },
1594
+ children: [
1595
+ streamingContent,
1596
+ /* @__PURE__ */ jsx3("span", { style: { opacity: 0.5, animation: "blink 1s infinite" }, children: "|" })
1597
+ ]
1598
+ }
1599
+ ) }),
1600
+ error && /* @__PURE__ */ jsx3(
1601
+ "div",
1602
+ {
1603
+ style: {
1604
+ padding: "10px 14px",
1605
+ borderRadius: "8px",
1606
+ backgroundColor: "#fef2f2",
1607
+ color: "#dc2626",
1608
+ fontSize: "13px"
1609
+ },
1610
+ children: error
1611
+ }
1612
+ ),
1613
+ /* @__PURE__ */ jsx3("div", { ref: messagesEndRef })
1614
+ ]
1615
+ }
1616
+ ),
1617
+ /* @__PURE__ */ jsx3("form", { onSubmit: handleSubmit, style: { padding: "12px", borderTop: "1px solid #e5e5e5" }, children: /* @__PURE__ */ jsxs2("div", { style: { display: "flex", gap: "8px" }, children: [
1618
+ /* @__PURE__ */ jsx3(
1619
+ "input",
1620
+ {
1621
+ ref: inputRef,
1622
+ type: "text",
1623
+ value: inputValue,
1624
+ onChange: (e) => setInputValue(e.target.value),
1625
+ placeholder: config.placeholder || "Ask a question...",
1626
+ disabled: isStreaming,
1627
+ style: {
1628
+ flex: 1,
1629
+ padding: "10px 14px",
1630
+ borderRadius: "8px",
1631
+ border: "1px solid #d1d5db",
1632
+ fontSize: "14px",
1633
+ fontFamily: "var(--ac-font)",
1634
+ outline: "none"
1635
+ }
1636
+ }
1637
+ ),
1638
+ /* @__PURE__ */ jsx3(
1639
+ "button",
1640
+ {
1641
+ type: "submit",
1642
+ disabled: isStreaming || !inputValue.trim(),
1643
+ style: {
1644
+ padding: "10px 16px",
1645
+ borderRadius: "8px",
1646
+ backgroundColor: isStreaming || !inputValue.trim() ? "#d1d5db" : "var(--ac-primary)",
1647
+ color: "white",
1648
+ border: "none",
1649
+ cursor: isStreaming || !inputValue.trim() ? "not-allowed" : "pointer",
1650
+ fontWeight: 500,
1651
+ fontSize: "14px"
1652
+ },
1653
+ children: isStreaming ? "..." : "Send"
1654
+ }
1655
+ )
1656
+ ] }) }),
1657
+ /* @__PURE__ */ jsx3("style", { children: `
1658
+ @keyframes blink {
1659
+ 0%, 50% { opacity: 1; }
1660
+ 51%, 100% { opacity: 0; }
1661
+ }
1662
+ ` })
1663
+ ]
1664
+ }
1665
+ );
1666
+ }
1667
+
1668
+ // src/components/WebsiteChatbot.tsx
1669
+ import { useState as useState4, useRef as useRef4, useEffect as useEffect4 } from "react";
1670
+
1671
+ // src/utils/card-parser.ts
1672
+ var CARD_MARKER_REGEX = /\[([A-Z][A-Z0-9_]*):([^\]]+)\]/g;
1673
+ function parseCardMarker(marker) {
1674
+ const match = marker.match(/^\[([A-Z][A-Z0-9_]*):([^\]]+)\]$/);
1675
+ if (!match) return null;
1676
+ const [, type, valuesStr] = match;
1677
+ const values = valuesStr.split("|").map((v) => v.trim());
1678
+ return {
1679
+ type,
1680
+ values,
1681
+ originalMarker: marker
1682
+ };
1683
+ }
1684
+ function parseMessageContent(content) {
1685
+ const segments = [];
1686
+ let lastIndex = 0;
1687
+ const matches = [...content.matchAll(CARD_MARKER_REGEX)];
1688
+ for (const match of matches) {
1689
+ const marker = match[0];
1690
+ const startIndex = match.index;
1691
+ if (startIndex > lastIndex) {
1692
+ const text = content.slice(lastIndex, startIndex).trim();
1693
+ if (text) {
1694
+ segments.push({ type: "text", content: text });
1695
+ }
1696
+ }
1697
+ const card = parseCardMarker(marker);
1698
+ if (card) {
1699
+ segments.push({ type: "card", card });
1700
+ }
1701
+ lastIndex = startIndex + marker.length;
1702
+ }
1703
+ if (lastIndex < content.length) {
1704
+ const text = content.slice(lastIndex).trim();
1705
+ if (text) {
1706
+ segments.push({ type: "text", content: text });
1707
+ }
1708
+ }
1709
+ if (segments.length === 0 && content.trim()) {
1710
+ segments.push({ type: "text", content: content.trim() });
1711
+ }
1712
+ return segments;
1713
+ }
1714
+ function isUrl(str) {
1715
+ return /^https?:\/\//i.test(str);
1716
+ }
1717
+ function isImageUrl(url) {
1718
+ if (!isUrl(url)) return false;
1719
+ return /\.(jpg|jpeg|png|gif|webp|svg)(\?|$)/i.test(url);
1720
+ }
1721
+ function extractCardDisplayData(card) {
1722
+ const values = [...card.values];
1723
+ const result = {
1724
+ title: values[0] || card.type,
1725
+ extraValues: []
1726
+ };
1727
+ if (values.length <= 1) return result;
1728
+ const imageIndex = values.findIndex((v, i) => i > 0 && isImageUrl(v));
1729
+ if (imageIndex > 0) {
1730
+ result.imageUrl = values[imageIndex];
1731
+ values.splice(imageIndex, 1);
1732
+ }
1733
+ const actionIndex = values.findIndex((v, i) => i > 0 && isUrl(v) && !isImageUrl(v));
1734
+ if (actionIndex > 0) {
1735
+ result.actionUrl = values[actionIndex];
1736
+ result.actionLabel = "View";
1737
+ values.splice(actionIndex, 1);
1738
+ }
1739
+ const remaining = values.slice(1);
1740
+ if (remaining.length > 0) {
1741
+ if (remaining[0].length <= 50) {
1742
+ result.subtitle = remaining[0];
1743
+ remaining.shift();
1744
+ }
1745
+ }
1746
+ if (remaining.length > 0) {
1747
+ result.description = remaining[0];
1748
+ remaining.shift();
1749
+ }
1750
+ result.extraValues = remaining;
1751
+ return result;
1752
+ }
1753
+
1754
+ // src/components/WebsiteChatbot.tsx
1755
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1756
+ var defaultTheme3 = {
1757
+ primaryColor: "#f59e0b",
1758
+ // Amber
1759
+ backgroundColor: "#ffffff",
1760
+ textColor: "#1c1917",
1761
+ borderRadius: "12px",
1762
+ fontFamily: "system-ui, -apple-system, sans-serif"
1763
+ };
1764
+ function ChatCard({ card, theme }) {
1765
+ const data = extractCardDisplayData(card);
1766
+ return /* @__PURE__ */ jsxs3(
1767
+ "div",
1768
+ {
1769
+ style: {
1770
+ border: "1px solid #e5e7eb",
1771
+ borderRadius: "8px",
1772
+ overflow: "hidden",
1773
+ backgroundColor: "#fff",
1774
+ marginTop: "8px",
1775
+ marginBottom: "8px"
1776
+ },
1777
+ children: [
1778
+ data.imageUrl && /* @__PURE__ */ jsx4(
1779
+ "div",
1780
+ {
1781
+ style: {
1782
+ width: "100%",
1783
+ height: "140px",
1784
+ backgroundColor: "#f3f4f6",
1785
+ overflow: "hidden"
1786
+ },
1787
+ children: /* @__PURE__ */ jsx4(
1788
+ "img",
1789
+ {
1790
+ src: data.imageUrl,
1791
+ alt: data.title,
1792
+ style: {
1793
+ width: "100%",
1794
+ height: "100%",
1795
+ objectFit: "cover"
1796
+ },
1797
+ onError: (e) => {
1798
+ e.target.style.display = "none";
1799
+ }
1800
+ }
1801
+ )
1802
+ }
1803
+ ),
1804
+ /* @__PURE__ */ jsxs3("div", { style: { padding: "12px" }, children: [
1805
+ /* @__PURE__ */ jsx4(
1806
+ "div",
1807
+ {
1808
+ style: {
1809
+ display: "inline-block",
1810
+ fontSize: "10px",
1811
+ fontWeight: 600,
1812
+ textTransform: "uppercase",
1813
+ letterSpacing: "0.5px",
1814
+ color: theme.primaryColor,
1815
+ backgroundColor: `${theme.primaryColor}15`,
1816
+ padding: "2px 6px",
1817
+ borderRadius: "4px",
1818
+ marginBottom: "6px"
1819
+ },
1820
+ children: card.type
1821
+ }
1822
+ ),
1823
+ /* @__PURE__ */ jsx4(
1824
+ "div",
1825
+ {
1826
+ style: {
1827
+ fontSize: "15px",
1828
+ fontWeight: 600,
1829
+ color: "#1f2937",
1830
+ marginBottom: "4px",
1831
+ lineHeight: "1.3"
1832
+ },
1833
+ children: data.title
1834
+ }
1835
+ ),
1836
+ data.subtitle && /* @__PURE__ */ jsx4(
1837
+ "div",
1838
+ {
1839
+ style: {
1840
+ fontSize: "13px",
1841
+ color: "#6b7280",
1842
+ marginBottom: "6px"
1843
+ },
1844
+ children: data.subtitle
1845
+ }
1846
+ ),
1847
+ data.description && /* @__PURE__ */ jsx4(
1848
+ "div",
1849
+ {
1850
+ style: {
1851
+ fontSize: "13px",
1852
+ color: "#4b5563",
1853
+ lineHeight: "1.4",
1854
+ marginBottom: "8px"
1855
+ },
1856
+ children: data.description
1857
+ }
1858
+ ),
1859
+ data.extraValues.length > 0 && /* @__PURE__ */ jsx4(
1860
+ "div",
1861
+ {
1862
+ style: {
1863
+ fontSize: "12px",
1864
+ color: "#6b7280",
1865
+ marginBottom: "8px"
1866
+ },
1867
+ children: data.extraValues.join(" \u2022 ")
1868
+ }
1869
+ ),
1870
+ data.actionUrl && /* @__PURE__ */ jsxs3(
1871
+ "a",
1872
+ {
1873
+ href: data.actionUrl,
1874
+ target: "_blank",
1875
+ rel: "noopener noreferrer",
1876
+ style: {
1877
+ display: "inline-flex",
1878
+ alignItems: "center",
1879
+ gap: "4px",
1880
+ fontSize: "13px",
1881
+ fontWeight: 500,
1882
+ color: theme.primaryColor,
1883
+ textDecoration: "none",
1884
+ padding: "6px 12px",
1885
+ borderRadius: "6px",
1886
+ backgroundColor: `${theme.primaryColor}10`,
1887
+ transition: "background-color 0.2s"
1888
+ },
1889
+ onMouseEnter: (e) => {
1890
+ e.currentTarget.style.backgroundColor = `${theme.primaryColor}20`;
1891
+ },
1892
+ onMouseLeave: (e) => {
1893
+ e.currentTarget.style.backgroundColor = `${theme.primaryColor}10`;
1894
+ },
1895
+ children: [
1896
+ data.actionLabel || "View",
1897
+ /* @__PURE__ */ jsxs3("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
1898
+ /* @__PURE__ */ jsx4("path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" }),
1899
+ /* @__PURE__ */ jsx4("polyline", { points: "15 3 21 3 21 9" }),
1900
+ /* @__PURE__ */ jsx4("line", { x1: "10", y1: "14", x2: "21", y2: "3" })
1901
+ ] })
1902
+ ]
1903
+ }
1904
+ )
1905
+ ] })
1906
+ ]
1907
+ }
1908
+ );
1909
+ }
1910
+ function MessageContent({ content, theme }) {
1911
+ const segments = parseMessageContent(content);
1912
+ if (segments.length === 1 && segments[0].type === "text") {
1913
+ return /* @__PURE__ */ jsx4(Fragment2, { children: segments[0].content });
1914
+ }
1915
+ return /* @__PURE__ */ jsx4(Fragment2, { children: segments.map((segment, index) => {
1916
+ if (segment.type === "text") {
1917
+ return /* @__PURE__ */ jsx4("span", { style: { whiteSpace: "pre-wrap" }, children: segment.content }, index);
1918
+ }
1919
+ if (segment.type === "card" && segment.card) {
1920
+ return /* @__PURE__ */ jsx4(ChatCard, { card: segment.card, theme }, index);
1921
+ }
1922
+ return null;
1923
+ }) });
1924
+ }
1925
+ function WebsiteChatbot({ className, ...config }) {
1926
+ const theme = { ...defaultTheme3, ...config.theme };
1927
+ const apiUrl = config.apiUrl || "https://api.informedai.app/api/v1";
1928
+ const [messages, setMessages] = useState4([]);
1929
+ const [inputValue, setInputValue] = useState4("");
1930
+ const [isStreaming, setIsStreaming] = useState4(false);
1931
+ const [streamingContent, setStreamingContent] = useState4("");
1932
+ const [error, setError] = useState4(null);
1933
+ const [isCollapsed, setIsCollapsed] = useState4(config.defaultCollapsed ?? false);
1934
+ const messagesEndRef = useRef4(null);
1935
+ useEffect4(() => {
1936
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1937
+ }, [messages, streamingContent]);
1938
+ const sendMessage = async (message) => {
1939
+ if (!message.trim() || isStreaming) return;
1940
+ setError(null);
1941
+ setIsStreaming(true);
1942
+ setStreamingContent("");
1943
+ const newMessages = [...messages, { role: "user", content: message }];
1944
+ setMessages(newMessages);
1945
+ try {
1946
+ const response = await fetch(`${apiUrl}/website-agent/${config.agentId}/message`, {
1947
+ method: "POST",
1948
+ headers: {
1949
+ "Content-Type": "application/json"
1950
+ },
1951
+ body: JSON.stringify({
1952
+ message,
1953
+ history: messages
1954
+ })
1955
+ });
1956
+ if (!response.ok) {
1957
+ const err = await response.json().catch(() => ({ error: "Request failed" }));
1958
+ throw new Error(err.error || `HTTP ${response.status}`);
1959
+ }
1960
+ const reader = response.body?.getReader();
1961
+ if (!reader) throw new Error("No response body");
1962
+ const decoder = new TextDecoder();
1963
+ let buffer = "";
1964
+ let fullContent = "";
1965
+ while (true) {
1966
+ const { done, value } = await reader.read();
1967
+ if (done) break;
1968
+ buffer += decoder.decode(value, { stream: true });
1969
+ const lines = buffer.split("\n");
1970
+ buffer = lines.pop() || "";
1971
+ for (const line of lines) {
1972
+ if (line.startsWith("event:")) continue;
1973
+ if (line.startsWith("data:")) {
1974
+ const data = line.slice(5).trim();
1975
+ try {
1976
+ const parsed = JSON.parse(data);
1977
+ if (parsed.content) {
1978
+ fullContent += parsed.content;
1979
+ setStreamingContent(fullContent);
1980
+ }
1981
+ if (parsed.fullContent) {
1982
+ fullContent = parsed.fullContent;
1983
+ }
1984
+ } catch {
1985
+ }
1986
+ }
1987
+ }
1988
+ }
1989
+ setMessages([...newMessages, { role: "assistant", content: fullContent }]);
1990
+ setStreamingContent("");
1991
+ } catch (err) {
1992
+ setError(err instanceof Error ? err.message : "Failed to send message");
1993
+ } finally {
1994
+ setIsStreaming(false);
1995
+ }
1996
+ };
1997
+ const handleSubmit = (e) => {
1998
+ e.preventDefault();
1999
+ if (!inputValue.trim() || isStreaming) return;
2000
+ const message = inputValue.trim();
2001
+ setInputValue("");
2002
+ sendMessage(message);
2003
+ };
2004
+ const clearConversation = () => {
2005
+ setMessages([]);
2006
+ setStreamingContent("");
2007
+ setError(null);
2008
+ };
2009
+ const cssVars = {
2010
+ "--wc-primary": theme.primaryColor,
2011
+ "--wc-bg": theme.backgroundColor,
2012
+ "--wc-text": theme.textColor,
2013
+ "--wc-radius": theme.borderRadius,
2014
+ "--wc-font": theme.fontFamily
2015
+ };
2016
+ const positionStyles = config.position === "inline" ? {} : {
2017
+ position: "fixed",
2018
+ [config.position === "bottom-left" ? "left" : "right"]: "20px",
2019
+ bottom: "20px",
2020
+ zIndex: 9999
2021
+ };
2022
+ if (isCollapsed && config.position !== "inline") {
2023
+ return /* @__PURE__ */ jsx4(
2024
+ "button",
2025
+ {
2026
+ onClick: () => setIsCollapsed(false),
2027
+ className,
2028
+ style: {
2029
+ ...cssVars,
2030
+ ...positionStyles,
2031
+ width: "56px",
2032
+ height: "56px",
2033
+ borderRadius: "50%",
2034
+ backgroundColor: "var(--wc-primary)",
2035
+ color: "white",
2036
+ border: "none",
2037
+ cursor: "pointer",
2038
+ display: "flex",
2039
+ alignItems: "center",
2040
+ justifyContent: "center",
2041
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
2042
+ fontFamily: "var(--wc-font)"
2043
+ },
2044
+ children: /* @__PURE__ */ jsx4("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" }) })
2045
+ }
2046
+ );
2047
+ }
2048
+ return /* @__PURE__ */ jsxs3(
2049
+ "div",
2050
+ {
2051
+ className,
2052
+ style: {
2053
+ ...cssVars,
2054
+ ...positionStyles,
2055
+ width: config.position === "inline" ? "100%" : "400px",
2056
+ maxHeight: config.position === "inline" ? "600px" : "80vh",
2057
+ backgroundColor: "var(--wc-bg)",
2058
+ borderRadius: "var(--wc-radius)",
2059
+ border: "1px solid #e5e5e5",
2060
+ fontFamily: "var(--wc-font)",
2061
+ display: "flex",
2062
+ flexDirection: "column",
2063
+ boxShadow: config.position === "inline" ? "none" : "0 4px 20px rgba(0,0,0,0.15)",
2064
+ overflow: "hidden"
2065
+ },
2066
+ children: [
2067
+ /* @__PURE__ */ jsxs3(
2068
+ "div",
2069
+ {
2070
+ style: {
2071
+ padding: "16px",
2072
+ borderBottom: "1px solid #e5e5e5",
2073
+ display: "flex",
2074
+ alignItems: "center",
2075
+ justifyContent: "space-between",
2076
+ backgroundColor: "var(--wc-primary)",
2077
+ color: "white"
2078
+ },
2079
+ children: [
2080
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
2081
+ /* @__PURE__ */ jsxs3("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2082
+ /* @__PURE__ */ jsx4("circle", { cx: "12", cy: "12", r: "10" }),
2083
+ /* @__PURE__ */ jsx4("line", { x1: "2", y1: "12", x2: "22", y2: "12" }),
2084
+ /* @__PURE__ */ jsx4("path", { d: "M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" })
2085
+ ] }),
2086
+ /* @__PURE__ */ jsx4("span", { style: { fontWeight: 600 }, children: config.title || "Chat" })
2087
+ ] }),
2088
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px" }, children: [
2089
+ /* @__PURE__ */ jsx4(
2090
+ "button",
2091
+ {
2092
+ onClick: clearConversation,
2093
+ style: {
2094
+ background: "rgba(255,255,255,0.2)",
2095
+ border: "none",
2096
+ borderRadius: "4px",
2097
+ padding: "4px 8px",
2098
+ color: "white",
2099
+ cursor: "pointer",
2100
+ fontSize: "12px"
2101
+ },
2102
+ children: "Clear"
2103
+ }
2104
+ ),
2105
+ config.position !== "inline" && /* @__PURE__ */ jsx4(
2106
+ "button",
2107
+ {
2108
+ onClick: () => setIsCollapsed(true),
2109
+ style: {
2110
+ background: "none",
2111
+ border: "none",
2112
+ color: "white",
2113
+ cursor: "pointer",
2114
+ padding: "4px"
2115
+ },
2116
+ children: /* @__PURE__ */ jsxs3("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
2117
+ /* @__PURE__ */ jsx4("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
2118
+ /* @__PURE__ */ jsx4("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
2119
+ ] })
2120
+ }
2121
+ )
2122
+ ] })
2123
+ ]
2124
+ }
2125
+ ),
2126
+ /* @__PURE__ */ jsxs3(
2127
+ "div",
2128
+ {
2129
+ style: {
2130
+ flex: 1,
2131
+ overflowY: "auto",
2132
+ padding: "16px",
2133
+ display: "flex",
2134
+ flexDirection: "column",
2135
+ gap: "12px",
2136
+ minHeight: "200px"
2137
+ },
2138
+ children: [
2139
+ messages.length === 0 && !streamingContent && /* @__PURE__ */ jsxs3("div", { style: { textAlign: "center", color: "#9ca3af", padding: "40px 20px" }, children: [
2140
+ /* @__PURE__ */ jsx4(
2141
+ "svg",
2142
+ {
2143
+ width: "48",
2144
+ height: "48",
2145
+ viewBox: "0 0 24 24",
2146
+ fill: "none",
2147
+ stroke: "currentColor",
2148
+ strokeWidth: "1.5",
2149
+ style: { margin: "0 auto 16px" },
2150
+ children: /* @__PURE__ */ jsx4("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
2151
+ }
2152
+ ),
2153
+ /* @__PURE__ */ jsx4("p", { style: { margin: 0, fontSize: "14px" }, children: "How can I help you today?" })
2154
+ ] }),
2155
+ messages.map((msg, i) => /* @__PURE__ */ jsx4(
2156
+ "div",
2157
+ {
2158
+ style: {
2159
+ alignSelf: msg.role === "user" ? "flex-end" : "flex-start",
2160
+ maxWidth: "85%"
2161
+ },
2162
+ children: /* @__PURE__ */ jsx4(
2163
+ "div",
2164
+ {
2165
+ style: {
2166
+ padding: "10px 14px",
2167
+ borderRadius: "12px",
2168
+ backgroundColor: msg.role === "user" ? "var(--wc-primary)" : "#f3f4f6",
2169
+ color: msg.role === "user" ? "white" : "var(--wc-text)",
2170
+ fontSize: "14px",
2171
+ lineHeight: "1.5"
2172
+ },
2173
+ children: msg.role === "user" ? msg.content : /* @__PURE__ */ jsx4(MessageContent, { content: msg.content, theme })
2174
+ }
2175
+ )
2176
+ },
2177
+ i
2178
+ )),
2179
+ streamingContent && /* @__PURE__ */ jsx4("div", { style: { alignSelf: "flex-start", maxWidth: "85%" }, children: /* @__PURE__ */ jsxs3(
2180
+ "div",
2181
+ {
2182
+ style: {
2183
+ padding: "10px 14px",
2184
+ borderRadius: "12px",
2185
+ backgroundColor: "#f3f4f6",
2186
+ color: "var(--wc-text)",
2187
+ fontSize: "14px",
2188
+ lineHeight: "1.5"
2189
+ },
2190
+ children: [
2191
+ /* @__PURE__ */ jsx4(MessageContent, { content: streamingContent, theme }),
2192
+ /* @__PURE__ */ jsx4("span", { style: { opacity: 0.5, animation: "blink 1s infinite" }, children: "|" })
2193
+ ]
2194
+ }
2195
+ ) }),
2196
+ error && /* @__PURE__ */ jsx4(
2197
+ "div",
2198
+ {
2199
+ style: {
2200
+ padding: "10px 14px",
2201
+ borderRadius: "8px",
2202
+ backgroundColor: "#fef2f2",
2203
+ color: "#dc2626",
2204
+ fontSize: "13px"
2205
+ },
2206
+ children: error
2207
+ }
2208
+ ),
2209
+ /* @__PURE__ */ jsx4("div", { ref: messagesEndRef })
2210
+ ]
2211
+ }
2212
+ ),
2213
+ /* @__PURE__ */ jsx4("form", { onSubmit: handleSubmit, style: { padding: "12px", borderTop: "1px solid #e5e5e5" }, children: /* @__PURE__ */ jsxs3("div", { style: { display: "flex", gap: "8px" }, children: [
2214
+ /* @__PURE__ */ jsx4(
2215
+ "input",
2216
+ {
2217
+ type: "text",
2218
+ value: inputValue,
2219
+ onChange: (e) => setInputValue(e.target.value),
2220
+ placeholder: config.placeholder || "Type a message...",
2221
+ disabled: isStreaming,
2222
+ style: {
2223
+ flex: 1,
2224
+ padding: "10px 14px",
2225
+ borderRadius: "8px",
2226
+ border: "1px solid #d1d5db",
2227
+ fontSize: "14px",
2228
+ fontFamily: "var(--wc-font)",
2229
+ outline: "none"
2230
+ }
2231
+ }
2232
+ ),
2233
+ /* @__PURE__ */ jsx4(
2234
+ "button",
2235
+ {
2236
+ type: "submit",
2237
+ disabled: isStreaming || !inputValue.trim(),
2238
+ style: {
2239
+ padding: "10px 16px",
2240
+ borderRadius: "8px",
2241
+ backgroundColor: isStreaming || !inputValue.trim() ? "#d1d5db" : "var(--wc-primary)",
2242
+ color: "white",
2243
+ border: "none",
2244
+ cursor: isStreaming || !inputValue.trim() ? "not-allowed" : "pointer",
2245
+ fontWeight: 500,
2246
+ fontSize: "14px"
2247
+ },
2248
+ children: isStreaming ? "..." : "Send"
2249
+ }
2250
+ )
2251
+ ] }) }),
2252
+ /* @__PURE__ */ jsx4("style", { children: `
2253
+ @keyframes blink {
2254
+ 0%, 50% { opacity: 1; }
2255
+ 51%, 100% { opacity: 0; }
2256
+ }
2257
+ ` })
2258
+ ]
2259
+ }
2260
+ );
2261
+ }
2262
+
1274
2263
  // src/hooks/useSession.ts
1275
- import { useState as useState3, useEffect as useEffect3, useCallback as useCallback2, useRef as useRef3 } from "react";
2264
+ import { useState as useState5, useEffect as useEffect5, useCallback as useCallback2, useRef as useRef5 } from "react";
1276
2265
  function useSession(options) {
1277
2266
  const { apiUrl, documentTypeId, sessionId, onSessionChange, onError } = options;
1278
- const [session, setSession] = useState3(null);
1279
- const [isLoading, setIsLoading] = useState3(true);
1280
- const [error, setError] = useState3(null);
1281
- const clientRef = useRef3(null);
1282
- const isStreamingRef = useRef3(false);
1283
- useEffect3(() => {
2267
+ const [session, setSession] = useState5(null);
2268
+ const [isLoading, setIsLoading] = useState5(true);
2269
+ const [error, setError] = useState5(null);
2270
+ const clientRef = useRef5(null);
2271
+ const isStreamingRef = useRef5(false);
2272
+ useEffect5(() => {
1284
2273
  clientRef.current = new InformedAIClient(apiUrl);
1285
2274
  }, [apiUrl]);
1286
- useEffect3(() => {
2275
+ useEffect5(() => {
1287
2276
  async function initialize() {
1288
2277
  if (!clientRef.current) return;
1289
2278
  try {
@@ -1393,9 +2382,11 @@ function useSession(options) {
1393
2382
  };
1394
2383
  }
1395
2384
  export {
2385
+ AdminChatbot,
1396
2386
  InformedAIClient,
1397
2387
  InformedAIProvider,
1398
2388
  InformedAssistant,
2389
+ WebsiteChatbot,
1399
2390
  useInformedAI,
1400
2391
  useSession
1401
2392
  };